diff --git a/src/Client/AsyncDownloader.c b/src/Client/AsyncDownloader.c index 08c534fa1..e1c2afca8 100644 --- a/src/Client/AsyncDownloader.c +++ b/src/Client/AsyncDownloader.c @@ -6,17 +6,7 @@ #include "GameStructs.h" void ASyncRequest_Free(struct AsyncRequest* request) { - switch (request->RequestType) { - case REQUEST_TYPE_IMAGE: - Platform_MemFree(&request->ResultBitmap.Scan0); - break; - case REQUEST_TYPE_DATA: - Platform_MemFree(&request->ResultData.Ptr); - break; - case REQUEST_TYPE_STRING: - Platform_MemFree(&request->ResultString.buffer); - break; - } + Platform_MemFree(&request->ResultData); } #define ASYNCREQUESTLIST_DEFELEMS 10 @@ -127,37 +117,25 @@ void AsyncDownloader_GetSkin(STRING_PURE String* id, STRING_PURE String* skinNam String_AppendConst(&url, ".png"); } - AsyncDownloader_Add(&url, false, id, REQUEST_TYPE_IMAGE, NULL, NULL, NULL); + AsyncDownloader_Add(&url, false, id, REQUEST_TYPE_DATA, NULL, NULL, NULL); } void AsyncDownloader_GetData(STRING_PURE String* url, bool priority, STRING_PURE String* id) { AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, NULL); } -void AsyncDownloader_GetImage(STRING_PURE String* url, bool priority, STRING_PURE String* id) { - AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_IMAGE, NULL, NULL, NULL); -} - -void AsyncDownloader_GetString(STRING_PURE String* url, bool priority, STRING_PURE String* id) { - AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_STRING, NULL, NULL, NULL); -} - void AsyncDownloader_GetContentLength(STRING_PURE String* url, bool priority, STRING_PURE String* id) { AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_CONTENT_LENGTH, NULL, NULL, NULL); } void AsyncDownloader_PostString(STRING_PURE String* url, bool priority, STRING_PURE String* id, STRING_PURE String* contents) { - AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_STRING, NULL, NULL, contents); + AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, contents); } void AsyncDownloader_GetDataEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag) { AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, lastModified, etag, NULL); } -void AsyncDownloader_GetImageEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag) { - AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_IMAGE, lastModified, etag, NULL); -} - void AsyncDownloader_PurgeOldEntriesTask(struct ScheduledTask* task) { Platform_MutexLock(async_processedMutex); { @@ -247,27 +225,8 @@ static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) { UInt64 addr = (UInt64)data; Platform_Log2("OK I got the DATA! %i bytes at %x", &size, &addr); - - struct Stream memStream; - switch (request->RequestType) { - case REQUEST_TYPE_DATA: - request->ResultData.Ptr = data; - request->ResultData.Size = size; - break; - - case REQUEST_TYPE_IMAGE: - Stream_ReadonlyMemory(&memStream, data, size, &url); - Bitmap_DecodePng(&request->ResultBitmap, &memStream); - break; - - case REQUEST_TYPE_STRING: - request->ResultString = String_Init(data, size, size); - break; - - case REQUEST_TYPE_CONTENT_LENGTH: - request->ResultContentLength = size; - break; - } + request->ResultData = data; + request->ResultSize = size; } static void AsyncDownloader_CompleteResult(struct AsyncRequest* request) { diff --git a/src/Client/AsyncDownloader.h b/src/Client/AsyncDownloader.h index 3fd3ef78c..70eda71ca 100644 --- a/src/Client/AsyncDownloader.h +++ b/src/Client/AsyncDownloader.h @@ -9,10 +9,7 @@ struct IGameComponent; struct ScheduledTask; -enum REQUEST_TYPE { - REQUEST_TYPE_DATA, REQUEST_TYPE_IMAGE, - REQUEST_TYPE_STRING, REQUEST_TYPE_CONTENT_LENGTH, -}; +enum REQUEST_TYPE { REQUEST_TYPE_DATA, REQUEST_TYPE_CONTENT_LENGTH }; #define ASYNC_PROGRESS_NOTHING -3 #define ASYNC_PROGRESS_MAKING_REQUEST -2 #define ASYNC_PROGRESS_FETCHING_DATA -1 @@ -25,12 +22,8 @@ struct AsyncRequest { DateTime TimeDownloaded; UInt16 StatusCode; - union { - struct { void* Ptr; UInt32 Size; } ResultData; - struct Bitmap ResultBitmap; - String ResultString; - UInt32 ResultContentLength; - }; + void* ResultData; + UInt32 ResultSize; DateTime LastModified; /* Time item cached at (if at all) */ UInt8 Etag[String_BufferSize(STRING_SIZE)]; /* ETag of cached item (if any) */ @@ -42,13 +35,10 @@ void ASyncRequest_Free(struct AsyncRequest* request); void AsyncDownloader_MakeComponent(struct IGameComponent* comp); void AsyncDownloader_GetSkin(STRING_PURE String* id, STRING_PURE String* skinName); void AsyncDownloader_GetData(STRING_PURE String* url, bool priority, STRING_PURE String* id); -void AsyncDownloader_GetImage(STRING_PURE String* url, bool priority, STRING_PURE String* id); -void AsyncDownloader_GetString(STRING_PURE String* url, bool priority, STRING_PURE String* id); void AsyncDownloader_GetContentLength(STRING_PURE String* url, bool priority, STRING_PURE String* id); /* TODO: Implement post */ //void AsyncDownloader_PostString(STRING_PURE String* url, bool priority, STRING_PURE String* id, STRING_PURE String* contents); void AsyncDownloader_GetDataEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag); -void AsyncDownloader_GetImageEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag); bool AsyncDownloader_Get(STRING_PURE String* id, struct AsyncRequest* item); bool AsyncDownloader_GetCurrent(struct AsyncRequest* request, Int32* progress); diff --git a/src/Client/Bitmap.c b/src/Client/Bitmap.c index d9b44b615..3ecb4707c 100644 --- a/src/Client/Bitmap.c +++ b/src/Client/Bitmap.c @@ -63,13 +63,20 @@ enum PNG_FILTER { typedef void(*Png_RowExpander)(UInt8 bpp, Int32 width, UInt32* palette, UInt8* src, UInt32* dst); UInt8 png_sig[PNG_SIG_SIZE] = { 137, 80, 78, 71, 13, 10, 26, 10 }; +bool Bitmap_DetectPng(UInt8* data, UInt32 len) { + if (len < PNG_SIG_SIZE) return false; + Int32 i; + + for (i = 0; i < PNG_SIG_SIZE; i++) { + if (data[i] != png_sig[i]) return false; + } + return true; +} + static void Png_CheckHeader(struct Stream* stream) { UInt8 header[PNG_SIG_SIZE]; Stream_Read(stream, header, PNG_SIG_SIZE); - Int32 i; - for (i = 0; i < PNG_SIG_SIZE; i++) { - if (header[i] != png_sig[i]) ErrorHandler_Fail("Invalid PNG header"); - } + if (!Bitmap_DetectPng(header, PNG_SIG_SIZE)) ErrorHandler_Fail("Invalid PNG header"); } static void Png_Reconstruct(UInt8 type, UInt8 bytesPerPixel, UInt8* line, UInt8* prior, UInt32 lineLen) { diff --git a/src/Client/Bitmap.h b/src/Client/Bitmap.h index 314de6055..e1b4d1db5 100644 --- a/src/Client/Bitmap.h +++ b/src/Client/Bitmap.h @@ -25,6 +25,7 @@ void Bitmap_Allocate(struct Bitmap* bmp, Int32 width, Int32 height); /* Allocates a power-of-2 sized bitmap larger or equal to to the given size, and clears it to 0. You are responsible for freeing its memory! */ void Bitmap_AllocateClearedPow2(struct Bitmap* bmp, Int32 width, Int32 height); +bool Bitmap_DetectPng(UInt8* data, UInt32 len); /* Partially based off information from https://handmade.network/forums/wip/t/2363-implementing_a_basic_png_reader_the_handmade_way diff --git a/src/Client/Entity.c b/src/Client/Entity.c index 33ef0c1d5..9c90c2da6 100644 --- a/src/Client/Entity.c +++ b/src/Client/Entity.c @@ -697,8 +697,12 @@ static void Player_CheckSkin(struct Player* player) { struct AsyncRequest item; if (!AsyncDownloader_Get(&skin, &item)) return; - struct Bitmap bmp = item.ResultBitmap; - if (bmp.Scan0 == NULL) { Player_SetSkinAll(player, true); return; } + if (item.ResultData == NULL) { Player_SetSkinAll(player, true); return; } + + String url = String_FromRawArray(item.URL); + struct Stream mem; struct Bitmap bmp; + Stream_ReadonlyMemory(&mem, item.ResultData, item.ResultSize, &url); + Bitmap_DecodePng(&bmp, &mem); Gfx_DeleteTexture(&entity->TextureId); Player_SetSkinAll(player, true); diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 2a973d7d0..bb379bd2d 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -3324,7 +3324,7 @@ static void TexPackOverlay_Render(struct GuiElem* elem, Real64 delta) { struct AsyncRequest item; if (!AsyncDownloader_Get(&identifier, &item)) return; - screen->ContentLength = item.ResultContentLength; + screen->ContentLength = item.ResultSize; if (screen->ContentLength == 0) return; screen->ContextLost(elem); diff --git a/src/Client/PacketHandlers.c b/src/Client/PacketHandlers.c index 44782c258..d43fe02bc 100644 --- a/src/Client/PacketHandlers.c +++ b/src/Client/PacketHandlers.c @@ -200,7 +200,7 @@ static void WoM_CheckMotd(void) { applied in the new world if the async 'get env request' didn't complete before the old world was unloaded */ wom_counter++; WoM_UpdateIdentifier(); - AsyncDownloader_GetString(&url, true, &wom_identifier); + AsyncDownloader_GetData(&url, true, &wom_identifier); wom_sendId = true; } @@ -288,11 +288,13 @@ static void WoM_Reset(void) { static void WoM_Tick(void) { struct AsyncRequest item; - bool success = AsyncDownloader_Get(&wom_identifier, &item); - if (success && item.ResultString.length > 0) { - Wom_ParseConfig(&item.ResultString); - ASyncRequest_Free(&item); + if (!AsyncDownloader_Get(&wom_identifier, &item)) return; + + if (item.ResultData) { + String str = String_Init(item.ResultData, item.ResultSize, item.ResultSize); + Wom_ParseConfig(&str); } + ASyncRequest_Free(&item); } diff --git a/src/Client/ServerConnection.c b/src/Client/ServerConnection.c index 2187fd753..ec44fba07 100644 --- a/src/Client/ServerConnection.c +++ b/src/Client/ServerConnection.c @@ -60,47 +60,27 @@ void ServerConnection_DownloadTexturePack(STRING_PURE String* url) { TextureCache_GetLastModified(url, &lastModified); TextureCache_GetETag(url, &etag); } + TexturePack_ExtractCurrent(url); - - String zip = String_FromConst(".zip"); - if (String_ContainsString(url, &zip)) { - String texPack = String_FromConst("texturePack"); - AsyncDownloader_GetDataEx(url, true, &texPack, &lastModified, &etag); - } else { - String terrain = String_FromConst("terrain"); - AsyncDownloader_GetImageEx(url, true, &terrain, &lastModified, &etag); - } -} - -void ServerConnection_LogResourceFail(struct AsyncRequest* item) { - Int32 status = item->StatusCode; - if (status == 0 || status == 304) return; - - UChar msgBuffer[String_BufferSize(STRING_SIZE)]; - String msg = String_InitAndClearArray(msgBuffer); - String_Format1(&msg, "&c%i error when trying to download texture pack", &status); - Chat_Add(&msg); + String texPack = String_FromConst("texturePack"); + AsyncDownloader_GetDataEx(url, true, &texPack, &lastModified, &etag); } void ServerConnection_CheckAsyncResources(void) { struct AsyncRequest item; - String terrain = String_FromConst("terrain"); String texPack = String_FromConst("texturePack"); + if (!AsyncDownloader_Get(&texPack, &item)) return; - if (AsyncDownloader_Get(&terrain, &item)) { - if (item.ResultBitmap.Scan0 != NULL) { - TexturePack_ExtractTerrainPng_Req(&item); - } else { - ServerConnection_LogResourceFail(&item); - } - } + if (item.ResultData) { + TexturePack_Extract_Req(&item); + } else { + Int32 status = item.StatusCode; + if (status == 0 || status == 304) return; - if (AsyncDownloader_Get(&texPack, &item)) { - if (item.ResultData.Ptr != NULL) { - TexturePack_ExtractTexturePack_Req(&item); - } else { - ServerConnection_LogResourceFail(&item); - } + UChar msgBuffer[String_BufferSize(STRING_SIZE)]; + String msg = String_InitAndClearArray(msgBuffer); + String_Format1(&msg, "&c%i error when trying to download texture pack", &status); + Chat_Add(&msg); } } diff --git a/src/Client/Socket.c b/src/Client/Socket.c index 1a1a18786..8910313b1 100644 --- a/src/Client/Socket.c +++ b/src/Client/Socket.c @@ -63,7 +63,7 @@ ReturnCode Platform_SocketConnect(SocketPtr socket, STRING_PURE String* ip, Int3 ReturnCode Platform_SocketRead(SocketPtr socket, UInt8* buffer, UInt32 count, UInt32* modified) { Int32 recvCount = recv(socket, buffer, count, 0); - if (recvCount == -1) { *modified = recvCount; return 0; } + if (recvCount != -1) { *modified = recvCount; return 0; } *modified = 0; return Socket__Error(); } diff --git a/src/Client/TexturePack.c b/src/Client/TexturePack.c index 4b0e48cab..8d781e39c 100644 --- a/src/Client/TexturePack.c +++ b/src/Client/TexturePack.c @@ -354,39 +354,24 @@ void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag) { TexturePack_GetFromTags(url, etag, &cache_eTags); } -static void* TextureCache_CreateFile(STRING_PURE String* path) { - String folder = String_FromConst(TEXCACHE_FOLDER); - if (!Platform_DirectoryExists(&folder)) { - ReturnCode dirResult = Platform_DirectoryCreate(&folder); - ErrorHandler_CheckOrFail(dirResult, "TextureCache_CreateFile - create directory"); - } - - void* file; - ReturnCode result = Platform_FileCreate(&file, path); - /* TODO: Should we just log failure to save? */ - ErrorHandler_CheckOrFail(result, "TextureCache_CreateFile - open file"); - return file; -} - -void TextureCache_AddImage(STRING_PURE String* url, struct Bitmap* bmp) { - String path; TexCache_InitAndMakePath(url); - void* file = TextureCache_CreateFile(&path); - struct Stream stream; Stream_FromFile(&stream, file, &path); - { - Bitmap_EncodePng(bmp, &stream); - } - ReturnCode result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "TextureCache_AddImage - close file"); -} - void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length) { String path; TexCache_InitAndMakePath(url); - void* file = TextureCache_CreateFile(&path); + ReturnCode result; + + String folder = String_FromConst(TEXCACHE_FOLDER); + if (!Platform_DirectoryExists(&folder)) { + result = Platform_DirectoryCreate(&folder); + ErrorHandler_CheckOrFail(result, "TextureCache_AddData - create directory"); + } + + void* file; result = Platform_FileCreate(&file, &path); + /* TODO: Should we just log failure to save? */ + ErrorHandler_CheckOrFail(result, "TextureCache_AddData - open file"); struct Stream stream; Stream_FromFile(&stream, file, &path); { Stream_Write(&stream, data, length); } - ReturnCode result = stream.Close(&stream); + result = stream.Close(&stream); ErrorHandler_CheckOrFail(result, "TextureCache_AddData - close file"); } @@ -495,29 +480,15 @@ void TexturePack_ExtractCurrent(STRING_PURE String* url) { } ReturnCode result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - slow stream"); + ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - close stream"); } } -void TexturePack_ExtractTerrainPng_Req(struct AsyncRequest* item) { +void TexturePack_Extract_Req(struct AsyncRequest* item) { String url = String_FromRawArray(item->URL); String_Set(&World_TextureUrl, &url); - struct Bitmap bmp = item->ResultBitmap; - - String etag = String_FromRawArray(item->Etag); - TextureCache_AddImage(&url, &bmp); - TextureCache_AddETag(&url, &etag); - TextureCache_AddLastModified(&url, &item->LastModified); - - Event_RaiseVoid(&TextureEvents_PackChanged); - if (!Game_ChangeTerrainAtlas(&bmp)) ASyncRequest_Free(item); -} - -void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item) { - String url = String_FromRawArray(item->URL); - String_Set(&World_TextureUrl, &url); - void* data = item->ResultData.Ptr; - UInt32 len = item->ResultData.Size; + void* data = item->ResultData; + UInt32 len = item->ResultSize; String etag = String_FromRawArray(item->Etag); TextureCache_AddData(&url, data, len); @@ -525,7 +496,14 @@ void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item) { TextureCache_AddLastModified(&url, &item->LastModified); String id = String_FromRawArray(item->ID); - struct Stream stream; Stream_ReadonlyMemory(&stream, data, len, &id); - TexturePack_ExtractZip(&stream); + struct Stream mem; Stream_ReadonlyMemory(&mem, data, len, &id); + + if (Bitmap_DetectPng(data, len)) { + struct Bitmap bmp; Bitmap_DecodePng(&bmp, &mem); + Event_RaiseVoid(&TextureEvents_PackChanged); + if (!Game_ChangeTerrainAtlas(&bmp)) Platform_MemFree(&bmp.Scan0); + } else { + TexturePack_ExtractZip(&mem); + } ASyncRequest_Free(item); -} +} \ No newline at end of file diff --git a/src/Client/TexturePack.h b/src/Client/TexturePack.h index 1848f87d7..51596d8b8 100644 --- a/src/Client/TexturePack.h +++ b/src/Client/TexturePack.h @@ -35,7 +35,6 @@ bool TextureCache_HasUrl(STRING_PURE String* url); bool TextureCache_GetStream(STRING_PURE String* url, struct Stream* stream); void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time); void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag); -void TextureCache_AddImage(STRING_PURE String* url, struct Bitmap* bmp); void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length); void TextureCache_AddETag(STRING_PURE String* url, STRING_PURE String* etag); void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModified); @@ -43,6 +42,5 @@ void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModifie void TexturePack_ExtractZip_File(STRING_PURE String* filename); void TexturePack_ExtractDefault(void); void TexturePack_ExtractCurrent(STRING_PURE String* url); -void TexturePack_ExtractTerrainPng_Req(struct AsyncRequest* item); -void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item); +void TexturePack_Extract_Req(struct AsyncRequest* item); #endif