diff --git a/src/Event.h b/src/Event.h index d9357db8b..425e45ced 100644 --- a/src/Event.h +++ b/src/Event.h @@ -83,8 +83,8 @@ CC_API void Event_RaiseFloat(struct Event_Float* handlers, float arg); #define Event_RegisterFloat(handlers, obj, handler) Event_RegisterMacro(handlers, obj, handler) #define Event_UnregisterFloat(handlers, obj, handler) Event_UnregisterMacro(handlers, obj, handler) -/* Calls all registered callbacks for an event which has data stream and name argumenst. */ -/* This is (currently) only used for processing entries from default.zip */ +/* Calls all registered callbacks for an event which has data stream and name arguments. */ +/* This is (currently) only used for processing entries from texture pack zip */ void Event_RaiseEntry(struct Event_Entry* handlers, struct Stream* stream, const String* name); #define Event_RegisterEntry(handlers, obj, handler) Event_RegisterMacro(handlers, obj, handler) #define Event_UnregisterEntry(handlers, obj, handler) Event_UnregisterMacro(handlers, obj, handler) diff --git a/src/Server.c b/src/Server.c index 91b304841..ff5869f75 100644 --- a/src/Server.c +++ b/src/Server.c @@ -55,22 +55,9 @@ void Server_RetrieveTexturePack(const String* url) { void Server_DownloadTexturePack(const String* url) { static const String texPack = String_FromConst("texturePack"); - String etag; char etagBuffer[STRING_SIZE]; - String time; char timeBuffer[STRING_SIZE]; - - if (TextureCache_HasDenied(url)) return; - String_InitArray(etag, etagBuffer); - String_InitArray(time, timeBuffer); - - /* Only retrieve etag/last-modified headers if the file exists */ - /* This can occur if user decided to delete some cached files */ - if (TextureCache_Has(url)) { - TextureCache_GetLastModified(url, &time); - TextureCache_GetETag(url, &etag); - } - TexturePack_ExtractCurrent(url); - Http_AsyncGetDataEx(url, true, &texPack, &time, &etag); + TexturePack_DownloadAsync(url, &texPack); + String_Copy(&World_TextureUrl, url); } static void Server_CheckAsyncResources(void) { @@ -79,7 +66,9 @@ static void Server_CheckAsyncResources(void) { if (!Http_GetResult(&texPack, &item)) return; if (item.Success) { + TextureCache_Update(&item); TexturePack_Extract_Req(&item); + HttpRequest_Free(&item); } else if (item.Result) { Chat_Add1("&cError %i when trying to download texture pack", &item.Result); } else { diff --git a/src/TexturePack.c b/src/TexturePack.c index 52f851b34..859960d02 100644 --- a/src/TexturePack.c +++ b/src/TexturePack.c @@ -569,7 +569,7 @@ bool TextureCache_Get(const String* url, struct Stream* stream) { return true; } -void TexturePack_GetFromTags(const String* url, String* result, struct EntryList* list) { +CC_NOINLINE static void TexturePack_GetFromTags(const String* url, String* result, struct EntryList* list) { String key, value; char keyBuffer[STRING_INT_CHARS]; String_InitArray(key, keyBuffer); @@ -578,7 +578,7 @@ void TexturePack_GetFromTags(const String* url, String* result, struct EntryList if (value.length) String_AppendString(result, &value); } -void TextureCache_GetLastModified(const String* url, String* time) { +static void TextureCache_GetLastModified(const String* url, String* time) { String entry; char entryBuffer[STRING_SIZE]; TimeMS raw; @@ -593,21 +593,10 @@ void TextureCache_GetLastModified(const String* url, String* time) { } } -void TextureCache_GetETag(const String* url, String* etag) { +static void TextureCache_GetETag(const String* url, String* etag) { TexturePack_GetFromTags(url, etag, &etagCache); } -void TextureCache_Set(const String* url, const uint8_t* data, uint32_t length) { - String path; char pathBuffer[FILENAME_SIZE]; - ReturnCode res; - - String_InitArray(path, pathBuffer); - TextureCache_MakePath(&path, url); - - res = Stream_WriteAllTo(&path, data, length); - if (res) { Logger_Warn2(res, "caching", url); } -} - CC_NOINLINE static void TextureCache_SetEntry(const String* url, const String* data, struct EntryList* list) { String key; char keyBuffer[STRING_INT_CHARS]; String_InitArray(key, keyBuffer); @@ -627,6 +616,22 @@ static void TextureCache_SetLastModified(const String* url, const String* time) TextureCache_SetEntry(url, time, &lastModifiedCache); } +void TextureCache_Update(struct HttpRequest* req) { + String path, url; char pathBuffer[FILENAME_SIZE]; + ReturnCode res; + url = String_FromRawArray(req->URL); + + path = String_FromRawArray(req->Etag); + TextureCache_SetETag(&url, &path); + path = String_FromRawArray(req->LastModified); + TextureCache_SetLastModified(&url, &path); + + String_InitArray(path, pathBuffer); + TextureCache_MakePath(&path, &url); + res = Stream_WriteAllTo(&path, req->Data, req->Size); + if (res) { Logger_Warn2(res, "caching", &url); } +} + /*########################################################################################################################* *-------------------------------------------------------TexturePack-------------------------------------------------------* @@ -638,6 +643,7 @@ static ReturnCode TexturePack_ProcessZipEntry(const String* path, struct Stream* return 0; } +/* Extracts all the files from a stream representing a .zip archive */ static ReturnCode TexturePack_ExtractZip(struct Stream* stream) { struct ZipState state; Event_RaiseVoid(&TextureEvents.PackChanged); @@ -648,6 +654,21 @@ static ReturnCode TexturePack_ExtractZip(struct Stream* stream) { return Zip_Extract(&state); } +/* Changes the current terrain atlas from a stream representing a .png image */ +/* Raises TextureEvents.PackChanged, so behaves as a .zip with only terrain.png in it */ +static ReturnCode TexturePack_ExtractTerrainPng(struct Stream* stream) { + Bitmap bmp; + ReturnCode res = Png_Decode(&bmp, stream); + + if (!res) { + Event_RaiseVoid(&TextureEvents.PackChanged); + if (Game_ChangeTerrainAtlas(&bmp)) return 0; + } + + Mem_Free(bmp.Scan0); + return res; +} + void TexturePack_ExtractZip_File(const String* filename) { String path; char pathBuffer[FILENAME_SIZE]; struct Stream stream; @@ -680,19 +701,6 @@ void TexturePack_ExtractZip_File(const String* filename) { #endif } -ReturnCode TexturePack_ExtractTerrainPng(struct Stream* stream) { - Bitmap bmp; - ReturnCode res = Png_Decode(&bmp, stream); - - if (!res) { - Event_RaiseVoid(&TextureEvents.PackChanged); - if (Game_ChangeTerrainAtlas(&bmp)) return 0; - } - - Mem_Free(bmp.Scan0); - return res; -} - void TexturePack_ExtractDefault(void) { String texPack; char texPackBuffer[STRING_SIZE]; @@ -709,9 +717,9 @@ void TexturePack_ExtractCurrent(const String* url) { bool zip; ReturnCode res = 0; - if (!url->length) { TexturePack_ExtractDefault(); return; } - - if (!TextureCache_Get(url, &stream)) { + if (!url->length) { + TexturePack_ExtractDefault(); + } else if (!TextureCache_Get(url, &stream)) { /* e.g. 404 errors */ if (World_TextureUrl.length) TexturePack_ExtractDefault(); } else { @@ -740,12 +748,6 @@ void TexturePack_Extract_Req(struct HttpRequest* item) { String_Copy(&World_TextureUrl, &url); data = item->Data; len = item->Size; - TextureCache_Set(&url, data, len); - - str = String_FromRawArray(item->Etag); - TextureCache_SetETag(&url, &str); - str = String_FromRawArray(item->LastModified); - TextureCache_SetLastModified(&url, &str); Stream_ReadonlyMemory(&mem, data, len); png = Png_Detect(data, len); @@ -753,5 +755,20 @@ void TexturePack_Extract_Req(struct HttpRequest* item) { : TexturePack_ExtractZip(&mem); if (res) Logger_Warn2(res, png ? "decoding" : "extracting", &url); - HttpRequest_Free(item); +} + +void TexturePack_DownloadAsync(const String* url, const String* id) { + String etag; char etagBuffer[STRING_SIZE]; + String time; char timeBuffer[STRING_SIZE]; + + String_InitArray(etag, etagBuffer); + String_InitArray(time, timeBuffer); + + /* Only retrieve etag/last-modified headers if the file exists */ + /* This inconsistency can occur if user deleted some cached files */ + if (TextureCache_Has(url)) { + TextureCache_GetLastModified(url, &time); + TextureCache_GetETag(url, &etag); + } + Http_AsyncGetDataEx(url, true, id, &time, &etag); } diff --git a/src/TexturePack.h b/src/TexturePack.h index a85a2dcd0..8a0a4a0f5 100644 --- a/src/TexturePack.h +++ b/src/TexturePack.h @@ -87,16 +87,22 @@ void TextureCache_Deny(const String* url); bool TextureCache_Has(const String* url); /* Attempts to get the cached data stream for the given url. */ bool TextureCache_Get(const String* url, struct Stream* stream); -/* Attempts to get the Last-Modified header cached for the given URL. */ -void TextureCache_GetLastModified(const String* url, String* time); -/* Attempts to get the ETag header cached for the given URL. */ -void TextureCache_GetETag(const String* url, String* etag); -/* Sets the cached data for the given url. */ -void TextureCache_Set(const String* url, const uint8_t* data, uint32_t length); +/* Updates cached data, ETag, and Last-Modified for the given URL. */ +void TextureCache_Update(struct HttpRequest* req); +/* Extracts a texture pack .zip from the given file. */ void TexturePack_ExtractZip_File(const String* filename); /* Extracts user's default texture pack, then resets World_TextureUrl. */ void TexturePack_ExtractDefault(void); +/* Extracts the current texture pack or terrain.png. 3 cases: */ +/* - Server has not set a URL, so just extract default */ +/* - URL is in texture cache, so extract cached version */ +/* - URL is not cached, so extract default for now */ void TexturePack_ExtractCurrent(const String* url); +/* Asynchronously downloads a texture pack. */ +/* Sends ETag and Last-Modified to webserver to avoid redundant downloads. */ +/* NOTE: This does not load cached textures - use TexturePack_ExtractCurrent for that. */ +void TexturePack_DownloadAsync(const String* url, const String* id); +/* Extracts a texture pack or terrain.png from given downloaded data. */ void TexturePack_Extract_Req(struct HttpRequest* item); #endif diff --git a/src/World.c b/src/World.c index 39806590a..a7b045cb6 100644 --- a/src/World.c +++ b/src/World.c @@ -8,6 +8,7 @@ #include "ExtMath.h" #include "Physics.h" #include "Game.h" +#include "TexturePack.h" struct _WorldData World; /*########################################################################################################################* @@ -135,6 +136,12 @@ const PackedCol Env_DefaultShadowCol = PACKEDCOL_CONST(0x9B, 0x9B, 0x9B, 0xFF); static char World_TextureUrlBuffer[STRING_SIZE]; String World_TextureUrl = String_FromArray(World_TextureUrlBuffer); +void World_ApplyTexturePack(const String* url) { + static const String texPack = String_FromConst("texturePack"); + TexturePack_ExtractCurrent(url); + TexturePack_DownloadAsync(url, &texPack); +} + void Env_Reset(void) { Env.EdgeHeight = -1; Env.SidesOffset = -2; diff --git a/src/World.h b/src/World.h index ce35df0b7..e11605055 100644 --- a/src/World.h +++ b/src/World.h @@ -123,9 +123,13 @@ extern const PackedCol Env_DefaultSunCol, Env_DefaultShadowCol; #define ENV_DEFAULT_SUNCOL_HEX "FFFFFF" #define ENV_DEFAULT_SHADOWCOL_HEX "9B9B9B" +/* Extracts texture pack cached for the given URL (or default.zip if not), */ +/* then asynchronously downloads the data for the given URL. */ +CC_API void World_ApplyTexturePack(const String* url); /* Resets all environment settings to default. */ /* NOTE: Unlike Env_Set functions, DOES NOT raise EnvVarChanged event. */ CC_API void Env_Reset(void); + /* Sets the edge/horizon block. (default water) */ CC_API void Env_SetEdgeBlock(BlockID block); /* Sets the sides/border block. (default bedrock) */