From 1d6e422c3f01c4451cc2d3c30aacf415c49e53cf Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 15 Aug 2018 23:36:14 +1000 Subject: [PATCH] log errors instead of immediately dying in C client --- src/Client/Animations.c | 8 +++- src/Client/AsyncDownloader.c | 6 +-- src/Client/Audio.c | 27 ++++++++---- src/Client/Bitmap.c | 4 +- src/Client/Chat.c | 24 ++++++----- src/Client/D3D9Api.c | 49 ++++++++++----------- src/Client/Entity.c | 9 ++-- src/Client/ErrorHandler.c | 4 ++ src/Client/ErrorHandler.h | 4 +- src/Client/Formats.c | 2 +- src/Client/Game.c | 58 ++++++++++++++----------- src/Client/GraphicsAPI.h | 2 +- src/Client/Gui.c | 2 +- src/Client/Input.c | 4 +- src/Client/Menus.c | 18 +++++--- src/Client/OpenGLApi.c | 6 +-- src/Client/Options.c | 26 ++++++------ src/Client/Program.c | 22 ++-------- src/Client/Stream.c | 10 ++--- src/Client/TexturePack.c | 82 ++++++++++++++++++------------------ src/Client/Utils.c | 11 +++++ src/Client/Utils.h | 1 + 22 files changed, 210 insertions(+), 169 deletions(-) diff --git a/src/Client/Animations.c b/src/Client/Animations.c index 46bf81920..e561984b1 100644 --- a/src/Client/Animations.c +++ b/src/Client/Animations.c @@ -188,8 +188,9 @@ static void Animations_ReadDescription(struct Stream* stream) { } if (anims_count == Array_Elems(anims_list)) { - ErrorHandler_Fail("Too many animations in animations.txt"); + Chat_AddRaw("&cCannot show over 256 animations"); return; } + data.TexLoc = tileX + (tileY * ATLAS2D_TILES_PER_ROW); anims_list[anims_count++] = data; } @@ -320,7 +321,10 @@ static void Animations_FileChanged(void* obj, struct Stream* stream) { String* name = &stream->Name; if (String_CaselessEqualsConst(name, "animation.png") || String_CaselessEqualsConst(name, "animations.png")) { ReturnCode result = Bitmap_DecodePng(&anims_bmp, stream); - ErrorHandler_CheckOrFail(result, "Decoding animations bitmap"); + if (!result) return; + + ErrorHandler_LogError_Path(result, "decoding", name); + Mem_Free(&anims_bmp.Scan0); } else if (String_CaselessEqualsConst(name, "animation.txt") || String_CaselessEqualsConst(name, "animations.txt")) { Animations_ReadDescription(stream); } else if (String_CaselessEqualsConst(name, "uselavaanim")) { diff --git a/src/Client/AsyncDownloader.c b/src/Client/AsyncDownloader.c index 316d5ed70..209f7ad75 100644 --- a/src/Client/AsyncDownloader.c +++ b/src/Client/AsyncDownloader.c @@ -198,7 +198,7 @@ static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) { result = Http_MakeRequest(request, &handle); elapsedMS = Stopwatch_ElapsedMicroseconds(&stopwatch) / 1000; Platform_Log2("HTTP make request: ret code %i, in %i ms", &result, &elapsedMS); - if (!ErrorHandler_Check(result)) return; + if (result) return; async_curProgress = ASYNC_PROGRESS_FETCHING_DATA; UInt32 size = 0; @@ -208,7 +208,7 @@ static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) { UInt32 status = request->StatusCode; Platform_Log3("HTTP get headers: ret code %i (http %i), in %i ms", &result, &status, &elapsedMS); - if (!ErrorHandler_Check(result) || request->StatusCode != 200) { + if (result || request->StatusCode != 200) { Http_FreeRequest(handle); return; } @@ -221,7 +221,7 @@ static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) { } Http_FreeRequest(handle); - if (!ErrorHandler_Check(result)) return; + if (result) return; UInt64 addr = (UInt64)data; Platform_Log2("OK I got the DATA! %i bytes at %x", &size, &addr); diff --git a/src/Client/Audio.c b/src/Client/Audio.c index 66b5ec628..2fe6cf1c3 100644 --- a/src/Client/Audio.c +++ b/src/Client/Audio.c @@ -10,6 +10,7 @@ #include "GameStructs.h" #include "Errors.h" #include "Vorbis.h" +#include "Chat.h" StringsBuffer files; /*########################################################################################################################* @@ -117,19 +118,26 @@ static void Soundboard_Init(struct Soundboard* board, STRING_PURE String* boardN struct SoundGroup* group = Soundboard_Find(board, &name); if (group == NULL) { - if (board->Count == Array_Elems(board->Groups)) ErrorHandler_Fail("Soundboard - too many groups"); + if (board->Count == Array_Elems(board->Groups)) { + Chat_AddRaw("&cCannot have more than 10 sound groups"); return; + } group = &board->Groups[board->Count++]; group->Name = String_InitAndClearArray(group->NameBuffer); String_Set(&group->Name, &name); } - if (group->Count == Array_Elems(group->Sounds)) ErrorHandler_Fail("Soundboard - too many sounds"); + if (group->Count == Array_Elems(group->Sounds)) { + Chat_AddRaw("&cCannot have more than 10 sounds in a group"); return; + } + struct Sound* snd = &group->Sounds[group->Count]; ReturnCode result = Sound_ReadWave(&file, snd); - ErrorHandler_CheckOrFail(result, "Soundboard - reading WAV"); - group->Count++; + if (result) { + ErrorHandler_LogError_Path(result, "decoding", &file); + Mem_Free(&snd->Data); + } else { group->Count++; } } } @@ -337,6 +345,7 @@ static void Music_RunLoop(void) { if (!count) return; Random rnd; Random_InitFromCurrentTime(&rnd); UInt8 pathBuffer[String_BufferSize(FILENAME_SIZE)]; + ReturnCode result; while (!music_pendingStop) { Int32 idx = Random_Range(&rnd, 0, count); @@ -345,17 +354,17 @@ static void Music_RunLoop(void) { String_Format2(&path, "audio%r%s", &Directory_Separator, &filename); Platform_Log1("playing music file: %s", &filename); - void* file; ReturnCode result = File_Open(&file, &path); - ErrorHandler_CheckOrFail(result, "Music_RunLoop - opening file"); + void* file; result = File_Open(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "opening", &path); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { result = Music_PlayOgg(&stream); - ErrorHandler_CheckOrFail(result, "Music_RunLoop - playing ogg"); + if (result) { ErrorHandler_LogError_Path(result, "playing", &path); } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Music_RunLoop - closing file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); } - if (music_pendingStop) break; + if (music_pendingStop) return; Int32 delay = 1000 * 120 + Random_Range(&rnd, 0, 1000 * 300); Waitable_WaitFor(music_waitable, delay); } diff --git a/src/Client/Bitmap.c b/src/Client/Bitmap.c index aa4c8a659..3228d0cb4 100644 --- a/src/Client/Bitmap.c +++ b/src/Client/Bitmap.c @@ -458,8 +458,8 @@ ReturnCode Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { UInt32 bufferLeft = bufferLen - bufferIdx, read; if (bufferLeft > bufferMax) bufferLeft = bufferMax; - ReturnCode code = compStream.Read(&compStream, &buffer[bufferIdx], bufferLeft, &read); - ErrorHandler_CheckOrFail(code, "PNG - reading image bulk data"); + result = compStream.Read(&compStream, &buffer[bufferIdx], bufferLeft, &read); + if (result) return result; if (!read) break; UInt32 startY = bufferIdx / scanlineBytes, rowY; diff --git a/src/Client/Chat.c b/src/Client/Chat.c index eb61268bd..14c5772a9 100644 --- a/src/Client/Chat.c +++ b/src/Client/Chat.c @@ -48,8 +48,8 @@ DateTime ChatLog_LastLogDate; static void Chat_CloseLog(void) { if (!Chat_LogStream.Meta.File) return; - ReturnCode code = Chat_LogStream.Close(&Chat_LogStream); - ErrorHandler_CheckOrFail(code, "Chat - closing log file"); + ReturnCode result = Chat_LogStream.Close(&Chat_LogStream); + if (result) ErrorHandler_LogError(result, "closing chat log file"); } static bool Chat_AllowedLogChar(UChar c) { @@ -74,11 +74,14 @@ void Chat_SetLogName(STRING_PURE String* name) { } } +static void Chat_DisableLogging(void) { + Game_ChatLogging = false; + Chat_AddRaw("&cDisabling chat logging as a result"); +} + static void Chat_OpenLog(DateTime* now) { - String logsDir = String_FromConst("logs"); - if (!Directory_Exists(&logsDir)) { - Directory_Create(&logsDir); - } + ReturnCode result; + if (!Utils_EnsureDirectory("logs")) { Chat_DisableLogging(); return; } /* Ensure multiple instances do not end up overwriting each other's log entries. */ Int32 i, year = now->Year, month = now->Month, day = now->Day; @@ -93,9 +96,10 @@ static void Chat_OpenLog(DateTime* now) { String_Format1(&path, "%s.log", &Chat_LogName); } - void* file; ReturnCode result = File_Append(&file, &path); + void* file; result = File_Append(&file, &path); if (result && result != ReturnCode_FileShareViolation) { - ErrorHandler_FailWithCode(result, "Chat - opening log file"); + ErrorHandler_LogError_Path(result, "appending to", &path); + Chat_DisableLogging(); return; } if (result == ReturnCode_FileShareViolation) continue; @@ -104,8 +108,8 @@ static void Chat_OpenLog(DateTime* now) { } Chat_LogStream.Meta.File = NULL; - String failedMsg = String_FromConst("Failed to open chat log file after 20 tries, giving up"); - ErrorHandler_Log(&failedMsg); + ErrorHandler_Log1("Failed to open a chat log file after %i tries, giving up", &i); + Chat_DisableLogging(); } static void Chat_AppendLog(STRING_PURE String* text) { diff --git a/src/Client/D3D9Api.c b/src/Client/D3D9Api.c index 4d0943b91..e5ed10190 100644 --- a/src/Client/D3D9Api.c +++ b/src/Client/D3D9Api.c @@ -73,7 +73,7 @@ static void D3D9_FindCompatibleFormat(void) { for (i = 0; i < count; i++) { d3d9_viewFormat = d3d9_viewFormats[i]; res = IDirect3D9_CheckDeviceType(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3d9_viewFormat, d3d9_viewFormat, true); - if (ErrorHandler_Check(res)) break; + if (!res) break; if (i == count - 1) { ErrorHandler_Fail("Unable to create a back buffer with sufficient precision."); @@ -84,7 +84,7 @@ static void D3D9_FindCompatibleFormat(void) { for (i = 0; i < count; i++) { d3d9_depthFormat = d3d9_depthFormats[i]; res = IDirect3D9_CheckDepthStencilMatch(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3d9_viewFormat, d3d9_viewFormat, d3d9_depthFormat); - if (ErrorHandler_Check(res)) break; + if (!res) break; if (i == count - 1) { ErrorHandler_Fail("Unable to create a depth buffer with sufficient precision."); @@ -130,11 +130,11 @@ void Gfx_Init(void) { /* Try to create a device with as much hardware usage as possible. */ res = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winHandle, createFlags, &args, &device); - if (!ErrorHandler_Check(res)) { + if (res) { createFlags = D3DCREATE_MIXED_VERTEXPROCESSING; res = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winHandle, createFlags, &args, &device); } - if (!ErrorHandler_Check(res)) { + if (res) { createFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; res = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winHandle, createFlags, &args, &device); } @@ -565,32 +565,33 @@ void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 z } -void Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height) { - IDirect3DSurface9* backbuffer; - IDirect3DSurface9* temp; - ReturnCode hresult; +ReturnCode Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height) { + IDirect3DSurface9* backbuffer = NULL; + IDirect3DSurface9* temp = NULL; + ReturnCode result; - hresult = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Get back buffer"); - hresult = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &temp, NULL); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Create temp surface"); - /* For DX 8 use IDirect3DDevice8::CreateImageSurface */ + result = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); + if (result) goto finished; + result = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &temp, NULL); + if (result) goto finished; /* TODO: For DX 8 use IDirect3DDevice8::CreateImageSurface */ + result = IDirect3DDevice9_GetRenderTargetData(device, backbuffer, temp); + if (result) goto finished; - hresult = IDirect3DDevice9_GetRenderTargetData(device, backbuffer, temp); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Copying back buffer"); D3DLOCKED_RECT rect; - hresult = IDirect3DSurface9_LockRect(temp, &rect, NULL, D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Lock temp surface"); - - struct Bitmap bmp; Bitmap_Create(&bmp, width, height, rect.pBits); - hresult = Bitmap_EncodePng(&bmp, output); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Writing .png"); - - hresult = IDirect3DSurface9_UnlockRect(temp); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Unlock temp surface"); + result = IDirect3DSurface9_LockRect(temp, &rect, NULL, D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE); + if (result) goto finished; + { + struct Bitmap bmp; Bitmap_Create(&bmp, width, height, rect.pBits); + result = Bitmap_EncodePng(&bmp, output); + if (result) { IDirect3DSurface9_UnlockRect(temp); goto finished; } + } + result = IDirect3DSurface9_UnlockRect(temp); + if (result) goto finished; +finished: D3D9_FreeResource(&backbuffer); D3D9_FreeResource(&temp); + return result; } bool Gfx_WarnIfNecessary(void) { return false; } diff --git a/src/Client/Entity.c b/src/Client/Entity.c index b37ef03ea..568e12cbe 100644 --- a/src/Client/Entity.c +++ b/src/Client/Entity.c @@ -656,8 +656,6 @@ static void Player_EnsurePow2(struct Player* player, struct Bitmap* bmp) { if (width == bmp->Width && height == bmp->Height) return; struct Bitmap scaled; Bitmap_Allocate(&scaled, width, height); - if (!scaled.Scan0) ErrorHandler_Fail("Failed to allocate memory for resizing player skin"); - Int32 y; UInt32 stride = (UInt32)(bmp->Width) * BITMAP_SIZEOF_PIXEL; for (y = 0; y < bmp->Height; y++) { @@ -695,8 +693,13 @@ static void Player_CheckSkin(struct Player* player) { String url = String_FromRawArray(item.URL); struct Stream mem; struct Bitmap bmp; Stream_ReadonlyMemory(&mem, item.ResultData, item.ResultSize, &url); + ReturnCode result = Bitmap_DecodePng(&bmp, &mem); - ErrorHandler_CheckOrFail(result, "Decoding player skin"); + if (result) { + ErrorHandler_LogError_Path(result, "decoding", &url); + Mem_Free(&bmp.Scan0); + return; + } Gfx_DeleteTexture(&entity->TextureId); Player_SetSkinAll(player, true); diff --git a/src/Client/ErrorHandler.c b/src/Client/ErrorHandler.c index b97745a8d..3b5f8fc5d 100644 --- a/src/Client/ErrorHandler.c +++ b/src/Client/ErrorHandler.c @@ -30,6 +30,10 @@ void ErrorHandler_LogError(ReturnCode result, const UChar* place) { ErrorHandler_Log4("&cError %y when %c", &result, place, NULL, NULL); } +void ErrorHandler_LogError_Path(ReturnCode result, const UChar* place, STRING_PURE String* path) { + ErrorHandler_Log4("&cError %y when %c '%s'", &result, place, path, NULL); +} + void ErrorHandler_FailWithCode(ReturnCode result, const UChar* raw_msg) { UChar logMsgBuffer[String_BufferSize(3071)]; String logMsg = String_InitAndClearArray(logMsgBuffer); diff --git a/src/Client/ErrorHandler.h b/src/Client/ErrorHandler.h index c8b8a26c2..bfe77e187 100644 --- a/src/Client/ErrorHandler.h +++ b/src/Client/ErrorHandler.h @@ -13,11 +13,11 @@ void ErrorHandler_Log2(const UChar* format, const void* a1, const void* a2); void ErrorHandler_Log3(const UChar* format, const void* a1, const void* a2, const void* a3); void ErrorHandler_Log4(const UChar* format, const void* a1, const void* a2, const void* a3, const void* a4); void ErrorHandler_LogError(ReturnCode result, const UChar* place); +void ErrorHandler_LogError_Path(ReturnCode result, const UChar* place, STRING_PURE String* path); -#define ErrorHandler_Check(returnCode) ((returnCode) == 0) void ErrorHandler_Fail(const UChar* raw_msg); void ErrorHandler_FailWithCode(ReturnCode returnCode, const UChar* raw_msg); -#define ErrorHandler_CheckOrFail(returnCode, raw_msg) if (returnCode != 0) { ErrorHandler_FailWithCode(returnCode, raw_msg); } +#define ErrorHandler_CheckOrFail(returnCode, raw_msg) if (returnCode) { ErrorHandler_FailWithCode(returnCode, raw_msg); } void ErrorHandler_ShowDialog(const UChar* title, const UChar* msg); void ErrorHandler_Backtrace(STRING_TRANSIENT String* str); #endif diff --git a/src/Client/Formats.c b/src/Client/Formats.c index c44e6f886..c1e043daa 100644 --- a/src/Client/Formats.c +++ b/src/Client/Formats.c @@ -14,7 +14,7 @@ static ReturnCode Map_ReadBlocks(struct Stream* stream) { World_BlocksSize = World_Width * World_Length * World_Height; - World_Blocks = Mem_Alloc(World_BlocksSize, sizeof(BlockID), "map blocks for load"); + World_Blocks = Mem_Alloc(World_BlocksSize, sizeof(BlockID), "map blocks"); return Stream_TryRead(stream, World_Blocks, World_BlocksSize); } diff --git a/src/Client/Game.c b/src/Client/Game.c index 7f4c40ef4..145fe7203 100644 --- a/src/Client/Game.c +++ b/src/Client/Game.c @@ -207,9 +207,9 @@ bool Game_CanPick(BlockID block) { bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, UInt8* skinType) { struct Bitmap bmp; ReturnCode result = Bitmap_DecodePng(&bmp, src); - ErrorHandler_CheckOrFail(result, "Decoding texture"); + if (result) { ErrorHandler_LogError_Path(result, "decoding", &src->Name); } - bool success = Game_ValidateBitmap(&src->Name, &bmp); + bool success = !result && Game_ValidateBitmap(&src->Name, &bmp); if (success) { Gfx_DeleteTexture(texId); if (skinType != NULL) { *skinType = Utils_GetSkinType(&bmp); } @@ -293,19 +293,27 @@ static void Game_OnNewMapLoadedCore(void* obj) { } static void Game_TextureChangedCore(void* obj, struct Stream* src) { - if (String_CaselessEqualsConst(&src->Name, "terrain.png")) { - struct Bitmap atlas; - ReturnCode result = Bitmap_DecodePng(&atlas, src); - ErrorHandler_CheckOrFail(result, "Decoding terrain bitmap"); - - if (Game_ChangeTerrainAtlas(&atlas)) return; - Mem_Free(&atlas.Scan0); - } else if (String_CaselessEqualsConst(&src->Name, "default.png")) { - struct Bitmap bmp; + String* name = &src->Name; + struct Bitmap bmp; + if (String_CaselessEqualsConst(name, "terrain.png")) { ReturnCode result = Bitmap_DecodePng(&bmp, src); - ErrorHandler_CheckOrFail(result, "Decoding font bitmap"); - Drawer2D_SetFontBitmap(&bmp); - Event_RaiseVoid(&ChatEvents_FontChanged); + + if (result) { + ErrorHandler_LogError_Path(result, "decoding", name); + Mem_Free(&bmp.Scan0); + } else if (!Game_ChangeTerrainAtlas(&bmp)) { + Mem_Free(&bmp.Scan0); + } + } else if (String_CaselessEqualsConst(name, "default.png")) { + ReturnCode result = Bitmap_DecodePng(&bmp, src); + + if (result) { + ErrorHandler_LogError_Path(result, "decoding", name); + Mem_Free(&bmp.Scan0); + } else { + Drawer2D_SetFontBitmap(&bmp); + Event_RaiseVoid(&ChatEvents_FontChanged); + } } } @@ -616,11 +624,9 @@ static void Game_DoScheduledTasks(Real64 time) { } void Game_TakeScreenshot(void) { - String dir = String_FromConst("screenshots"); - if (!Directory_Exists(&dir)) { - ReturnCode result = Directory_Create(&dir); - ErrorHandler_CheckOrFail(result, "Creating screenshots directory"); - } + ReturnCode result; + Game_ScreenshotRequested = false; + if (!Utils_EnsureDirectory("screenshots")) return; DateTime now; DateTime_CurrentLocal(&now); Int32 year = now.Year, month = now.Month, day = now.Day; @@ -635,16 +641,20 @@ void Game_TakeScreenshot(void) { String path = String_InitAndClearArray(pathBuffer); String_Format2(&path, "screenshots%r%s", &Directory_Separator, &filename); - void* file; ReturnCode result = File_Create(&file, &path); - ErrorHandler_CheckOrFail(result, "Taking screenshot - opening file"); + void* file; result = File_Create(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "creating", &path); return; } + struct Stream stream; Stream_FromFile(&stream, file, &path); { - Gfx_TakeScreenshot(&stream, Game_Width, Game_Height); + result = Gfx_TakeScreenshot(&stream, Game_Width, Game_Height); + if (result) { + ErrorHandler_LogError(result, "saving screenshot"); + stream.Close(&stream); return; + } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Taking screenshot - closing file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); return; } - Game_ScreenshotRequested = false; String_Clear(&path); String_Format1(&path, "&eTaken screenshot as: %s", &filename); Chat_Add(&path); diff --git a/src/Client/GraphicsAPI.h b/src/Client/GraphicsAPI.h index f2bae2b2f..8928d0059 100644 --- a/src/Client/GraphicsAPI.h +++ b/src/Client/GraphicsAPI.h @@ -96,7 +96,7 @@ void Gfx_CalcOrthoMatrix(Real32 width, Real32 height, struct Matrix* matrix); void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 zFar, struct Matrix* matrix); /* Outputs a .png screenshot of the backbuffer */ -void Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height); +ReturnCode Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height); /* Adds a warning to game's chat if this graphics API has problems with the current user's GPU. Returns boolean of whether legacy rendering mode is needed. */ bool Gfx_WarnIfNecessary(void); diff --git a/src/Client/Gui.c b/src/Client/Gui.c index 66b00c99c..fe7081a16 100644 --- a/src/Client/Gui.c +++ b/src/Client/Gui.c @@ -156,7 +156,7 @@ void Gui_RefreshHud(void) { Elem_Recreate(Gui_HUD); } void Gui_ShowOverlay(struct Screen* overlay, bool atFront) { if (Gui_OverlaysCount == GUI_MAX_OVERLAYS) { - ErrorHandler_Fail("Cannot have more than 6 overlays"); + ErrorHandler_Fail("Gui_ShowOverlay - hit max count"); } if (atFront) { diff --git a/src/Client/Input.c b/src/Client/Input.c index 311ceed35..70740f698 100644 --- a/src/Client/Input.c +++ b/src/Client/Input.c @@ -5,6 +5,7 @@ #include "Utils.h" #include "ErrorHandler.h" #include "Platform.h" +#include "Chat.h" #define Key_Function_Names \ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",\ @@ -223,7 +224,8 @@ void Hotkeys_AddNewHotkey(Key trigger, UInt8 flags, STRING_PURE String* text, bo hKey.StaysOpen = more; if (HotkeysText.Count == HOTKEYS_MAX_COUNT) { - ErrorHandler_Fail("Cannot define more than 256 hotkeys"); + Chat_AddRaw("&cCannot define more than 256 hotkeys"); + return; } HotkeysList[HotkeysText.Count] = hKey; diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 404b6991a..82ffeee2f 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -1336,9 +1336,10 @@ static void SaveLevelScreen_Render(struct GuiElem* elem, Real64 delta) { struct SaveLevelScreen* screen = (struct SaveLevelScreen*)elem; if (!screen->TextPath.length) return; String path = screen->TextPath; + ReturnCode result; - void* file; ReturnCode result = File_Create(&file, &path); - ErrorHandler_CheckOrFail(result, "Saving map - opening file"); + void* file; result = File_Create(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "creating", &path); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { String cw = String_FromConst(".cw"); @@ -1349,7 +1350,7 @@ static void SaveLevelScreen_Render(struct GuiElem* elem, Real64 delta) { } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Saving map - closing file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); return; } UChar msgBuffer[String_BufferSize(STRING_SIZE * 2)]; String msg = String_InitAndClearArray(msgBuffer); @@ -1619,7 +1620,7 @@ void LoadLevelScreen_LoadMap(STRING_PURE String* path) { Inventory_SetDefaultMapping(); void* file; ReturnCode result = File_Open(&file, path); - ErrorHandler_CheckOrFail(result, "Loading map - open file"); + if (result) { ErrorHandler_LogError_Path(result, "opening", path); return; } struct Stream stream; Stream_FromFile(&stream, file, path); { String cw = String_FromConst(".cw"); String lvl = String_FromConst(".lvl"); @@ -1634,10 +1635,15 @@ void LoadLevelScreen_LoadMap(STRING_PURE String* path) { } else if (String_CaselessEnds(path, &lvl)) { result = Lvl_Load(&stream); } - ErrorHandler_CheckOrFail(result, "Loading map - reading data"); + + if (result) { + ErrorHandler_LogError_Path(result, "decoding", path); + Mem_Free(&World_Blocks); World_BlocksSize = 0; + stream.Close(&stream); return; + } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Loading map - close file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", path); } World_SetNewMap(World_Blocks, World_BlocksSize, World_Width, World_Height, World_Length); Event_RaiseVoid(&WorldEvents_MapLoaded); diff --git a/src/Client/OpenGLApi.c b/src/Client/OpenGLApi.c index 6d4ffa338..7342735ec 100644 --- a/src/Client/OpenGLApi.c +++ b/src/Client/OpenGLApi.c @@ -516,7 +516,7 @@ void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 z } -void Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height) { +ReturnCode Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height) { struct Bitmap bmp; Bitmap_Allocate(&bmp, width, height); glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bmp.Scan0); UInt8 tmp[PNG_MAX_DIMS * BITMAP_SIZEOF_PIXEL]; @@ -536,9 +536,9 @@ void Gfx_TakeScreenshot(struct Stream* output, Int32 width, Int32 height) { }*/ } - ReturnCode hresult = Bitmap_EncodePng(&bmp, output); - ErrorHandler_CheckOrFail(hresult, "Gfx_TakeScreenshot - Writing .png"); + ReturnCode result = Bitmap_EncodePng(&bmp, output); Mem_Free(&bmp.Scan0); + return result; } void Gfx_MakeApiInfo(void) { diff --git a/src/Client/Options.c b/src/Client/Options.c index 9094a34ea..5fc3740ea 100644 --- a/src/Client/Options.c +++ b/src/Client/Options.c @@ -158,15 +158,11 @@ void Options_Set(const UChar* keyRaw, STRING_PURE String* value) { void Options_Load(void) { String path = String_FromConst("options.txt"); - void* file; ReturnCode result = File_Open(&file, &path); + ReturnCode result; + void* file; result = File_Open(&file, &path); if (result == ReturnCode_FileNotFound) return; - /* TODO: Should we just log failure to open? */ - ErrorHandler_CheckOrFail(result, "Options - Loading"); - - UChar lineBuffer[String_BufferSize(768)]; - String line = String_InitAndClearArray(lineBuffer); - struct Stream stream; Stream_FromFile(&stream, file, &path); + if (result) { ErrorHandler_LogError_Path(result, "opening", &path); return; } /* Remove all the unchanged options */ UInt32 i; @@ -176,6 +172,10 @@ void Options_Load(void) { Options_Remove(i - 1); } + UChar lineBuffer[String_BufferSize(768)]; + String line = String_InitAndClearArray(lineBuffer); + struct Stream stream; Stream_FromFile(&stream, file, &path); + /* ReadLine reads single byte at a time */ UInt8 buffer[2048]; struct Stream buffered; Stream_ReadonlyBuffered(&buffered, &stream, buffer, sizeof(buffer)); @@ -197,15 +197,15 @@ void Options_Load(void) { } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Options load - close file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); return; } } void Options_Save(void) { String path = String_FromConst("options.txt"); - void* file; ReturnCode result = File_Create(&file, &path); + ReturnCode result; - /* TODO: Should we just log failure to save? */ - ErrorHandler_CheckOrFail(result, "Options - Saving"); + void* file; result = File_Create(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "creating", &path); return; } UChar lineBuffer[String_BufferSize(1024)]; String line = String_InitAndClearArray(lineBuffer); @@ -221,7 +221,7 @@ void Options_Save(void) { String_Clear(&line); } - result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "Options save - close file"); StringsBuffer_Free(&Options_Changed); + result = stream.Close(&stream); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); return; } } diff --git a/src/Client/Program.c b/src/Client/Program.c index 4a8c1cbe5..90725497c 100644 --- a/src/Client/Program.c +++ b/src/Client/Program.c @@ -11,8 +11,8 @@ #include "Game.h" #include "Funcs.h" #include "AsyncDownloader.h" -#include "Audio.h" #include "ExtMath.h" +#include "Utils.h" //#define CC_TEST_VORBIS #ifdef CC_TEST_VORBIS @@ -61,23 +61,9 @@ int main(void) { ReturnCode ret2 = Http_FreeRequest(reqHandle); ReturnCode ret3 = Http_Free();*/ - String maps = String_FromConst("maps"); - if (!Directory_Exists(&maps)) { - ReturnCode result = Directory_Create(&maps); - ErrorHandler_CheckOrFail(result, "Program - creating maps directory"); - } - - String texPacks = String_FromConst("texpacks"); - if (!Directory_Exists(&texPacks)) { - ReturnCode result = Directory_Create(&texPacks); - ErrorHandler_CheckOrFail(result, "Program - creating texpacks directory"); - } - - String texCache = String_FromConst("texturecache"); - if (!Directory_Exists(&texCache)) { - ReturnCode result = Directory_Create(&texCache); - ErrorHandler_CheckOrFail(result, "Program - creating texturecache directory"); - } + Utils_EnsureDirectory("maps"); + Utils_EnsureDirectory("texpacks"); + Utils_EnsureDirectory("texturecache"); UChar defPathBuffer[String_BufferSize(STRING_SIZE)]; String defPath = String_InitAndClearArray(defPathBuffer); diff --git a/src/Client/Stream.c b/src/Client/Stream.c index 8870e26bd..7f9423906 100644 --- a/src/Client/Stream.c +++ b/src/Client/Stream.c @@ -9,7 +9,7 @@ *#########################################################################################################################*/ #define Stream_SafeWriteBlock(stream, buffer, count, write)\ ReturnCode result = stream->Write(stream, buffer, count, &write);\ -if (!write || !ErrorHandler_Check(result)) {\ +if (!write || result) {\ Stream_Fail(stream, result, "writing to");\ } @@ -24,7 +24,7 @@ void Stream_Read(struct Stream* stream, UInt8* buffer, UInt32 count) { UInt32 read; while (count) { ReturnCode result = stream->Read(stream, buffer, count, &read); - if (!read || !ErrorHandler_Check(result)) { Stream_Fail(stream, result, "reading from"); } + if (!read || result) { Stream_Fail(stream, result, "reading from"); } buffer += read; count -= read; @@ -123,9 +123,9 @@ static ReturnCode Stream_FileWrite(struct Stream* stream, UInt8* data, UInt32 co return File_Write(stream->Meta.File, data, count, modified); } static ReturnCode Stream_FileClose(struct Stream* stream) { - ReturnCode code = File_Close(stream->Meta.File); + ReturnCode result = File_Close(stream->Meta.File); stream->Meta.File = NULL; - return code; + return result; } static ReturnCode Stream_FileSeek(struct Stream* stream, Int32 offset, Int32 seekType) { return File_Seek(stream->Meta.File, offset, seekType); @@ -422,7 +422,7 @@ bool Stream_ReadLine(struct Stream* stream, STRING_TRANSIENT String* text) { ReturnCode result = Stream_ReadUtf8Char(stream, &codepoint); if (result == ERR_END_OF_STREAM) break; - if (!ErrorHandler_Check(result)) { Stream_Fail(stream, result, "reading utf8 from"); } + if (result) { Stream_Fail(stream, result, "reading utf8 from"); } readAny = true; /* Handle \r\n or \n line endings */ diff --git a/src/Client/TexturePack.c b/src/Client/TexturePack.c index de78c927a..1cf10470f 100644 --- a/src/Client/TexturePack.c +++ b/src/Client/TexturePack.c @@ -189,13 +189,14 @@ static void EntryList_Load(struct EntryList* list) { String folder = String_FromRawArray(list->FolderBuffer); String filename = String_FromRawArray(list->FileBuffer); UChar pathBuffer[String_BufferSize(FILENAME_SIZE)]; + String path = String_InitAndClearArray(pathBuffer); String_Format3(&path, "%s%r%s", &folder, &Directory_Separator, &filename); + ReturnCode result; - void* file; ReturnCode result = File_Open(&file, &path); + void* file; result = File_Open(&file, &path); if (result == ReturnCode_FileNotFound) return; - /* TODO: Should we just log failure to save? */ - ErrorHandler_CheckOrFail(result, "EntryList_Load - open file"); + if (result) { ErrorHandler_LogError_Path(result, "opening", &path); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { /* ReadLine reads single byte at a time */ @@ -211,24 +212,25 @@ static void EntryList_Load(struct EntryList* list) { } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "EntryList_Load - close file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); } } static void EntryList_Save(struct EntryList* list) { String folder = String_FromRawArray(list->FolderBuffer); String filename = String_FromRawArray(list->FileBuffer); UChar pathBuffer[String_BufferSize(FILENAME_SIZE)]; + String path = String_InitAndClearArray(pathBuffer); String_Format3(&path, "%s%r%s", &folder, &Directory_Separator, &filename); + ReturnCode result; if (!Directory_Exists(&folder)) { - ReturnCode dirResult = Directory_Create(&folder); - ErrorHandler_CheckOrFail(dirResult, "EntryList_Save - create directory"); + result = Directory_Create(&folder); + if (result) { ErrorHandler_LogError_Path(result, "creating", &folder); return; } } - void* file; ReturnCode result = File_Create(&file, &path); - /* TODO: Should we just log failure to save? */ - ErrorHandler_CheckOrFail(result, "EntryList_Save - open file"); + void* file; result = File_Create(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "creating", &path); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { Int32 i; @@ -238,7 +240,7 @@ static void EntryList_Save(struct EntryList* list) { } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "EntryList_Save - close file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); } } static void EntryList_Add(struct EntryList* list, STRING_PURE String* entry) { @@ -312,7 +314,7 @@ bool TextureCache_GetStream(STRING_PURE String* url, struct Stream* stream) { void* file; ReturnCode result = File_Open(&file, &path); if (result == ReturnCode_FileNotFound) return false; - ErrorHandler_CheckOrFail(result, "TextureCache - GetStream"); + if (result) { ErrorHandler_LogError_Path(result, "opening cache for", url); return false; } Stream_FromFile(stream, file, &path); return true; } @@ -338,12 +340,16 @@ void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time) { TexturePack_GetFromTags(url, &entry, &cache_lastModified); Int64 ticks; + DateTime temp; + if (entry.length && Convert_TryParseInt64(&entry, &ticks)) { DateTime_FromTotalMs(time, ticks / TEXCACHE_TICKS_PER_MS); } else { String path; TexCache_InitAndMakePath(url); - ReturnCode result = File_GetModifiedTime(&path, time); - ErrorHandler_CheckOrFail(result, "TextureCache - get file last modified time") + ReturnCode result = File_GetModifiedTime(&path, &temp); + + if (result) { ErrorHandler_LogError_Path(result, "getting last modified time of", url); return; } + *time = temp; } } @@ -354,22 +360,17 @@ void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag) { void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length) { String path; TexCache_InitAndMakePath(url); ReturnCode result; - - String folder = String_FromConst(TEXCACHE_FOLDER); - if (!Directory_Exists(&folder)) { - result = Directory_Create(&folder); - ErrorHandler_CheckOrFail(result, "TextureCache_AddData - create directory"); - } + if (!Utils_EnsureDirectory(TEXCACHE_FOLDER)) return; void* file; result = File_Create(&file, &path); - /* TODO: Should we just log failure to save? */ - ErrorHandler_CheckOrFail(result, "TextureCache_AddData - open file"); + if (result) { ErrorHandler_LogError_Path(result, "creating cache for", url); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { - Stream_Write(&stream, data, length); + result = Stream_TryWrite(&stream, data, length); + if (result) { ErrorHandler_LogError_Path(result, "saving data for", url); } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "TextureCache_AddData - close file"); + if (result) { ErrorHandler_LogError_Path(result, "closing cache for", url); } } void TextureCache_AddToTags(STRING_PURE String* url, STRING_PURE String* data, struct EntryList* list) { @@ -429,23 +430,24 @@ void TexturePack_ExtractZip_File(STRING_PURE String* filename) { UChar pathBuffer[String_BufferSize(FILENAME_SIZE)]; String path = String_InitAndClearArray(pathBuffer); String_Format2(&path, "texpacks%r%s", &Directory_Separator, filename); + ReturnCode result; - void* file; ReturnCode result = File_Open(&file, &path); - ErrorHandler_CheckOrFail(result, "TexturePack_Extract - opening file"); + void* file; result = File_Open(&file, &path); + if (result) { ErrorHandler_LogError_Path(result, "opening", &path); return; } struct Stream stream; Stream_FromFile(&stream, file, &path); { result = TexturePack_ExtractZip(&stream); - ErrorHandler_CheckOrFail(result, "TexturePack_Extract - extract content"); + if (result) { ErrorHandler_LogError_Path(result, "extracting", &path); } } result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "TexturePack_Extract - closing file"); + if (result) { ErrorHandler_LogError_Path(result, "closing", &path); } } ReturnCode TexturePack_ExtractTerrainPng(struct Stream* stream) { struct Bitmap bmp; ReturnCode result = Bitmap_DecodePng(&bmp, stream); - if (result == 0) { + if (!result) { Event_RaiseVoid(&TextureEvents_PackChanged); if (Game_ChangeTerrainAtlas(&bmp)) return 0; } @@ -475,17 +477,18 @@ void TexturePack_ExtractCurrent(STRING_PURE String* url) { ReturnCode result = 0; if (String_Equals(url, &World_TextureUrl)) { - } else if (String_ContainsString(url, &zip)) { - String_Set(&World_TextureUrl, url); - result = TexturePack_ExtractZip(&stream); } else { + bool zip = String_ContainsString(url, &zip); String_Set(&World_TextureUrl, url); - result = TexturePack_ExtractTerrainPng(&stream); + const UChar* operation = zip ? "extracting" : "decoding"; + + ReturnCode result = zip ? TexturePack_ExtractZip(&stream) : + TexturePack_ExtractTerrainPng(&stream); + if (result) { ErrorHandler_LogError_Path(result, operation, &url); } } - ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - extract content"); result = stream.Close(&stream); - ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - close stream"); + if (result) { ErrorHandler_LogError_Path(result, "closing cache for", url); } } } @@ -503,13 +506,10 @@ void TexturePack_Extract_Req(struct AsyncRequest* item) { String id = String_FromRawArray(item->ID); struct Stream mem; Stream_ReadonlyMemory(&mem, data, len, &id); - ReturnCode result; - if (Bitmap_DetectPng(data, len)) { - result = TexturePack_ExtractTerrainPng(&mem); - } else { - result = TexturePack_ExtractZip(&mem); - } + bool png = Bitmap_DetectPng(data, len); + ReturnCode result = png ? TexturePack_ExtractTerrainPng(&mem) : TexturePack_ExtractZip(&mem); + const UChar* operation = png ? "decoding" : "extracting"; - ErrorHandler_CheckOrFail(result, "TexturePack_Extract_Req - extract content"); + if (result) { ErrorHandler_LogError_Path(result, operation, &url); } ASyncRequest_Free(item); } \ No newline at end of file diff --git a/src/Client/Utils.c b/src/Client/Utils.c index c0c8a95a9..988968c38 100644 --- a/src/Client/Utils.c +++ b/src/Client/Utils.c @@ -2,6 +2,8 @@ #include "Constants.h" #include "Bitmap.h" #include "PackedCol.h" +#include "ErrorHandler.h" +#include "Platform.h" #define DATETIME_SECONDS_PER_MINUTE 60 #define DATETIME_SECONDS_PER_HOUR (60 * 60) @@ -119,6 +121,15 @@ bool Utils_IsUrlPrefix(STRING_PURE String* value, Int32 index) { || String_IndexOfString(value, &https) == index; } +bool Utils_EnsureDirectory(STRING_PURE const UChar* dirName) { + String dir = String_FromReadonly(dirName); + if (Directory_Exists(&dir)) return true; + + ReturnCode result = Directory_Create(&dir); + if (result) { ErrorHandler_LogError_Path(result, "creating directory", &dir); } + return result == 0; +} + void Utils_UNSAFE_GetFilename(STRING_TRANSIENT String* str) { Int32 i; for (i = str->length - 1; i >= 0; i--) { diff --git a/src/Client/Utils.h b/src/Client/Utils.h index cb615f133..dee8ef41f 100644 --- a/src/Client/Utils.h +++ b/src/Client/Utils.h @@ -27,6 +27,7 @@ UInt32 Utils_ParseEnum(STRING_PURE String* text, UInt32 defValue, const UChar** bool Utils_IsValidInputChar(UChar c, bool supportsCP437); bool Utils_IsUrlPrefix(STRING_PURE String* value, Int32 index); +bool Utils_EnsureDirectory(STRING_PURE const UChar* dirName); void Utils_UNSAFE_GetFilename(STRING_TRANSIENT String* str); Int32 Utils_AccumulateWheelDelta(Real32* accmulator, Real32 delta); #define Utils_AdjViewDist(value) ((Int32)(1.4142135f * (value)))