mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-25 14:14:46 -04:00
Should be using the 'lastmodified' provided for our own 'if modified since' header, fixes texture packs from some web servers always being redownloaded. (Thanks CookieNetwork)
This commit is contained in:
parent
ae379a85c0
commit
83aaf4091d
@ -192,6 +192,7 @@ namespace ClassicalSharp {
|
|||||||
internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" );
|
internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" );
|
||||||
internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" );
|
internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" );
|
||||||
internal EntryList ETags = new EntryList( "etags.txt" );
|
internal EntryList ETags = new EntryList( "etags.txt" );
|
||||||
|
internal EntryList LastModified = new EntryList( "lastmodified.txt" );
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Calculates the amount that the hotbar widget should be scaled by when rendered. </summary>
|
/// <summary> Calculates the amount that the hotbar widget should be scaled by when rendered. </summary>
|
||||||
|
@ -98,8 +98,8 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
void DownloadTexturePack( string url ) {
|
void DownloadTexturePack( string url ) {
|
||||||
if( game.DeniedUrls.HasEntry( url ) ) return;
|
if( game.DeniedUrls.HasEntry( url ) ) return;
|
||||||
DateTime lastModified = TextureCache.GetLastModifiedFromCache( url );
|
DateTime lastModified = TextureCache.GetLastModified( url, game.LastModified );
|
||||||
string etag = TextureCache.GetETagFromCache( url, game.ETags );
|
string etag = TextureCache.GetETag( url, game.ETags );
|
||||||
|
|
||||||
if( url.Contains( ".zip" ) )
|
if( url.Contains( ".zip" ) )
|
||||||
game.AsyncDownloader.DownloadData( url, true, "texturePack",
|
game.AsyncDownloader.DownloadData( url, true, "texturePack",
|
||||||
@ -134,10 +134,12 @@ namespace ClassicalSharp {
|
|||||||
game.Drawer2D.ConvertTo32Bpp( ref bmp );
|
game.Drawer2D.ConvertTo32Bpp( ref bmp );
|
||||||
}
|
}
|
||||||
if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; }
|
if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; }
|
||||||
TextureCache.AddToCache( item.Url, bmp );
|
|
||||||
TextureCache.AddETagToCache( item.Url, item.ETag, game.ETags );
|
TextureCache.Add( item.Url, bmp );
|
||||||
|
TextureCache.AddETag( item.Url, item.ETag, game.ETags );
|
||||||
|
TextureCache.AdddLastModified( item.Url, item.LastModified, game.LastModified );
|
||||||
} else {
|
} else {
|
||||||
Bitmap bmp = TextureCache.GetBitmapFromCache( item.Url );
|
Bitmap bmp = TextureCache.GetBitmap( item.Url );
|
||||||
if( bmp == null ) { // e.g. 404 errors
|
if( bmp == null ) { // e.g. 404 errors
|
||||||
ExtractDefault();
|
ExtractDefault();
|
||||||
} else if( item.Url != game.World.TextureUrl ) {
|
} else if( item.Url != game.World.TextureUrl ) {
|
||||||
@ -154,10 +156,11 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
TexturePackExtractor extractor = new TexturePackExtractor();
|
TexturePackExtractor extractor = new TexturePackExtractor();
|
||||||
extractor.Extract( (byte[])item.Data, game );
|
extractor.Extract( (byte[])item.Data, game );
|
||||||
TextureCache.AddToCache( item.Url, (byte[])item.Data );
|
TextureCache.Add( item.Url, (byte[])item.Data );
|
||||||
TextureCache.AddETagToCache( item.Url, item.ETag, game.ETags );
|
TextureCache.AddETag( item.Url, item.ETag, game.ETags );
|
||||||
|
TextureCache.AdddLastModified( item.Url, item.LastModified, game.LastModified );
|
||||||
} else {
|
} else {
|
||||||
byte[] data = TextureCache.GetDataFromCache( item.Url );
|
byte[] data = TextureCache.GetData( item.Url );
|
||||||
if( data == null ) { // e.g. 404 errors
|
if( data == null ) { // e.g. 404 errors
|
||||||
ExtractDefault();
|
ExtractDefault();
|
||||||
} else if( item.Url != game.World.TextureUrl ) {
|
} else if( item.Url != game.World.TextureUrl ) {
|
||||||
|
@ -197,11 +197,14 @@ namespace ClassicalSharp.Network {
|
|||||||
object value = null;
|
object value = null;
|
||||||
HttpStatusCode status = HttpStatusCode.OK;
|
HttpStatusCode status = HttpStatusCode.OK;
|
||||||
string etag = null;
|
string etag = null;
|
||||||
|
DateTime lastModified = DateTime.MinValue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpWebRequest req = MakeRequest( request );
|
HttpWebRequest req = MakeRequest( request );
|
||||||
using( HttpWebResponse response = (HttpWebResponse)req.GetResponse() ) {
|
using( HttpWebResponse response = (HttpWebResponse)req.GetResponse() ) {
|
||||||
etag = response.Headers[HttpResponseHeader.ETag];
|
etag = response.Headers[HttpResponseHeader.ETag];
|
||||||
|
if( response.Headers[HttpResponseHeader.LastModified] != null )
|
||||||
|
lastModified = response.LastModified;
|
||||||
value = DownloadContent( request, response );
|
value = DownloadContent( request, response );
|
||||||
}
|
}
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
@ -220,7 +223,8 @@ namespace ClassicalSharp.Network {
|
|||||||
|
|
||||||
lock( downloadedLocker ) {
|
lock( downloadedLocker ) {
|
||||||
DownloadedItem oldItem;
|
DownloadedItem oldItem;
|
||||||
DownloadedItem newItem = new DownloadedItem( value, request.TimeAdded, url, status, etag );
|
DownloadedItem newItem = new DownloadedItem( value, request.TimeAdded, url,
|
||||||
|
status, etag, lastModified );
|
||||||
|
|
||||||
if( downloaded.TryGetValue( request.Identifier, out oldItem ) ) {
|
if( downloaded.TryGetValue( request.Identifier, out oldItem ) ) {
|
||||||
if( oldItem.TimeAdded > newItem.TimeAdded ) {
|
if( oldItem.TimeAdded > newItem.TimeAdded ) {
|
||||||
@ -357,14 +361,19 @@ namespace ClassicalSharp.Network {
|
|||||||
/// <summary> Unique identifier assigned by the server to this item. </summary>
|
/// <summary> Unique identifier assigned by the server to this item. </summary>
|
||||||
public string ETag;
|
public string ETag;
|
||||||
|
|
||||||
|
/// <summary> Time the server indicates this item was last modified. </summary>
|
||||||
|
public DateTime LastModified;
|
||||||
|
|
||||||
public DownloadedItem( object data, DateTime timeAdded,
|
public DownloadedItem( object data, DateTime timeAdded,
|
||||||
string url, HttpStatusCode code, string etag ) {
|
string url, HttpStatusCode code,
|
||||||
|
string etag, DateTime lastModified ) {
|
||||||
Data = data;
|
Data = data;
|
||||||
TimeAdded = timeAdded;
|
TimeAdded = timeAdded;
|
||||||
TimeDownloaded = DateTime.UtcNow;
|
TimeDownloaded = DateTime.UtcNow;
|
||||||
Url = url;
|
Url = url;
|
||||||
ResponseCode = code;
|
ResponseCode = code;
|
||||||
ETag = etag;
|
ETag = etag;
|
||||||
|
LastModified = lastModified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,54 +13,76 @@ namespace ClassicalSharp.TexturePack {
|
|||||||
/// <summary> Caches terrain atlases and texture packs to avoid making redundant downloads. </summary>
|
/// <summary> Caches terrain atlases and texture packs to avoid making redundant downloads. </summary>
|
||||||
public static class TextureCache {
|
public static class TextureCache {
|
||||||
|
|
||||||
|
/// <summary> Gets whether the given url has data associated with it in the cache. </summary>
|
||||||
|
public static bool HasUrl( string url ) {
|
||||||
|
return File.Exists( MakePath( url ) );
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Gets the bitmap associated with the url from the cache, returning null if the bitmap
|
/// <summary> Gets the bitmap associated with the url from the cache, returning null if the bitmap
|
||||||
/// for the url was not found in the cache or the bitmap in the cache was corrupted. </summary>
|
/// for the url was not found in the cache or the bitmap in the cache was corrupted. </summary>
|
||||||
public static Bitmap GetBitmapFromCache( string url ) {
|
public static Bitmap GetBitmap( string url ) {
|
||||||
string path = MakePath( url );
|
string path = MakePath( url );
|
||||||
if( !File.Exists( path ) ) return null;
|
if( !File.Exists( path ) ) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new Bitmap( path );
|
return new Bitmap( path );
|
||||||
} catch( ArgumentException ex ) {
|
} catch( ArgumentException ex ) {
|
||||||
ErrorHandler.LogError( "Cache.GetBitmapFromCache", ex );
|
ErrorHandler.LogError( "Cache.GetBitmap", ex );
|
||||||
return null;
|
return null;
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ErrorHandler.LogError( "Cache.GetBitmapFromCache", ex );
|
ErrorHandler.LogError( "Cache.GetBitmap", ex );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets the data associated with the url from the cache, returning null if the
|
/// <summary> Gets the data associated with the url from the cache, returning null if the
|
||||||
/// data for the url was not found in the cache. </summary>
|
/// data for the url was not found in the cache. </summary>
|
||||||
public static byte[] GetDataFromCache( string url ) {
|
public static byte[] GetData( string url ) {
|
||||||
string path = MakePath( url );
|
string path = MakePath( url );
|
||||||
if( !File.Exists( path ) ) return null;
|
if( !File.Exists( path ) ) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return File.ReadAllBytes( path );
|
return File.ReadAllBytes( path );
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ErrorHandler.LogError( "Cache.GetDataFromCache", ex );
|
ErrorHandler.LogError( "Cache.GetData", ex );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets the time the data associated with the url from the cache was last modified,
|
/// <summary> Gets the time the data associated with the url from the cache was last modified,
|
||||||
/// returning DateTime.MinValue if data for the url was not found in the cache. </summary>
|
/// returning DateTime.MinValue if data for the url was not found in the cache. </summary>
|
||||||
public static DateTime GetLastModifiedFromCache( string url ) {
|
public static DateTime GetLastModified( string url, EntryList tags ) {
|
||||||
string path = MakePath( url );
|
string entry = GetFromTags( url, tags );
|
||||||
if( !File.Exists( path ) )
|
long ticks = 0;
|
||||||
return DateTime.MinValue;
|
if( entry != null && long.TryParse( entry, out ticks ) )
|
||||||
|
return new DateTime( ticks, DateTimeKind.Utc );
|
||||||
|
|
||||||
|
string path = MakePath( url );
|
||||||
|
if( !File.Exists( path ) ) return DateTime.MinValue;
|
||||||
return File.GetLastWriteTimeUtc( path );
|
return File.GetLastWriteTimeUtc( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets whether the given url has a bitmap associated with it in the cache. </summary>
|
public static string GetETag( string url, EntryList tags ) {
|
||||||
public static bool IsInCache( string url ) {
|
return GetFromTags( url, tags );
|
||||||
return File.Exists( MakePath( url ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string GetFromTags( string url, EntryList tags ) {
|
||||||
|
string crc32 = CRC32( url );
|
||||||
|
|
||||||
|
for( int i = 0; i < tags.Entries.Count; i++ ) {
|
||||||
|
string entry = tags.Entries[i];
|
||||||
|
if( !entry.StartsWith( crc32 ) ) continue;
|
||||||
|
|
||||||
|
int sepIndex = entry.IndexOf( ' ' );
|
||||||
|
if( sepIndex == -1 ) continue;
|
||||||
|
return entry.Substring( sepIndex + 1 );
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Adds the url and the bitmap associated with it to the cache. </summary>
|
/// <summary> Adds the url and the bitmap associated with it to the cache. </summary>
|
||||||
public static void AddToCache( string url, Bitmap bmp ) {
|
public static void Add( string url, Bitmap bmp ) {
|
||||||
string path = MakePath( url );
|
string path = MakePath( url );
|
||||||
try {
|
try {
|
||||||
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
||||||
@ -75,7 +97,7 @@ namespace ClassicalSharp.TexturePack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Adds the url and the data associated with it to the cache. </summary>
|
/// <summary> Adds the url and the data associated with it to the cache. </summary>
|
||||||
public static void AddToCache( string url, byte[] data ) {
|
public static void Add( string url, byte[] data ) {
|
||||||
string path = MakePath( url );
|
string path = MakePath( url );
|
||||||
try {
|
try {
|
||||||
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
||||||
@ -88,51 +110,48 @@ namespace ClassicalSharp.TexturePack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetETagFromCache( string url, EntryList tags ) {
|
public static void AddETag( string url, string etag, EntryList tags ) {
|
||||||
byte[] utf8 = Encoding.UTF8.GetBytes( url );
|
if( etag == null ) return;
|
||||||
string crc32 = CRC32( utf8 ).ToString();
|
AddToTags( url, etag, tags );
|
||||||
|
|
||||||
for( int i = 0; i < tags.Entries.Count; i++ ) {
|
|
||||||
string entry = tags.Entries[i];
|
|
||||||
if( !entry.StartsWith( crc32 ) ) continue;
|
|
||||||
|
|
||||||
int sepIndex = entry.IndexOf( ' ' );
|
|
||||||
if( sepIndex == -1 ) continue;
|
|
||||||
return entry.Substring( sepIndex + 1 );
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddETagToCache( string url, string etag, EntryList tags ) {
|
public static void AdddLastModified( string url, DateTime lastModified, EntryList tags ) {
|
||||||
if( etag == null ) return;
|
if( lastModified == DateTime.MinValue ) return;
|
||||||
byte[] utf8 = Encoding.UTF8.GetBytes( url );
|
string data = lastModified.ToUniversalTime().Ticks.ToString();
|
||||||
string crc32 = CRC32( utf8 ).ToString();
|
AddToTags( url, data, tags );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddToTags( string url, string data, EntryList tags ) {
|
||||||
|
string crc32 = CRC32( url );
|
||||||
for( int i = 0; i < tags.Entries.Count; i++ ) {
|
for( int i = 0; i < tags.Entries.Count; i++ ) {
|
||||||
if( !tags.Entries[i].StartsWith( crc32 ) ) continue;
|
if( !tags.Entries[i].StartsWith( crc32 ) ) continue;
|
||||||
tags.Entries[i] = crc32 + " " + etag;
|
tags.Entries[i] = crc32 + " " + data;
|
||||||
tags.Save(); return;
|
tags.Save(); return;
|
||||||
}
|
}
|
||||||
tags.AddEntry( crc32 + " " + etag );
|
tags.AddEntry( crc32 + " " + data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const string Folder = "texturecache";
|
const string Folder = "texturecache";
|
||||||
|
|
||||||
static string MakePath( string url ) {
|
static string MakePath( string url ) {
|
||||||
byte[] utf8 = Encoding.UTF8.GetBytes( url );
|
string crc32 = CRC32( url );
|
||||||
uint crc32 = CRC32( utf8 );
|
|
||||||
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
string basePath = PathIO.Combine( Program.AppDirectory, Folder );
|
||||||
return PathIO.Combine( basePath, crc32.ToString() );
|
return PathIO.Combine( basePath, crc32 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint CRC32( byte[] data ) {
|
static string CRC32( string url ) {
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes( url );
|
||||||
uint crc = 0xffffffffU;
|
uint crc = 0xffffffffU;
|
||||||
|
|
||||||
for( int i = 0; i < data.Length; i++ ) {
|
for( int i = 0; i < data.Length; i++ ) {
|
||||||
crc ^= data[i];
|
crc ^= data[i];
|
||||||
for( int j = 0; j < 8; j++ )
|
for( int j = 0; j < 8; j++ )
|
||||||
crc = (crc >> 1) ^ (crc & 1) * 0xEDB88320;
|
crc = (crc >> 1) ^ (crc & 1) * 0xEDB88320;
|
||||||
}
|
}
|
||||||
return crc ^ 0xffffffffU;
|
|
||||||
|
uint result = crc ^ 0xffffffffU;
|
||||||
|
return result.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user