From ca000b317ca55d6f187f846955abcc40b258b74a Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 27 Apr 2018 09:23:46 +1000 Subject: [PATCH] Multiplayer of C client connects (Although pretty much doing anything causes a crash) --- src/Client/Animations.c | 2 +- src/Client/Bitmap.c | 4 +- src/Client/BlockPhysics.c | 2 +- src/Client/BordersRenderer.c | 4 +- src/Client/Builder.c | 2 +- src/Client/ChunkUpdater.c | 12 +- src/Client/D3D9Api.c | 3 +- src/Client/Entity.h | 1 + src/Client/EnvRenderer.c | 6 +- src/Client/Formats.c | 6 +- src/Client/Game.c | 10 +- src/Client/GameMode.c | 4 +- src/Client/Gui.c | 15 +- src/Client/Gui.h | 7 +- src/Client/InputHandler.c | 4 +- src/Client/Lighting.c | 3 +- src/Client/MapGenerator.c | 4 +- src/Client/Menus.c | 58 +-- src/Client/OpenGLApi.c | 3 +- src/Client/PacketHandlers.c | 818 +++++++++++++++++----------------- src/Client/PacketHandlers.h | 4 +- src/Client/Physics.c | 2 +- src/Client/Platform.h | 5 +- src/Client/Program.c | 7 +- src/Client/Screens.c | 12 +- src/Client/Screens.h | 3 +- src/Client/SelectionBox.c | 8 +- src/Client/ServerConnection.c | 91 ++-- src/Client/String.c | 6 +- src/Client/Vectors.c | 2 +- src/Client/WeatherRenderer.c | 2 +- src/Client/WinPlatform.c | 26 +- 32 files changed, 601 insertions(+), 535 deletions(-) diff --git a/src/Client/Animations.c b/src/Client/Animations.c index ba70f5408..3fb0fde0a 100644 --- a/src/Client/Animations.c +++ b/src/Client/Animations.c @@ -195,7 +195,7 @@ void Animations_Draw(AnimationData* data, Int32 texId, Int32 size) { UInt8* ptr = buffer; if (size > ANIMS_FAST_SIZE) { /* cannot allocate memory on the stack for very big animation.png frames */ - ptr = Platform_MemAlloc(Bitmap_DataSize(size, size)); + ptr = Platform_MemAlloc(size * size, BITMAP_SIZEOF_PIXEL); if (ptr == NULL) ErrorHandler_Fail("Failed to allocate memory for anim frame"); } diff --git a/src/Client/Bitmap.c b/src/Client/Bitmap.c index eb1df8a20..a98799be5 100644 --- a/src/Client/Bitmap.c +++ b/src/Client/Bitmap.c @@ -25,7 +25,7 @@ void Bitmap_CopyBlock(Int32 srcX, Int32 srcY, Int32 dstX, Int32 dstY, Bitmap* sr void Bitmap_Allocate(Bitmap* bmp, Int32 width, Int32 height) { bmp->Width = width; bmp->Height = height; bmp->Stride = width * BITMAP_SIZEOF_PIXEL; - bmp->Scan0 = Platform_MemAlloc(Bitmap_DataSize(width, height)); + bmp->Scan0 = Platform_MemAlloc(width * height, BITMAP_SIZEOF_PIXEL); if (bmp->Scan0 == NULL) { ErrorHandler_Fail("Bitmap - failed to allocate memory"); @@ -324,7 +324,7 @@ void Bitmap_DecodePng(Bitmap* bmp, Stream* stream) { if (bmp->Height < 0 || bmp->Height > PNG_MAX_DIMS) ErrorHandler_Fail("PNG image too tall"); bmp->Stride = bmp->Width * BITMAP_SIZEOF_PIXEL; - bmp->Scan0 = Platform_MemAlloc(Bitmap_DataSize(bmp->Width, bmp->Height)); + bmp->Scan0 = Platform_MemAlloc(bmp->Width * bmp->Height, BITMAP_SIZEOF_PIXEL); if (bmp->Scan0 == NULL) ErrorHandler_Fail("Failed to allocate memory for PNG bitmap"); bitsPerSample = Stream_ReadU8(stream); diff --git a/src/Client/BlockPhysics.c b/src/Client/BlockPhysics.c index fc1789f13..dc8f7931e 100644 --- a/src/Client/BlockPhysics.c +++ b/src/Client/BlockPhysics.c @@ -46,7 +46,7 @@ void TickQueue_Resize(TickQueue* queue) { UInt32 capacity = queue->BufferSize * 2; if (capacity < 32) capacity = 32; - UInt32* newBuffer = Platform_MemAlloc(capacity * sizeof(UInt32)); + UInt32* newBuffer = Platform_MemAlloc(capacity, sizeof(UInt32)); if (newBuffer == NULL) { ErrorHandler_Fail("TickQueue - failed to allocate memory"); } diff --git a/src/Client/BordersRenderer.c b/src/Client/BordersRenderer.c index 28e8d6f1a..305246511 100644 --- a/src/Client/BordersRenderer.c +++ b/src/Client/BordersRenderer.c @@ -180,7 +180,7 @@ void BordersRenderer_RebuildSides(Int32 y, Int32 axisSize) { VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b* ptr = v; if (borders_sidesVertices > 4096) { - ptr = Platform_MemAlloc(borders_sidesVertices * sizeof(VertexP3fT2fC4b)); + ptr = Platform_MemAlloc(borders_sidesVertices, sizeof(VertexP3fT2fC4b)); if (ptr == NULL) ErrorHandler_Fail("BordersRenderer_Sides - failed to allocate memory"); } VertexP3fT2fC4b* temp = ptr; @@ -223,7 +223,7 @@ void BordersRenderer_RebuildEdges(Int32 y, Int32 axisSize) { VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b* ptr = v; if (borders_edgesVertices > 4096) { - ptr = Platform_MemAlloc(borders_edgesVertices * sizeof(VertexP3fT2fC4b)); + ptr = Platform_MemAlloc(borders_edgesVertices, sizeof(VertexP3fT2fC4b)); if (ptr == NULL) ErrorHandler_Fail("BordersRenderer_Edges - failed to allocate memory"); } VertexP3fT2fC4b* temp = ptr; diff --git a/src/Client/Builder.c b/src/Client/Builder.c index 4e6de473b..4878e206c 100644 --- a/src/Client/Builder.c +++ b/src/Client/Builder.c @@ -63,7 +63,7 @@ void Builder1DPart_Prepare(Builder1DPart* part) { if (vCount > part->verticesBufferCount) { Platform_MemFree(&part->vertices); - part->vertices = Platform_MemAlloc((vCount + 2) * sizeof(VertexP3fT2fC4b)); + part->vertices = Platform_MemAlloc(vCount + 2, sizeof(VertexP3fT2fC4b)); part->verticesBufferCount = vCount; if (part->vertices == NULL) { ErrorHandler_Fail("Builder1DPart_Prepare - failed to allocate memory"); diff --git a/src/Client/ChunkUpdater.c b/src/Client/ChunkUpdater.c index 4e0ac7a78..0004996b6 100644 --- a/src/Client/ChunkUpdater.c +++ b/src/Client/ChunkUpdater.c @@ -125,23 +125,23 @@ void ChunkUpdater_FreeAllocations(void) { } void ChunkUpdater_PerformAllocations(void) { - MapRenderer_Chunks = Platform_MemAlloc(MapRenderer_ChunksCount * sizeof(ChunkInfo)); + MapRenderer_Chunks = Platform_MemAlloc(MapRenderer_ChunksCount, sizeof(ChunkInfo)); if (MapRenderer_Chunks == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate chunk info"); - MapRenderer_SortedChunks = Platform_MemAlloc(MapRenderer_ChunksCount * sizeof(ChunkInfo*)); + MapRenderer_SortedChunks = Platform_MemAlloc(MapRenderer_ChunksCount, sizeof(ChunkInfo*)); if (MapRenderer_Chunks == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate sorted chunk info"); - MapRenderer_RenderChunks = Platform_MemAlloc(MapRenderer_ChunksCount * sizeof(ChunkInfo*)); + MapRenderer_RenderChunks = Platform_MemAlloc(MapRenderer_ChunksCount, sizeof(ChunkInfo*)); if (MapRenderer_RenderChunks == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate render chunk info"); - ChunkUpdater_Distances = Platform_MemAlloc(MapRenderer_ChunksCount * sizeof(Int32)); + ChunkUpdater_Distances = Platform_MemAlloc(MapRenderer_ChunksCount, sizeof(Int32)); if (ChunkUpdater_Distances == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate chunk distances"); UInt32 partsCount = MapRenderer_ChunksCount * MapRenderer_1DUsedCount; - UInt32 partsSize = (partsCount * (UInt32)sizeof(ChunkPartInfo)) * 2; - MapRenderer_PartsBuffer_Raw = Platform_MemAlloc(partsSize); + MapRenderer_PartsBuffer_Raw = Platform_MemAlloc(partsCount * 2, sizeof(ChunkPartInfo)); if (MapRenderer_PartsBuffer_Raw == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate chunk parts buffer"); + UInt32 partsSize = partsCount * 2 * (UInt32)sizeof(ChunkPartInfo); Platform_MemSet(MapRenderer_PartsBuffer_Raw, 0, partsSize); MapRenderer_PartsNormal = MapRenderer_PartsBuffer_Raw; MapRenderer_PartsTranslucent = MapRenderer_PartsBuffer_Raw + partsCount; diff --git a/src/Client/D3D9Api.c b/src/Client/D3D9Api.c index 64ae1a00d..1d628c244 100644 --- a/src/Client/D3D9Api.c +++ b/src/Client/D3D9Api.c @@ -205,9 +205,8 @@ void D3D9_DoMipmaps(IDirect3DTexture9* texture, Int32 x, Int32 y, Bitmap* bmp, b x /= 2; y /= 2; if (width > 1) width /= 2; if (height > 1) height /= 2; - UInt32 size = Bitmap_DataSize(width, height); - UInt8* cur = Platform_MemAlloc(size); + UInt8* cur = Platform_MemAlloc(width * height, BITMAP_SIZEOF_PIXEL); if (cur == NULL) ErrorHandler_Fail("Allocating memory for mipmaps"); GfxCommon_GenMipmaps(width, height, cur, prev); diff --git a/src/Client/Entity.h b/src/Client/Entity.h index 68fa9d8e7..f16727770 100644 --- a/src/Client/Entity.h +++ b/src/Client/Entity.h @@ -142,6 +142,7 @@ typedef struct NetPlayer_ { bool ShouldRender; } NetPlayer; void NetPlayer_Init(NetPlayer* player, STRING_PURE String* displayName, STRING_PURE String* skinName); +NetPlayer NetPlayers_List[ENTITIES_SELF_ID]; /* Represents the user/player's own entity. */ typedef struct LocalPlayer_ { diff --git a/src/Client/EnvRenderer.c b/src/Client/EnvRenderer.c index c93576256..493561891 100644 --- a/src/Client/EnvRenderer.c +++ b/src/Client/EnvRenderer.c @@ -138,7 +138,7 @@ void EnvRenderer_UpdateFog(void) { Gfx_SetFogDensity((Real32)density); } else { Gfx_SetFogMode(FOG_LINEAR); - Gfx_SetFogEnd(Game_ViewDistance); + Gfx_SetFogEnd((Real32)Game_ViewDistance); } Gfx_ClearColour(fogCol); Gfx_SetFogColour(fogCol); @@ -214,7 +214,7 @@ void EnvRenderer_RebuildClouds(Int32 extent, Int32 axisSize) { VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b* ptr = v; if (env_cloudVertices > 4096) { - ptr = Platform_MemAlloc(env_cloudVertices * sizeof(VertexP3fT2fC4b)); + ptr = Platform_MemAlloc(env_cloudVertices, sizeof(VertexP3fT2fC4b)); if (ptr == NULL) ErrorHandler_Fail("EnvRenderer_Clouds - failed to allocate memory"); } @@ -233,7 +233,7 @@ void EnvRenderer_RebuildSky(Int32 extent, Int32 axisSize) { VertexP3fC4b v[4096]; VertexP3fC4b* ptr = v; if (env_skyVertices > 4096) { - ptr = Platform_MemAlloc(env_skyVertices * sizeof(VertexP3fC4b)); + ptr = Platform_MemAlloc(env_skyVertices, sizeof(VertexP3fC4b)); if (ptr == NULL) ErrorHandler_Fail("EnvRenderer_Sky - failed to allocate memory"); } diff --git a/src/Client/Formats.c b/src/Client/Formats.c index 2acd37d46..0cb96035b 100644 --- a/src/Client/Formats.c +++ b/src/Client/Formats.c @@ -12,7 +12,7 @@ void Map_ReadBlocks(Stream* stream) { World_BlocksSize = World_Width * World_Length * World_Height; - World_Blocks = Platform_MemAlloc(World_BlocksSize); + World_Blocks = Platform_MemAlloc(World_BlocksSize, sizeof(BlockID)); if (World_Blocks == NULL) { ErrorHandler_Fail("Failed to allocate memory for reading blocks array from file"); } @@ -326,7 +326,7 @@ void Nbt_ReadTag(UInt8 typeId, bool readTagName, Stream* stream, NbtTag* parent, if (count < NBT_SMALL_SIZE) { Stream_Read(stream, tag.DataSmall, count); } else { - tag.DataBig = Platform_MemAlloc(count); + tag.DataBig = Platform_MemAlloc(count, sizeof(UInt8)); if (tag.DataBig == NULL) ErrorHandler_Fail("Nbt_ReadTag - allocating memory"); Stream_Read(stream, tag.DataBig, count); } @@ -396,7 +396,7 @@ bool Cw_Callback_1(NbtTag* tag) { if (IsTag(tag, "BlockArray")) { World_BlocksSize = tag->DataSize; if (tag->DataSize < NBT_SMALL_SIZE) { - World_Blocks = Platform_MemAlloc(World_BlocksSize); + World_Blocks = Platform_MemAlloc(World_BlocksSize, sizeof(UInt8)); if (World_Blocks == NULL) ErrorHandler_Fail("Failed to allocate memory for map"); Platform_MemCpy(World_Blocks, tag->DataSmall, tag->DataSize); } else { diff --git a/src/Client/Game.c b/src/Client/Game.c index 47af52101..2a4983471 100644 --- a/src/Client/Game.c +++ b/src/Client/Game.c @@ -173,7 +173,8 @@ void Game_UpdateProjection(void) { void Game_Disconnect(STRING_PURE String* title, STRING_PURE String* reason) { World_Reset(); Event_RaiseVoid(&WorldEvents_NewMap); - Gui_SetNewScreen(DisconnectScreen_MakeInstance(title, reason)); + Gui_FreeActive(); + Gui_SetActive(DisconnectScreen_MakeInstance(title, reason)); Drawer2D_Init(); Block_Reset(); @@ -530,7 +531,8 @@ void Game_Load(void) { String_Format2(&loadTitle, "Connecting to %s:%i..", &Game_IPAddress, &Game_Port); String loadMsg = String_MakeNull(); - Gui_SetNewScreen(LoadingScreen_MakeInstance(&loadTitle, &loadMsg)); + Gui_FreeActive(); + Gui_SetActive(LoadingScreen_MakeInstance(&loadTitle, &loadMsg)); ServerConnection_Connect(&Game_IPAddress, Game_Port); } @@ -672,7 +674,8 @@ void Game_RenderFrame(Real64 delta) { Camera_Active->UpdateMouse(); if (!Window_GetFocused() && !Gui_GetActiveScreen()->HandlesAllInput) { - Gui_SetNewScreen(PauseScreen_MakeInstance()); + Gui_FreeActive(); + Gui_SetActive(PauseScreen_MakeInstance()); } bool allowZoom = Gui_Active == NULL && !Gui_HUD->HandlesAllInput; @@ -779,7 +782,6 @@ void Cw_Save(Stream* stream) { } void Dat_Load(Stream* stream) { } void Schematic_Save(Stream* stream) { } void Gfx_MakeApiInfo(void) { } -void ServerConnection_InitMultiplayer(void) { } bool Convert_TryParseInt64(STRING_PURE String* str, Int64* value) { return true; } DateTime DateTime_FromTotalMs(Int64 ms) { DateTime time; return time; } Screen* UrlWarningOverlay_MakeInstance(STRING_PURE String* url) { return NULL; } diff --git a/src/Client/GameMode.c b/src/Client/GameMode.c index 28f661765..53943ce49 100644 --- a/src/Client/GameMode.c +++ b/src/Client/GameMode.c @@ -23,8 +23,8 @@ IGameComponent GameMode_MakeComponent(void) { bool GameMode_HandlesKeyDown(Key key) { Screen* activeScreen = Gui_GetActiveScreen(); if (key == KeyBind_Get(KeyBind_Inventory) && activeScreen == Gui_HUD) { - Screen* screen = InventoryScreen_MakeInstance(); - Gui_SetNewScreen(screen); + Gui_FreeActive(); + Gui_SetActive(InventoryScreen_MakeInstance()); return true; } else if (key == KeyBind_Get(KeyBind_DropBlock) && !Game_ClassicMode) { if (Inventory_CanChangeSelected() && Inventory_SelectedBlock != BLOCK_AIR) { diff --git a/src/Client/Gui.c b/src/Client/Gui.c index 5aedff8e6..b6ae7a50e 100644 --- a/src/Client/Gui.c +++ b/src/Client/Gui.c @@ -112,7 +112,7 @@ void Gui_Reset(void) { void Gui_Free(void) { Event_UnregisterStream(&TextureEvents_FileChanged, NULL, Gui_FileChanged); - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); Elem_TryFree(Gui_Status); if (Gui_Active != NULL) { Elem_TryFree(Gui_Active); } @@ -138,9 +138,16 @@ Screen* Gui_GetUnderlyingScreen(void) { return Gui_Active == NULL ? Gui_HUD : Gui_Active; } -void Gui_SetScreen(Screen* screen, bool freeOld) { +void Gui_ReplaceActive(Screen* screen) { + Gui_FreeActive(); + Gui_SetActive(screen); +} +void Gui_FreeActive(void) { + if (Gui_Active != NULL) { Elem_TryFree(Gui_Active); } +} + +void Gui_SetActive(Screen* screen) { InputHandler_ScreenChanged(Gui_Active, screen); - if (Gui_Active != NULL && freeOld) { Elem_TryFree(Gui_Active); } if (screen == NULL) { Game_SetCursorVisible(false); @@ -152,8 +159,6 @@ void Gui_SetScreen(Screen* screen, bool freeOld) { if (screen != NULL) { Elem_Init(screen); } Gui_Active = screen; } - -void Gui_SetNewScreen(Screen* screen) { Gui_SetScreen(screen, true); } void Gui_RefreshHud(void) { Elem_Recreate(Gui_HUD); } void Gui_ShowOverlay_Impl(Screen* overlay, bool atFront) { diff --git a/src/Client/Gui.h b/src/Client/Gui.h index 69b7b8dab..b36f1ab32 100644 --- a/src/Client/Gui.h +++ b/src/Client/Gui.h @@ -77,8 +77,11 @@ Screen* Gui_GetActiveScreen(void); /* Gets the non-overlay screen that the user is currently interacting with. This means if an overlay is active, it will return the screen under it. */ Screen* Gui_GetUnderlyingScreen(void); -void Gui_SetScreen(Screen* screen, bool freeOld); -void Gui_SetNewScreen(Screen* screen); + +void Gui_ReplaceActive(Screen* screen); +void Gui_FreeActive(void); +/* This doesn't free old active screen - you probably want Gui_ReplaceActive */ +void Gui_SetActive(Screen* screen); void Gui_RefreshHud(void); void Gui_ShowOverlay(Screen* overlay, bool atFront); void Gui_RenderGui(Real64 delta); diff --git a/src/Client/InputHandler.c b/src/Client/InputHandler.c index 2d2dcb72c..e6bb80027 100644 --- a/src/Client/InputHandler.c +++ b/src/Client/InputHandler.c @@ -174,8 +174,8 @@ bool InputHandler_HandleCoreKey(Key key) { InputHandler_CycleDistanceForwards(viewDists, count); } } else if ((key == KeyBind_Get(KeyBind_PauseOrExit) || key == Key_Pause) && World_Blocks != NULL) { - Screen* screen = PauseScreen_MakeInstance(); - Gui_SetNewScreen(screen); + Gui_FreeActive(); + Gui_SetActive(PauseScreen_MakeInstance()); } else if (GameMode_HandlesKeyDown(key)) { } else if (key == KeyBind_Get(KeyBind_IDOverlay)) { if (Gui_OverlaysCount > 0) return true; diff --git a/src/Client/Lighting.c b/src/Client/Lighting.c index c8ac6d4f8..38db87197 100644 --- a/src/Client/Lighting.c +++ b/src/Client/Lighting.c @@ -331,8 +331,7 @@ void Lighting_OnNewMap(void) { } void Lighting_OnNewMapLoaded(void) { - UInt32 size = World_Width * World_Length * sizeof(Int16); - Lighting_heightmap = Platform_MemAlloc(size); + Lighting_heightmap = Platform_MemAlloc(World_Width * World_Length, sizeof(Int16)); if (Lighting_heightmap == NULL) { ErrorHandler_Fail("WorldLighting - failed to allocate heightmap"); } diff --git a/src/Client/MapGenerator.c b/src/Client/MapGenerator.c index 2e4c0bc1d..b206e0331 100644 --- a/src/Client/MapGenerator.c +++ b/src/Client/MapGenerator.c @@ -17,7 +17,7 @@ void Gen_Init(void) { Gen_CurrentProgress = 0.0f; Gen_CurrentState = ""; - Gen_Blocks = Platform_MemAlloc(Gen_Width * Gen_Height * Gen_Length * sizeof(BlockID)); + Gen_Blocks = Platform_MemAlloc(Gen_Width * Gen_Height * Gen_Length, sizeof(BlockID)); if (Gen_Blocks == NULL) { ErrorHandler_Fail("MapGen - failed to allocate Blocks array"); } @@ -465,7 +465,7 @@ void NotchyGen_PlantTrees(void) { void NotchyGen_Generate(void) { Gen_Init(); - Heightmap = Platform_MemAlloc(Gen_Width * Gen_Length * sizeof(Int16)); + Heightmap = Platform_MemAlloc(Gen_Width * Gen_Length, sizeof(Int16)); if (Heightmap == NULL) { ErrorHandler_Fail("NotchyGen - Failed to allocate Heightmap array"); } diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 68d88f4e5..ed7cebb0f 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -242,30 +242,30 @@ Int32 Menu_Int32(STRING_PURE String* v) { Int32 value; Convert_TryParseInt32(v, Real32 Menu_Real32(STRING_PURE String* v) { Real32 value; Convert_TryParseReal32(v, &value); return value; } PackedCol Menu_HexCol(STRING_PURE String* v) { PackedCol value; PackedCol_TryParseHex(v, &value); return value; } -void Menu_SwitchOptions(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(OptionsGroupScreen_MakeInstance()); } -void Menu_SwitchPause(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(PauseScreen_MakeInstance()); } -void Menu_SwitchClassicOptions(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicOptionsScreen_MakeInstance()); } +void Menu_SwitchOptions(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(OptionsGroupScreen_MakeInstance()); } +void Menu_SwitchPause(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(PauseScreen_MakeInstance()); } +void Menu_SwitchClassicOptions(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicOptionsScreen_MakeInstance()); } -void Menu_SwitchKeysClassic(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchKeysClassicHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicHacksKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchKeysNormal(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(NormalKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchKeysHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HacksKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchKeysOther(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(OtherKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchKeysMouse(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(MouseKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysClassic(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysClassicHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicHacksKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysNormal(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(NormalKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(HacksKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysOther(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(OtherKeyBindingsScreen_MakeInstance()); } +void Menu_SwitchKeysMouse(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(MouseKeyBindingsScreen_MakeInstance()); } -void Menu_SwitchMisc(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(MiscOptionsScreen_MakeInstance()); } -void Menu_SwitchGui(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(GuiOptionsScreen_MakeInstance()); } -void Menu_SwitchGfx(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(GraphicsOptionsScreen_MakeInstance()); } -void Menu_SwitchHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HacksSettingsScreen_MakeInstance()); } -void Menu_SwitchEnv(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(EnvSettingsScreen_MakeInstance()); } -void Menu_SwitchNostalgia(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(NostalgiaScreen_MakeInstance()); } +void Menu_SwitchMisc(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(MiscOptionsScreen_MakeInstance()); } +void Menu_SwitchGui(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GuiOptionsScreen_MakeInstance()); } +void Menu_SwitchGfx(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GraphicsOptionsScreen_MakeInstance()); } +void Menu_SwitchHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(HacksSettingsScreen_MakeInstance()); } +void Menu_SwitchEnv(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(EnvSettingsScreen_MakeInstance()); } +void Menu_SwitchNostalgia(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(NostalgiaScreen_MakeInstance()); } -void Menu_SwitchGenLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(GenLevelScreen_MakeInstance()); } -void Menu_SwitchClassicGenLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicGenScreen_MakeInstance()); } -void Menu_SwitchLoadLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(LoadLevelScreen_MakeInstance()); } -void Menu_SwitchSaveLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(SaveLevelScreen_MakeInstance()); } -void Menu_SwitchTexPacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(TexturePackScreen_MakeInstance()); } -void Menu_SwitchHotkeys(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HotkeyListScreen_MakeInstance()); } +void Menu_SwitchGenLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GenLevelScreen_MakeInstance()); } +void Menu_SwitchClassicGenLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicGenScreen_MakeInstance()); } +void Menu_SwitchLoadLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(LoadLevelScreen_MakeInstance()); } +void Menu_SwitchSaveLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(SaveLevelScreen_MakeInstance()); } +void Menu_SwitchTexPacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(TexturePackScreen_MakeInstance()); } +void Menu_SwitchHotkeys(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(HotkeyListScreen_MakeInstance()); } /*########################################################################################################################* @@ -408,7 +408,7 @@ void ListScreen_Free(GuiElement* elem) { bool ListScreen_HandlesKeyDown(GuiElement* elem, Key key) { ListScreen* screen = (ListScreen*)elem; if (key == Key_Escape) { - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); } else if (key == Key_Left) { ListScreen_PageClick(screen, false); } else if (key == Key_Right) { @@ -485,7 +485,7 @@ bool MenuScreen_HandlesMouseUp(GuiElement* elem, Int32 x, Int32 y, MouseButton b bool MenuScreen_HandlesMouseScroll(GuiElement* elem, Real32 delta) { return true; } bool MenuScreen_HandlesKeyDown(GuiElement* elem, Key key) { - if (key == Key_Escape) { Gui_SetNewScreen(NULL); } + if (key == Key_Escape) { Gui_ReplaceActive(NULL); } return key < Key_F1 || key > Key_F35; } bool MenuScreen_HandlesKeyPress(GuiElement* elem, UInt8 key) { return true; } @@ -596,7 +596,7 @@ void PauseScreen_MakeClassic(PauseScreen* screen, Int32 i, Int32 y, const UInt8* } void PauseScreen_Quit(GuiElement* a, GuiElement* b) { Window_Close(); } -void PauseScreen_Game(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(NULL); } +void PauseScreen_Game(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(NULL); } void PauseScreen_CheckHacksAllowed(void* obj) { if (Game_UseClassicOptions) return; @@ -913,7 +913,7 @@ void EditHotkeyScreen_SaveChanges(GuiElement* elem, GuiElement* widget) { Hotkeys_Add(hotkey.BaseKey, hotkey.Flags, &text, hotkey.StaysOpen); Hotkeys_UserAddedHotkey(hotkey.BaseKey, hotkey.Flags, hotkey.StaysOpen, &text); } - Gui_SetNewScreen(HotkeyListScreen_MakeInstance()); + Gui_ReplaceActive(HotkeyListScreen_MakeInstance()); } void EditHotkeyScreen_RemoveHotkey(GuiElement* elem, GuiElement* widget) { @@ -923,7 +923,7 @@ void EditHotkeyScreen_RemoveHotkey(GuiElement* elem, GuiElement* widget) { Hotkeys_Remove(hotkey.BaseKey, hotkey.Flags); Hotkeys_UserRemovedHotkey(hotkey.BaseKey, hotkey.Flags); } - Gui_SetNewScreen(HotkeyListScreen_MakeInstance()); + Gui_ReplaceActive(HotkeyListScreen_MakeInstance()); } void EditHotkeyScreen_Init(GuiElement* elem) { @@ -1351,7 +1351,7 @@ void SaveLevelScreen_Render(GuiElement* elem, Real64 delta) { String_Format1(&msg, "&eSaved map to: %s", &path); Chat_Add(&msg); - Gui_SetNewScreen(PauseScreen_MakeInstance()); + Gui_ReplaceActive(PauseScreen_MakeInstance()); String_Clear(&path); } @@ -1479,7 +1479,7 @@ void HotkeyListScreen_EntryClick(GuiElement* screenElem, GuiElement* w) { HotkeyData original = { 0 }; if (String_CaselessEqualsConst(&text, LIST_SCREEN_EMPTY)) { - Gui_SetNewScreen(EditHotkeyScreen_MakeInstance(original)); return; + Gui_ReplaceActive(EditHotkeyScreen_MakeInstance(original)); return; } Int32 sepIndex = String_IndexOf(&text, '|', 0); @@ -1501,7 +1501,7 @@ void HotkeyListScreen_EntryClick(GuiElement* screenElem, GuiElement* w) { HotkeyData h = HotkeysList[i]; if (h.BaseKey == baseKey && h.Flags == flags) { original = h; break; } } - Gui_SetNewScreen(EditHotkeyScreen_MakeInstance(original)); + Gui_ReplaceActive(EditHotkeyScreen_MakeInstance(original)); } Screen* HotkeyListScreen_MakeInstance(void) { diff --git a/src/Client/OpenGLApi.c b/src/Client/OpenGLApi.c index 945b48c0e..c83fdf71e 100644 --- a/src/Client/OpenGLApi.c +++ b/src/Client/OpenGLApi.c @@ -107,9 +107,8 @@ void GL_DoMipmaps(GfxResourceID texId, Int32 x, Int32 y, Bitmap* bmp, bool parti x /= 2; y /= 2; if (width > 1) width /= 2; if (height > 1) height /= 2; - UInt32 size = Bitmap_DataSize(width, height); - UInt8* cur = Platform_MemAlloc(size); + UInt8* cur = Platform_MemAlloc(width * height, BITMAP_SIZEOF_PIXEL); if (cur == NULL) ErrorHandler_Fail("Allocating memory for mipmaps"); GfxCommon_GenMipmaps(width, height, cur, prev); diff --git a/src/Client/PacketHandlers.c b/src/Client/PacketHandlers.c index f8569099e..7f73603cd 100644 --- a/src/Client/PacketHandlers.c +++ b/src/Client/PacketHandlers.c @@ -20,6 +20,7 @@ #include "AsyncDownloader.h" #include "Drawer2D.h" #include "ErrorHandler.h" +#include "TexturePack.h" /*########################################################################################################################* *-----------------------------------------------------Common handlers-----------------------------------------------------* @@ -68,73 +69,6 @@ void Handlers_RemoveEndPlus(STRING_TRANSIENT String* value) { String_DeleteAt(value, value->length - 1); } -void Handlers_CheckName(EntityID id, STRING_TRANSIENT String* displayName, STRING_TRANSIENT String* skinName) { - String_StripCols(&skinName); - Handlers_RemoveEndPlus(displayName); - Handlers_RemoveEndPlus(skinName); - /* Server is only allowed to change our own name colours. */ - if (id != ENTITIES_SELF_ID) return; - - UInt8 nameNoColsBuffer[String_BufferSize(STRING_SIZE)]; - String nameNoCols = String_InitAndClearArray(nameNoColsBuffer); - String_AppendColorless(&nameNoCols, displayName); - - if (!String_Equals(&nameNoCols, &Game_Username)) { String_Set(displayName, &Game_Username); } - if (skinName->length == 0) { String_Set(skinName, &Game_Username); } -} - -void Handlers_AddEntity(EntityID id, STRING_TRANSIENT String* displayName, STRING_TRANSIENT String* skinName, bool readPosition) { - LocalPlayer* p = &LocalPlayer_Instance; - if (id != ENTITIES_SELF_ID) { - Entity* oldEntity = Entities_List[id]; - if (oldEntity != NULL) Entities_Remove(id); - - game.Entities.List[id] = new NetPlayer(displayName, skinName, game); - Event_RaiseInt(&EntityEvents_Added, id); - } else { - p->Base.VTABLE->Despawn(&p->Base); - /* Always reset the texture here, in case other network players are using the same skin as us */ - /* In that case, we don't want the fetching of new skin for us to delete the texture used by them */ - Player_ResetSkin((Player*)p); - p->FetchedSkin = false; - - String player_name = String_InitAndClearArray(p->DisplayNameRaw); - String_Set(&player_name, displayName); - String player_skin = String_InitAndClearArray(p->SkinNameRaw); - String_Set(&player_skin, skinName); - Player_UpdateName((Player*)p); - } - - if (!readPosition) return; - Stream* stream = ServerConnection_ReadStream(); - Classic_ReadAbsoluteLocation(stream, id, false); - if (id != ENTITIES_SELF_ID) return; - - p->Spawn = p->Base.Position; - p->SpawnRotY = p->Base.HeadY; - p->SpawnHeadX = p->Base.HeadX; -} - -void Handlers_RemoveEntity(EntityID id) { - Entity* entity = Entities_List[id]; - if (entity == NULL) return; - if (id != ENTITIES_SELF_ID) Entities_Remove(id); - - /* See comment about some servers in Classic_AddEntity */ - Int32 mask = id >> 3, bit = 1 << (id & 0x7); - if (!addEntityHack || (needRemoveNames[mask] & bit) == 0) return; - - Handlers_RemoveTablistEntry(id); - needRemoveNames[mask] &= (UInt8)~bit; -} - -void Handlers_UpdateLocation(EntityID playerId, LocationUpdate* update, bool interpolate) { - Entity* entity = Entities_List[playerId]; - if (entity != NULL) { - entity->VTABLE->SetLocation(entity, update, interpolate); - } -} - void Handlers_AddTablistEntry(EntityID id, STRING_PURE String* playerName, STRING_PURE String* listName, STRING_PURE String* groupName, UInt8 groupRank) { /* Only redraw the tab list if something changed. */ if (TabList_Valid(id)) { @@ -160,6 +94,76 @@ void Handlers_RemoveTablistEntry(EntityID id) { TabList_Remove(id); } +void Handlers_CheckName(EntityID id, STRING_TRANSIENT String* displayName, STRING_TRANSIENT String* skinName) { + String_StripCols(skinName); + Handlers_RemoveEndPlus(displayName); + Handlers_RemoveEndPlus(skinName); + /* Server is only allowed to change our own name colours. */ + if (id != ENTITIES_SELF_ID) return; + + UInt8 nameNoColsBuffer[String_BufferSize(STRING_SIZE)]; + String nameNoCols = String_InitAndClearArray(nameNoColsBuffer); + String_AppendColorless(&nameNoCols, displayName); + + if (!String_Equals(&nameNoCols, &Game_Username)) { String_Set(displayName, &Game_Username); } + if (skinName->length == 0) { String_Set(skinName, &Game_Username); } +} + +void Classic_ReadAbsoluteLocation(Stream* stream, EntityID id, bool interpolate); +void Handlers_AddEntity(EntityID id, STRING_TRANSIENT String* displayName, STRING_TRANSIENT String* skinName, bool readPosition) { + LocalPlayer* p = &LocalPlayer_Instance; + if (id != ENTITIES_SELF_ID) { + Entity* oldEntity = Entities_List[id]; + if (oldEntity != NULL) Entities_Remove(id); + + NetPlayer* player = &NetPlayers_List[id]; + NetPlayer_Init(player, displayName, skinName); + Entities_List[id] = &player->Base; + Event_RaiseInt(&EntityEvents_Added, id); + } else { + p->Base.VTABLE->Despawn(&p->Base); + /* Always reset the texture here, in case other network players are using the same skin as us */ + /* In that case, we don't want the fetching of new skin for us to delete the texture used by them */ + Player_ResetSkin((Player*)p); + p->FetchedSkin = false; + + String player_name = String_InitAndClearArray(p->DisplayNameRaw); + String_Set(&player_name, displayName); + String player_skin = String_InitAndClearArray(p->SkinNameRaw); + String_Set(&player_skin, skinName); + Player_UpdateName((Player*)p); + } + + if (!readPosition) return; + Stream* stream = ServerConnection_ReadStream(); + Classic_ReadAbsoluteLocation(stream, id, false); + if (id != ENTITIES_SELF_ID) return; + + p->Spawn = p->Base.Position; + p->SpawnRotY = p->Base.HeadY; + p->SpawnHeadX = p->Base.HeadX; +} + +void Handlers_RemoveEntity(EntityID id) { + Entity* entity = Entities_List[id]; + if (entity == NULL) return; + if (id != ENTITIES_SELF_ID) Entities_Remove(id); + + /* See comment about some servers in Classic_AddEntity */ + Int32 mask = id >> 3, bit = 1 << (id & 0x7); + if (!addEntityHack || (needRemoveNames[mask] & bit) == 0) return; + + Handlers_RemoveTablistEntry(id); + needRemoveNames[mask] &= (UInt8)~bit; +} + +void Handlers_UpdateLocation(EntityID playerId, LocationUpdate* update, bool interpolate) { + Entity* entity = Entities_List[playerId]; + if (entity != NULL) { + entity->VTABLE->SetLocation(entity, update, interpolate); + } +} + void Handlers_DisableAddEntityHack(void) { if (!addEntityHack) return; addEntityHack = false; @@ -169,30 +173,146 @@ void Handlers_DisableAddEntityHack(void) { Int32 mask = id >> 3, bit = 1 << (id & 0x7); if (!(needRemoveNames[mask] & bit)) continue; - RemoveTablistEntry((EntityID)id); + Handlers_RemoveTablistEntry((EntityID)id); needRemoveNames[mask] &= (UInt8)~bit; } } -void Handlers_Reset(void) { - addEntityHack = true; - Classic_Reset(); - CPE_Reset(); - BlockDefs_Reset(); - WoM_Reset(); + +/*########################################################################################################################* +*------------------------------------------------------WoM protocol-------------------------------------------------------* +*#########################################################################################################################*/ +/* Partially based on information from http://files.worldofminecraft.com/texturing/ */ +/* NOTE: http://files.worldofminecraft.com/ has been down for quite a while, so support was removed on Oct 10, 2015 */ + +UInt8 wom_identifierBuffer[String_BufferSize(STRING_SIZE)]; +String wom_identifier = String_FromEmptyArray(wom_identifierBuffer); +Int32 wom_counter; +bool wom_sendId, wom_sentId; + +void WoM_UpdateIdentifier(void) { + String_Clear(&wom_identifier); + String_Format1(&wom_identifier, "womenv_%i", &wom_counter); } -void Handlers_Tick(void) { - Classic_Tick(); - CPE_Tick(); - WoM_Tick(); +void WoM_CheckMotd(void) { + String motd = ServerConnection_ServerMOTD; + if (motd.length == 0) return; + + String cfg = String_FromConst("cfg="); + Int32 index = String_IndexOfString(&motd, &cfg); + if (Game_PureClassic || index == -1) return; + + UInt8 urlBuffer[String_BufferSize(STRING_SIZE)]; + String url = String_InitAndClearArray(urlBuffer); + String host = String_UNSAFE_SubstringAt(&motd, index + cfg.length); + String_Format1(&url, "http://%s", &host); + /* TODO: Replace $U with username */ + /*url = url.Replace("$U", game.Username); */ + + /* Ensure that if the user quickly changes to a different world, env settings from old world aren't + 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_Download(&url, true, REQUEST_TYPE_STRING, &wom_identifier); + wom_sendId = true; +} + +void WoM_CheckSendWomID(void) { + if (wom_sendId && !wom_sentId) { + String msg = String_FromConst("/womid WoMClient-2.0.7") + ServerConnection_SendChat(&msg); + wom_sentId = true; + } +} + +PackedCol WoM_ParseCol(STRING_PURE String* value, PackedCol defaultCol) { + Int32 argb; + if (!Convert_TryParseInt32(value, &argb)) return defaultCol; + + PackedCol col; col.A = 255; + col.R = (UInt8)(argb >> 16); + col.G = (UInt8)(argb >> 8); + col.B = (UInt8)argb; + return col; +} + +bool WoM_ReadLine(STRING_REF String* page, Int32* start, STRING_TRANSIENT String* line) { + Int32 i, offset = *start; + if (offset == -1) return false; + + for (i = offset; i < page->length; i++) { + UInt8 c = page->buffer[i]; + if (c != '\r' && c != '\n') continue; + + *line = String_UNSAFE_Substring(page, offset, i - offset); + offset = i + 1; + if (c == '\r' && offset < page->length && page->buffer[offset] == '\n') { + offset++; /* we stop at the \r, so make sure to skip following \n */ + } + + *start = offset; return true; + } + + *line = String_UNSAFE_SubstringAt(page, offset); + + *start = -1; + return true; +} + +void Wom_ParseConfig(STRING_PURE String* page) { + String line; + Int32 start = 0; + + while (WoM_ReadLine(page, &start, &line)) { + Platform_Log(&line); + Int32 sepIndex = String_IndexOf(&line, '=', 0); + if (sepIndex == -1) continue; + + String key = String_UNSAFE_Substring(&line, 0, sepIndex); + String_UNSAFE_TrimEnd(&key); + String value = String_UNSAFE_SubstringAt(&line, sepIndex + 1); + String_UNSAFE_TrimStart(&value); + + if (String_CaselessEqualsConst(&key, "environment.cloud")) { + PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultCloudsCol); + WorldEnv_SetCloudsCol(col); + } else if (String_CaselessEqualsConst(&key, "environment.sky")) { + PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultSkyCol); + WorldEnv_SetSkyCol(col); + } else if (String_CaselessEqualsConst(&key, "environment.fog")) { + PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultFogCol); + WorldEnv_SetFogCol(col); + } else if (String_CaselessEqualsConst(&key, "environment.level")) { + Int32 waterLevel; + if (Convert_TryParseInt32(&value, &waterLevel)) { + WorldEnv_SetEdgeHeight(waterLevel); + } + } else if (String_CaselessEqualsConst(&key, "user.detail") && !cpe_useMessageTypes) { + Chat_AddOf(&value, MSG_TYPE_STATUS_2); + } + } +} + +void WoM_Reset(void) { + wom_counter = 0; + WoM_UpdateIdentifier(); + wom_sendId = false; wom_sentId = false; +} + +void WoM_Tick(void) { + AsyncRequest item; + bool success = AsyncDownloader_Get(&wom_identifier, &item); + if (success && item.ResultString.length > 0) { + Wom_ParseConfig(&item.ResultString); + Platform_MemFree(&item.ResultString.buffer); + } } /*########################################################################################################################* *----------------------------------------------------Classic protocol-----------------------------------------------------* *#########################################################################################################################*/ -bool receivedFirstPosition; DateTime mapReceiveStart; InflateState mapInflateState; Stream mapInflateStream; @@ -205,10 +325,54 @@ Stream mapPartStream; Screen* prevScreen; bool prevCursorVisible, receivedFirstPosition; +void Classic_WriteChat(Stream* stream, STRING_PURE String* text, bool partial) { + Int32 payload = !ServerConnection_SupportsPartialMessages ? ENTITIES_SELF_ID : (partial ? 1 : 0); + Stream_WriteU8(stream, OPCODE_MESSAGE); + Stream_WriteU8(stream, (UInt8)payload); + Handlers_WriteString(stream, text); +} + +void Classic_WritePosition(Stream* stream, Vector3 pos, Real32 rotY, Real32 headX) { + Int32 payload = cpe_sendHeldBlock ? Inventory_SelectedBlock : ENTITIES_SELF_ID; + Stream_WriteU8(stream, OPCODE_ENTITY_TELEPORT); + Handlers_WriteBlock(stream, (BlockID)payload); /* held block when using HeldBlock, otherwise just 255 */ + + if (cpe_extEntityPos) { + Stream_WriteI32_BE(stream, (Int32)(pos.X * 32)); + Stream_WriteI32_BE(stream, (Int32)((Int32)(pos.Y * 32) + 51)); + Stream_WriteI32_BE(stream, (Int32)(pos.Z * 32)); + } else { + Stream_WriteI16_BE(stream, (Int16)(pos.X * 32)); + Stream_WriteI16_BE(stream, (Int16)((Int32)(pos.Y * 32) + 51)); + Stream_WriteI16_BE(stream, (Int16)(pos.Z * 32)); + } + Stream_WriteU8(stream, Math_Deg2Packed(rotY)); + Stream_WriteU8(stream, Math_Deg2Packed(headX)); +} + +void Classic_WriteSetBlock(Stream* stream, Int32 x, Int32 y, Int32 z, bool place, BlockID block) { + Stream_WriteU8(stream, OPCODE_SET_BLOCK_CLIENT); + Stream_WriteI16_BE(stream, x); + Stream_WriteI16_BE(stream, y); + Stream_WriteI16_BE(stream, z); + Stream_WriteU8(stream, place ? 1 : 0); + Handlers_WriteBlock(stream, block); +} + +void Classic_WriteLogin(Stream* stream, STRING_PURE String* username, STRING_PURE String* verKey) { + UInt8 payload = Game_UseCPE ? 0x42 : 0x00; + Stream_WriteU8(stream, OPCODE_HANDSHAKE); + + Stream_WriteU8(stream, 7); /* protocol version */ + Handlers_WriteString(stream, username); + Handlers_WriteString(stream, verKey); + Stream_WriteU8(stream, payload); +} + void Classic_Handshake(Stream* stream) { UInt8 protocolVer = Stream_ReadU8(stream); - ReadString(stream, &ServerConnection_ServerName); - ReadString(stream, &ServerConnection_ServerMOTD); + Handlers_ReadString(stream, ServerConnection_ServerName.buffer); + Handlers_ReadString(stream, ServerConnection_ServerMOTD.buffer); Chat_SetLogName(&ServerConnection_ServerName); HacksComp* hacks = &LocalPlayer_Instance.Hacks; @@ -221,31 +385,20 @@ void Classic_Handshake(Stream* stream) { void Classic_Ping(Stream* stream) { } -void Classic_LevelInit(Stream* stream) { - if (!mapInflateInited) Classic_StartLoading(stream); - - /* Fast map puts volume in header, doesn't bother with gzip */ - if (cpe_fastMap) { - mapVolume = Stream_ReadI32_BE(stream); - gzHeader.Done = true; - mapSizeIndex = 4; - map = Platform_MemAlloc(mapVolume); - if (map == NULL) ErrorHandler_Fail("Failed to allocate memory for map"); - } -} - void Classic_StartLoading(Stream* stream) { World_Reset(); Event_RaiseVoid(&WorldEvents_NewMap); mapPartStream = *stream; prevScreen = Gui_Active; - if (prevScreen is LoadingMapScreen) { + if (prevScreen == LoadingScreen_UNSAFE_RawPointer) { + /* otherwise replacing LoadingScreen with LoadingScreen will cause issues */ + Gui_FreeActive(); prevScreen = NULL; } prevCursorVisible = Game_GetCursorVisible(); - Gui_SetNewScreen(new LoadingMapScreen(game, net.ServerName, net.ServerMotd), false); + Gui_SetActive(LoadingScreen_MakeInstance(&ServerConnection_ServerName, &ServerConnection_ServerMOTD)); WoM_CheckMotd(); receivedFirstPosition = false; GZipHeader_Init(&gzHeader); @@ -258,6 +411,19 @@ void Classic_StartLoading(Stream* stream) { Platform_CurrentUTCTime(&mapReceiveStart); } +void Classic_LevelInit(Stream* stream) { + if (!mapInflateInited) Classic_StartLoading(stream); + + /* Fast map puts volume in header, doesn't bother with gzip */ + if (cpe_fastMap) { + mapVolume = Stream_ReadI32_BE(stream); + gzHeader.Done = true; + mapSizeIndex = 4; + map = Platform_MemAlloc(mapVolume, sizeof(BlockID)); + if (map == NULL) ErrorHandler_Fail("Failed to allocate memory for map"); + } +} + void Classic_LevelDataChunk(Stream* stream) { /* Workaround for some servers that send LevelDataChunk before LevelInit due to their async sending behaviour */ if (!mapInflateInited) Classic_StartLoading(stream); @@ -281,7 +447,7 @@ void Classic_LevelDataChunk(Stream* stream) { if (mapSizeIndex == 4) { if (map == NULL) { mapVolume = (mapSize[0] << 24) | (mapSize[1] << 16) | (mapSize[2] << 8) | mapSize[3]; - map = Platform_MemAlloc(mapVolume); + map = Platform_MemAlloc(mapVolume, sizeof(BlockID)); if (map == NULL) ErrorHandler_Fail("Failed to allocate memory for map"); } @@ -297,7 +463,7 @@ void Classic_LevelDataChunk(Stream* stream) { } void Classic_LevelFinalise(Stream* stream) { - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); Gui_Active = prevScreen; if (prevScreen != NULL && prevCursorVisible != Game_GetCursorVisible()) { Game_SetCursorVisible(prevCursorVisible); @@ -314,7 +480,7 @@ void Classic_LevelFinalise(Stream* stream) { World_SetNewMap(map, mapVolume, mapWidth, mapHeight, mapLength); Event_RaiseVoid(&WorldEvents_MapLoaded); - Wom_CheckSendWomID(); + WoM_CheckSendWomID(); map = NULL; mapInflateInited = false; @@ -430,7 +596,7 @@ void Classic_Kick(Stream* stream) { void Classic_SetPermission(Stream* stream) { HacksComp* hacks = &LocalPlayer_Instance.Hacks; HacksComp_SetUserType(hacks, Stream_ReadU8(stream), !cpe_blockPerms); - HacksComp_UpdateHacksState(hacks); + HacksComp_UpdateState(hacks); } void Classic_ReadAbsoluteLocation(Stream* stream, EntityID id, bool interpolate) { @@ -453,50 +619,6 @@ void Classic_ReadAbsoluteLocation(Stream* stream, EntityID id, bool interpolate) Handlers_UpdateLocation(id, &update, interpolate); } -void Classic_WriteChat(Stream* stream, STRING_PURE String* text, bool partial) { - Int32 payload = !ServerConnection_SupportsPartialMessages ? ENTITIES_SELF_ID : (partial ? 1 : 0); - Stream_WriteU8(stream, OPCODE_MESSAGE); - Stream_WriteU8(stream, (UInt8)payload); - Handlers_WriteString(stream, text); -} - -void Classic_WritePosition(Stream* stream, Vector3 pos, Real32 rotY, Real32 headX) { - Int32 payload = cpe_sendHeldBlock ? Inventory_SelectedBlock : ENTITIES_SELF_ID; - Stream_WriteU8(stream, OPCODE_ENTITY_TELEPORT); - Handlers_WriteBlock(stream, (BlockID)payload); /* held block when using HeldBlock, otherwise just 255 */ - - if (cpe_extEntityPos) { - Stream_WriteI32_BE(stream, (Int32)(pos.X * 32)); - Stream_WriteI32_BE(stream, (Int32)((Int32)(pos.Y * 32) + 51)); - Stream_WriteI32_BE(stream, (Int32)(pos.Z * 32)); - } else { - Stream_WriteI16_BE(stream, (Int16)(pos.X * 32)); - Stream_WriteI16_BE(stream, (Int16)((Int32)(pos.Y * 32) + 51)); - Stream_WriteI16_BE(stream, (Int16)(pos.Z * 32)); - } - Stream_WriteU8(stream, Math_Deg2Packed(rotY)); - Stream_WriteU8(stream, Math_Deg2Packed(headX)); -} - -void Classic_WriteSetBlock(Stream* stream, Int32 x, Int32 y, Int32 z, bool place, BlockID block) { - Stream_WriteU8(stream, OPCODE_SET_BLOCK_CLIENT); - Stream_WriteI16_BE(stream, x); - Stream_WriteI16_BE(stream, y); - Stream_WriteI16_BE(stream, z); - Stream_WriteU8(stream, place ? 1 : 0); - Handlers_WriteBlock(stream, block); -} - -void Classic_WriteLogin(Stream* stream, STRING_PURE String* username, STRING_PURE String* verKey) { - UInt8 payload = Game_UseCPE ? 0x42 : 0x00; - Stream_WriteU8(stream, OPCODE_HANDSHAKE); - - Stream_WriteU8(stream, 7); /* protocol version */ - Handlers_WriteString(stream, username); - Handlers_WriteString(stream, verKey); - Stream_WriteU8(stream, payload); -} - void Classic_Reset(void) { mapInflateInited = false; receivedFirstPosition = false; @@ -533,17 +655,94 @@ void Classic_Tick(void) { *#########################################################################################################################*/ Int32 cpe_serverExtensionsCount, cpe_pingTicks; -bool cpe_sendHeldBlock, cpe_useMessageTypes; Int32 cpe_envMapVer = 2, cpe_blockDefsExtVer = 2; -bool cpe_needD3Fix, cpe_extEntityPos, cpe_twoWayPing, cpe_blockPerms, cpe_fastMap; +bool cpe_twoWayPing; -const UInt8** cpe_clientExtensions[28] = { +const UInt8* cpe_clientExtensions[28] = { "ClickDistance", "CustomBlocks", "HeldBlock", "EmoteFix", "TextHotKey", "ExtPlayerList", "EnvColors", "SelectionCuboid", "BlockPermissions", "ChangeModel", "EnvMapAppearance", "EnvWeatherType", "MessageTypes", "HackControl", "PlayerClick", "FullCP437", "LongerMessages", "BlockDefinitions", "BlockDefinitionsExt", "BulkBlockUpdate", "TextColors", "EnvMapAspect", "EntityProperty", "ExtEntityPositions", "TwoWayPing", "InventoryOrder", "InstantMOTD", "FastMap", }; +void CPE_SetMapEnvUrl(Stream* stream); + +#define Ext_Deg2Packed(x) ((Int16)((x) * 65536.0f / 360.0f)) +void CPE_WritePlayerClick(Stream* stream, MouseButton button, bool buttonDown, UInt8 targetId, PickedPos* pos) { + Entity* p = &LocalPlayer_Instance.Base; + Stream_WriteU8(stream, OPCODE_CPE_PLAYER_CLICK); + Stream_WriteU8(stream, button); + Stream_WriteU8(stream, buttonDown ? 0 : 1); + Stream_WriteI16_BE(stream, Ext_Deg2Packed(p->HeadY)); + Stream_WriteI16_BE(stream, Ext_Deg2Packed(p->HeadX)); + + Stream_WriteU8(stream, targetId); + Stream_WriteI16_BE(stream, pos->BlockPos.X); + Stream_WriteI16_BE(stream, pos->BlockPos.Y); + Stream_WriteI16_BE(stream, pos->BlockPos.Z); + + UInt8 face = 255; + /* Our own face values differ from CPE block face */ + switch (pos->ClosestFace) { + case FACE_XMAX: face = 0; break; + case FACE_XMIN: face = 1; break; + case FACE_YMAX: face = 2; break; + case FACE_YMIN: face = 3; break; + case FACE_ZMAX: face = 4; break; + case FACE_ZMIN: face = 5; break; + } + Stream_WriteU8(stream, face); +} + +void CPE_WriteExtInfo(Stream* stream, STRING_PURE String* appName, Int32 extensionsCount) { + Stream_WriteU8(stream, OPCODE_CPE_EXT_INFO); + Handlers_WriteString(stream, appName); + Stream_WriteU16_BE(stream, extensionsCount); +} + +void CPE_WriteExtEntry(Stream* stream, STRING_PURE String* extensionName, Int32 extensionVersion) { + Stream_WriteU8(stream, OPCODE_CPE_EXT_ENTRY); + Handlers_WriteString(stream, extensionName); + Stream_WriteI32_BE(stream, extensionVersion); +} + +void CPE_WriteCustomBlockLevel(Stream* stream, UInt8 version) { + Stream_WriteU8(stream, OPCODE_CPE_CUSTOM_BLOCK_LEVEL); + Stream_WriteU8(stream, version); +} + +void CPE_WriteTwoWayPing(Stream* stream, bool serverToClient, UInt16 data) { + Stream_WriteU8(stream, OPCODE_CPE_TWO_WAY_PING); + Stream_WriteU8(stream, serverToClient ? 1 : 0); + Stream_WriteU16_BE(stream, data); +} + +void CPE_SendCpeExtInfoReply(void) { + if (cpe_serverExtensionsCount != 0) return; + Int32 count = Array_Elems(cpe_clientExtensions); + if (!Game_AllowCustomBlocks) count -= 2; + Stream* stream = ServerConnection_WriteStream(); + + CPE_WriteExtInfo(stream, &ServerConnection_AppName, count); + Net_SendPacket(); + Int32 i, ver; + + for (i = 0; i < Array_Elems(cpe_clientExtensions); i++) { + String name = String_FromReadonly(cpe_clientExtensions[i]); + ver = 1; + if (String_CaselessEqualsConst(&name, "ExtPlayerList")) ver = 2; + if (String_CaselessEqualsConst(&name, "EnvMapAppearance")) ver = cpe_envMapVer; + if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) ver = cpe_blockDefsExtVer; + + if (!Game_AllowCustomBlocks) { + if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) continue; + if (String_CaselessEqualsConst(&name, "BlockDefinitions")) continue; + } + + CPE_WriteExtEntry(stream, &name, ver); + Net_SendPacket(); + } +} void CPE_ExtInfo(Stream* stream) { UInt8 appNameBuffer[String_BufferSize(STRING_SIZE)]; @@ -669,8 +868,8 @@ void CPE_ExtAddPlayerName(Stream* stream) { UInt8 groupRank = Stream_ReadU8(stream); String_StripCols(&playerName); - Handler_RemoveEndPlus(&playerName); - Handler_RemoveEndPlus(&listName); + Handlers_RemoveEndPlus(&playerName); + Handlers_RemoveEndPlus(&listName); /* Some server software will declare they support ExtPlayerList, but send AddEntity then AddPlayerName */ /* We need to workaround this case by removing all the tab names we added for the AddEntity packets */ @@ -755,7 +954,7 @@ void CPE_SetBlockPermission(Stream* stream) { void CPE_ChangeModel(Stream* stream) { UInt8 modelNameBuffer[String_BufferSize(STRING_SIZE)]; UInt8 id = Stream_ReadU8(stream); - String modelName = Handlers_ReadString(stream, &modelNameBuffer); + String modelName = Handlers_ReadString(stream, modelNameBuffer); String_MakeLowercase(&modelName); Entity* entity = Entities_List[id]; @@ -920,13 +1119,13 @@ void CPE_SetEntityProperty(Stream* stream) { Real32 scale; switch (type) { update.Flags |= LOCATIONUPDATE_FLAG_ROTX; - update.RotX = LocationUpdate_Clamp(value); break; + update.RotX = LocationUpdate_Clamp((Real32)value); break; case 1: update.Flags |= LOCATIONUPDATE_FLAG_HEADY; - update.HeadY = LocationUpdate_Clamp(value); break; + update.HeadY = LocationUpdate_Clamp((Real32)value); break; case 2: update.Flags |= LOCATIONUPDATE_FLAG_ROTZ; - update.RotZ = LocationUpdate_Clamp(value); break; + update.RotZ = LocationUpdate_Clamp((Real32)value); break; case 3: case 4: @@ -965,83 +1164,6 @@ void CPE_SetInventoryOrder(Stream* stream) { } } -#define Ext_Deg2Packed(x) ((Int16)((x) * 65536.0f / 360.0f)) -void CPE_WritePlayerClick(Stream* stream, MouseButton button, bool buttonDown, UInt8 targetId, PickedPos* pos) { - Entity* p = &LocalPlayer_Instance.Base; - Stream_WriteU8(stream, OPCODE_CPE_PLAYER_CLICK); - Stream_WriteU8(stream, button); - Stream_WriteU8(stream, buttonDown ? 0 : 1); - Stream_WriteI16_BE(stream, Ext_Deg2Packed(p->HeadY)); - Stream_WriteI16_BE(stream, Ext_Deg2Packed(p->HeadX)); - - Stream_WriteU8(stream, targetId); - Stream_WriteI16_BE(stream, pos->BlockPos.X); - Stream_WriteI16_BE(stream, pos->BlockPos.Y); - Stream_WriteI16_BE(stream, pos->BlockPos.Z); - - UInt8 face = 255; - /* Our own face values differ from CPE block face */ - switch (pos->ClosestFace) { - case FACE_XMAX: face = 0; break; - case FACE_XMIN: face = 1; break; - case FACE_YMAX: face = 2; break; - case FACE_YMIN: face = 3; break; - case FACE_ZMAX: face = 4; break; - case FACE_ZMIN: face = 5; break; - } - Stream_WriteU8(stream, face); -} - -void CPE_WriteExtInfo(Stream* stream, STRING_PURE String* appName, Int32 extensionsCount) { - Stream_WriteU8(stream, OPCODE_CPE_EXT_INFO); - Handlers_WriteString(stream, appName); - Stream_WriteU16_BE(stream, extensionsCount); -} - -void CPE_WriteExtEntry(Stream* stream, STRING_PURE String* extensionName, Int32 extensionVersion) { - Stream_WriteU8(stream, OPCODE_CPE_EXT_ENTRY); - Handlers_WriteString(stream, extensionName); - Stream_WriteI32_BE(stream, extensionVersion); -} - -void CPE_WriteCustomBlockLevel(Stream* stream, UInt8 version) { - Stream_WriteU8(stream, OPCODE_CPE_CUSTOM_BLOCK_LEVEL); - Stream_WriteU8(stream, version); -} - -void CPE_WriteTwoWayPing(Stream* stream, bool serverToClient, UInt16 data) { - Stream_WriteU8(stream, OPCODE_CPE_TWO_WAY_PING); - Stream_WriteU8(stream, serverToClient ? 1 : 0); - Stream_WriteU16_BE(stream, data); -} - -void CPE_SendCpeExtInfoReply(void) { - if (cpe_serverExtensionsCount != 0) return; - Int32 count = Array_Elems(cpe_clientExtensions); - if (!Game_AllowCustomBlocks) count -= 2; - Stream* stream = ServerConnection_WriteStream(); - - CPE_WriteExtInfo(stream, &ServerConnection_AppName, count); - Net_SendPacket(); - Int32 i, ver; - - for (i = 0; i < Array_Elems(cpe_clientExtensions); i++) { - String name = String_FromReadonly(cpe_clientExtensions[i]); - ver = 1; - if (String_CaselessEqualsConst(&name, "ExtPlayerList")) ver = 2; - if (String_CaselessEqualsConst(&name, "EnvMapAppearance")) ver = cpe_envMapVer; - if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) ver = cpe_blockDefsExtVer; - - if (!Game_AllowCustomBlocks) { - if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) continue; - if (String_CaselessEqualsConst(&name, "BlockDefinitions")) continue; - } - - CPE_WriteExtEntry(stream, &name, ver); - Net_SendPacket(); - } -} - void CPE_Reset(void) { cpe_serverExtensionsCount = 0; cpe_pingTicks = 0; cpe_sendHeldBlock = false; cpe_useMessageTypes = false; @@ -1084,7 +1206,7 @@ void CPE_Tick(void) { cpe_pingTicks++; if (cpe_pingTicks >= 20 && cpe_twoWayPing) { Stream* stream = ServerConnection_WriteStream(); - CPE_WriteTwoWayPing(stream, false, PingList_NextTwoWayPingData()); + CPE_WriteTwoWayPing(stream, false, PingList_NextPingData()); cpe_pingTicks = 0; } } @@ -1093,65 +1215,16 @@ void CPE_Tick(void) { /*########################################################################################################################* *------------------------------------------------------Custom blocks------------------------------------------------------* *#########################################################################################################################*/ -void BlockDefs_DefineBlock(Stream* stream) { - BlockID block = BlockDefs_DefineBlockCommonStart(stream, false); - - UInt8 shape = Stream_ReadU8(stream); - if (shape > 0 && shape <= 16) { - Block_MaxBB[block].Y = shape / 16.0f; - } - - BlockDefs_DefineBlockCommonEnd(stream, shape, block); - /* Update sprite BoundingBox if necessary */ - if (Block_Draw[block] == DRAW_SPRITE) { - Block_RecalculateBB(block); - } -} - -void BlockDefs_UndefineBlock(Stream* stream) { - BlockID block = Handlers_ReadBlock(stream); - bool didBlockLight = Block_BlocksLight[block]; - - Bloc_ResetBlockProps(block); - OnBlockUpdated(block, didBlockLight); - Block_UpdateCulling(block); - - Inventory_Remove(block); - if (block < BLOCK_CPE_COUNT) { Inventory_AddDefault(block); } - - Block_SetCustomDefined(block, false); - Event_RaiseVoid(&BlockEvents_BlockDefChanged); -} - void OnBlockUpdated(BlockID block, bool didBlockLight) { if (World_Blocks == NULL) return; /* Need to refresh lighting when a block's light blocking state changes */ if (Block_BlocksLight[block] != didBlockLight) { Lighting_Refresh(); } } -#define BlockDefs_ReadCoord(x) x = Stream_ReadU8(stream) / 16.0f; if (x > 1.0f) x = 1.0f; -void BlockDefs_DefineBlockExt(Stream* stream) { - BlockID block = BlockDefs_DefineBlockCommonStart(stream, cpe_blockDefsExtVer >= 2); - - Vector3 minBB; - BlockDefs_ReadCoord(minBB.X); - BlockDefs_ReadCoord(minBB.Y); - BlockDefs_ReadCoord(minBB.Z); - - Vector3 maxBB; - BlockDefs_ReadCoord(maxBB.X); - BlockDefs_ReadCoord(maxBB.Y); - BlockDefs_ReadCoord(maxBB.Z); - - Block_MinBB[block] = minBB; - Block_MaxBB[block] = maxBB; - BlockDefs_DefineBlockCommonEnd(stream, 1, block); -} - BlockID BlockDefs_DefineBlockCommonStart(Stream* stream, bool uniqueSideTexs) { BlockID block = Handlers_ReadBlock(stream); bool didBlockLight = Block_BlocksLight[block]; - Block_ResetBlockProps(block); + Block_ResetProps(block); UInt8 nameBuffer[String_BufferSize(STRING_SIZE)]; String name = Handlers_ReadString(stream, nameBuffer); @@ -1202,6 +1275,55 @@ void BlockDefs_DefineBlockCommonEnd(Stream* stream, UInt8 shape, BlockID block) Block_DefineCustom(block); } +void BlockDefs_DefineBlock(Stream* stream) { + BlockID block = BlockDefs_DefineBlockCommonStart(stream, false); + + UInt8 shape = Stream_ReadU8(stream); + if (shape > 0 && shape <= 16) { + Block_MaxBB[block].Y = shape / 16.0f; + } + + BlockDefs_DefineBlockCommonEnd(stream, shape, block); + /* Update sprite BoundingBox if necessary */ + if (Block_Draw[block] == DRAW_SPRITE) { + Block_RecalculateBB(block); + } +} + +void BlockDefs_UndefineBlock(Stream* stream) { + BlockID block = Handlers_ReadBlock(stream); + bool didBlockLight = Block_BlocksLight[block]; + + Block_ResetProps(block); + OnBlockUpdated(block, didBlockLight); + Block_UpdateCulling(block); + + Inventory_Remove(block); + if (block < BLOCK_CPE_COUNT) { Inventory_AddDefault(block); } + + Block_SetCustomDefined(block, false); + Event_RaiseVoid(&BlockEvents_BlockDefChanged); +} + +#define BlockDefs_ReadCoord(x) x = Stream_ReadU8(stream) / 16.0f; if (x > 1.0f) x = 1.0f; +void BlockDefs_DefineBlockExt(Stream* stream) { + BlockID block = BlockDefs_DefineBlockCommonStart(stream, cpe_blockDefsExtVer >= 2); + + Vector3 minBB; + BlockDefs_ReadCoord(minBB.X); + BlockDefs_ReadCoord(minBB.Y); + BlockDefs_ReadCoord(minBB.Z); + + Vector3 maxBB; + BlockDefs_ReadCoord(maxBB.X); + BlockDefs_ReadCoord(maxBB.Y); + BlockDefs_ReadCoord(maxBB.Z); + + Block_MinBB[block] = minBB; + Block_MaxBB[block] = maxBB; + BlockDefs_DefineBlockCommonEnd(stream, 1, block); +} + #if FALSE void HandleDefineModel(void) { int start = reader.index - 1; @@ -1240,130 +1362,18 @@ void BlockDefs_Reset(void) { /*########################################################################################################################* -*------------------------------------------------------WoM protocol-------------------------------------------------------* +*-----------------------------------------------------Public handlers-----------------------------------------------------* *#########################################################################################################################*/ -/* Partially based on information from http://files.worldofminecraft.com/texturing/ */ -/* NOTE: http://files.worldofminecraft.com/ has been down for quite a while, so support was removed on Oct 10, 2015 */ - -UInt8 wom_identifierBuffer[String_BufferSize(STRING_SIZE)]; -String wom_identifier = String_FromEmptyArray(wom_identifierBuffer); -Int32 wom_counter; -bool wom_sendId, wom_sentId; - -void WoM_UpdateIdentifier(void) { - String_Clear(&wom_identifier); - String_Format1(&wom_identifier, "womenv_%i", &wom_counter); +void Handlers_Reset(void) { + addEntityHack = true; + Classic_Reset(); + CPE_Reset(); + BlockDefs_Reset(); + WoM_Reset(); } -void WoM_CheckMotd(void) { - String motd = ServerConnection_ServerMOTD; - if (motd.length == 0) return; - - String cfg = String_FromConst("cfg="); - Int32 index = String_IndexOfString(&motd, &cfg); - if (Game_PureClassic || index == -1) return; - - UInt8 urlBuffer[String_BufferSize(STRING_SIZE)]; - String url = String_InitAndClearArray(urlBuffer); - String host = String_UNSAFE_SubstringAt(&motd, index + cfg.length); - String_Format1(&url, "http://%s", &host); - /* TODO: Replace $U with username */ - /*url = url.Replace("$U", game.Username); */ - - /* Ensure that if the user quickly changes to a different world, env settings from old world aren't - 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_Download(&url, true, REQUEST_TYPE_STRING, &wom_identifier); - wom_sendId = true; -} - -void WoM_CheckSendWomID(void) { - if (wom_sendId && !wom_sentId) { - String msg = String_FromConst("/womid WoMClient-2.0.7") - ServerConnection_SendChat(&msg); - wom_sentId = true; - } -} - -PackedCol WoM_ParseCol(STRING_PURE String* value, PackedCol defaultCol) { - Int32 argb; - if (!Convert_TryParseInt32(value, &argb)) return defaultCol; - - PackedCol col; col.A = 255; - col.R = (UInt8)(argb >> 16); - col.G = (UInt8)(argb >> 8); - col.B = (UInt8)argb; - return col; -} - -bool WoM_ReadLine(STRING_REF String* page, Int32* start, STRING_TRANSIENT String* line) { - Int32 i, offset = *start; - if (offset == -1) return false; - - for (i = offset; i < page->length; i++) { - UInt8 c = page->buffer[i]; - if (c != '\r' && c != '\n') continue; - - *line = String_UNSAFE_Substring(page, offset, i - offset); - offset = i + 1; - if (c == '\r' && offset < page->length && page->buffer[offset] == '\n') { - offset++; /* we stop at the \r, so make sure to skip following \n */ - } - - start = offset; return true; - } - - *line = String_UNSAFE_SubstringAt(page, offset); - start = -1; - return true; -} - -void Wom_ParseConfig(STRING_PURE String* page) { - String line; - Int32 start = 0; - - while (WoM_ReadLine(page, &start, &line)) { - Platform_Log(&line); - Int32 sepIndex = String_IndexOf(&line, '=', 0); - if (sepIndex == -1) continue; - - String key = String_UNSAFE_Substring(&line, 0, sepIndex); - String_UNSAFE_TrimEnd(&key); - String value = String_UNSAFE_SubstringAt(&line, sepIndex + 1); - String_UNSAFE_TrimStart(&value); - - if (String_CaselessEqualsConst(&key, "environment.cloud")) { - PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultCloudsCol); - WorldEnv_SetCloudsCol(col); - } else if (String_CaselessEqualsConst(&key, "environment.sky")) { - PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultSkyCol); - WorldEnv_SetSkyCol(col); - } else if (String_CaselessEqualsConst(&key, "environment.fog")) { - PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultFogCol); - WorldEnv_SetFogCol(col); - } else if (String_CaselessEqualsConst(&key, "environment.level")) { - Int32 waterLevel; - if (Convert_TryParseInt32(&value, &waterLevel)) { - WorldEnv_SetEdgeHeight(waterLevel); - } - } else if (String_CaselessEqualsConst(&key, "user.detail") && !cpe_useMessageTypes) { - Chat_AddOf(&value, MSG_TYPE_STATUS_2); - } - } -} - -void WoM_Reset(void) { - wom_counter = 0; - WoM_UpdateIdentifier(); - wom_sendId = false; wom_sentId = false; -} - -void WoM_Tick(void) { - AsyncRequest item; - bool success = AsyncDownloader_Get(&wom_identifier, &item); - if (success && item.ResultString.length > 0) { - ParseWomConfig(&item.ResultString); - Platform_MemFree(&item.ResultString.buffer); - } +void Handlers_Tick(void) { + Classic_Tick(); + CPE_Tick(); + WoM_Tick(); } \ No newline at end of file diff --git a/src/Client/PacketHandlers.h b/src/Client/PacketHandlers.h index 360a9faf1..2ded58cf7 100644 --- a/src/Client/PacketHandlers.h +++ b/src/Client/PacketHandlers.h @@ -9,10 +9,12 @@ typedef struct PickedPos_ PickedPos; typedef struct Stream_ Stream; +void Handlers_RemoveEntity(EntityID id); void Handlers_Reset(void); void Handlers_Tick(void); - void Handlers_RemoveEntity(EntityID id); + +bool cpe_sendHeldBlock, cpe_useMessageTypes, cpe_needD3Fix, cpe_extEntityPos, cpe_blockPerms, cpe_fastMap; void Classic_WriteChat(Stream* stream, STRING_PURE String* text, bool partial); void Classic_WritePosition(Stream* stream, Vector3 pos, Real32 rotY, Real32 headX); void Classic_WriteSetBlock(Stream* stream, Int32 x, Int32 y, Int32 z, bool place, BlockID block); diff --git a/src/Client/Physics.c b/src/Client/Physics.c index c2226141f..105dd35c2 100644 --- a/src/Client/Physics.c +++ b/src/Client/Physics.c @@ -169,7 +169,7 @@ Int32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entityE } Searcher_StatesCount = elements; - Searcher_States = Platform_MemAlloc(elements * sizeof(SearcherState)); + Searcher_States = Platform_MemAlloc(elements, sizeof(SearcherState)); if (Searcher_States == NULL) { ErrorHandler_Fail("Failed to allocate memory for Searcher_FindReachableBlocks"); } diff --git a/src/Client/Platform.h b/src/Client/Platform.h index 87211804b..45a0db317 100644 --- a/src/Client/Platform.h +++ b/src/Client/Platform.h @@ -17,8 +17,8 @@ void Platform_Init(void); void Platform_Free(void); void Platform_Exit(ReturnCode code); -void* Platform_MemAlloc(UInt32 numBytes); -void* Platform_MemRealloc(void* mem, UInt32 numBytes); +void* Platform_MemAlloc(UInt32 numElems, UInt32 elemsSize); +void* Platform_MemRealloc(void* mem, UInt32 numElems, UInt32 elemsSize); void Platform_MemFree(void** mem); void Platform_MemSet(void* dst, UInt8 value, UInt32 numBytes); void Platform_MemCpy(void* dst, void* src, UInt32 numBytes); @@ -72,4 +72,5 @@ ReturnCode Platform_SocketRead(void* socket, UInt8* buffer, UInt32 count, UInt32 ReturnCode Platform_SocketWrite(void* socket, UInt8* buffer, UInt32 count, UInt32* modified); ReturnCode Platform_SocketClose(void* socket); ReturnCode Platform_SocketAvailable(void* socket, UInt32* available); +ReturnCode Platform_SocketSelectRead(void* socket, Int32 microseconds, bool* success); #endif \ No newline at end of file diff --git a/src/Client/Program.c b/src/Client/Program.c index 1f90bd8f4..9210de87a 100644 --- a/src/Client/Program.c +++ b/src/Client/Program.c @@ -47,8 +47,11 @@ int main(int argc, char* argv[]) { } String title = String_FromConst(PROGRAM_APP_NAME); - // if (argc == 1 || arc == 2) { - if (true) { + argc = 5; + char* default_argv[5] = { "path", "UnknownShadow200", "mppass", "127.0.0.1", "25566" }; + argv = default_argv; + + if (argc == 1 || argc == 2) { //String_AppendConst(&Game_Username, argc > 1 ? argv[1] : "Singleplayer"); String_AppendConst(&Game_Username, "Singleplayer"); } else if (argc < 5) { diff --git a/src/Client/Screens.c b/src/Client/Screens.c index 5635236a2..de4e342fd 100644 --- a/src/Client/Screens.c +++ b/src/Client/Screens.c @@ -174,12 +174,12 @@ bool InventoryScreen_HandlesKeyDown(GuiElement* elem, Key key) { TableWidget* table = &screen->Table; if (key == KeyBind_Get(KeyBind_PauseOrExit)) { - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); } else if (key == KeyBind_Get(KeyBind_Inventory) && screen->ReleasedInv) { - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); } else if (key == Key_Enter && table->SelectedIndex != -1) { Inventory_SetSelectedBlock(table->Elements[table->SelectedIndex]); - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); } else if (Elem_HandlesKeyDown(table, key)) { } else { HUDScreen* hud = (HUDScreen*)Gui_HUD; @@ -207,7 +207,7 @@ bool InventoryScreen_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, MouseB bool handled = Elem_HandlesMouseDown(table, x, y, btn); if ((!handled || table->PendingClose) && btn == MouseButton_Left) { bool hotbar = Key_IsControlPressed() || Key_IsShiftPressed(); - if (!hotbar) Gui_SetNewScreen(NULL); + if (!hotbar) Gui_ReplaceActive(NULL); } return true; } @@ -618,6 +618,7 @@ Screen* LoadingScreen_MakeInstance(STRING_PURE String* title, STRING_PURE String LoadingScreen_Make(screen, &LoadingScreen_VTABLE, title, message); return (Screen*)screen; } +extern Screen* LoadingScreen_UNSAFE_RawPointer = (Screen*)&LoadingScreen_Instance; /*########################################################################################################################* @@ -1519,8 +1520,7 @@ bool DisconnectScreen_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, Mouse String empty = String_MakeNull(); String_Format2(&connect, "Connecting to %s: %i..", &Game_IPAddress, &Game_Port); - Screen* loadScreen = LoadingScreen_MakeInstance(&connect, &empty); - Gui_SetNewScreen(loadScreen); + Gui_ReplaceActive(LoadingScreen_MakeInstance(&connect, &empty)); ServerConnection_Connect(&Game_IPAddress, Game_Port); } return true; diff --git a/src/Client/Screens.h b/src/Client/Screens.h index b36ed0d72..cddfe00d5 100644 --- a/src/Client/Screens.h +++ b/src/Client/Screens.h @@ -1,7 +1,6 @@ #ifndef CC_SCREENS_H #define CC_SCREENS_H #include "Gui.h" - /* Contains all 2D non-menu screen implementations. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ @@ -17,6 +16,8 @@ Screen* DisconnectScreen_MakeInstance(STRING_PURE String* title, STRING_PURE Str /* Raw pointer to inventory screen. DO NOT USE THIS. Use InventoryScreen_MakeInstance() */ extern Screen* InventoryScreen_UNSAFE_RawPointer; +/* Raw pointer to loading screen. DO NOT USE THIS. Use LoadingScreen_MakeInstance() */ +extern Screen* LoadingScreen_UNSAFE_RawPointer; void HUDScreen_OpenInput(Screen* hud, STRING_PURE String* text); void HUDScreen_AppendInput(Screen* hud, STRING_PURE String* text); Widget* HUDScreen_GetHotbar(Screen* hud); diff --git a/src/Client/SelectionBox.c b/src/Client/SelectionBox.c index 547e152a2..befdc4b10 100644 --- a/src/Client/SelectionBox.c +++ b/src/Client/SelectionBox.c @@ -127,7 +127,7 @@ UInt32 selections_count; SelectionBox selections_list[SELECTIONS_MAX]; UInt8 selections_ids[SELECTIONS_MAX]; GfxResourceID selections_VB, selections_LineVB; -bool selections_allocated; +bool selections_used; void Selections_Add(UInt8 id, Vector3I p1, Vector3I p2, PackedCol col) { SelectionBox sel; @@ -163,7 +163,7 @@ void Selections_ContextLost(void* obj) { } void Selections_ContextRecreated(void* obj) { - if (!selections_allocated) return; + if (!selections_used) return; selections_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FC4B, SELECTIONS_MAX_VERTICES); selections_LineVB = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FC4B, SELECTIONS_MAX_VERTICES); } @@ -197,9 +197,9 @@ void Selections_Render(Real64 delta) { } Selections_QuickSort(0, selections_count - 1); - if (!selections_allocated) { /* lazy init as most servers don't use this */ + if (selections_VB == NULL) { /* lazy init as most servers don't use this */ + selections_used = true; Selections_ContextRecreated(NULL); - selections_allocated = true; } VertexP3fC4b vertices[SELECTIONS_MAX_VERTICES]; VertexP3fC4b* ptr = vertices; diff --git a/src/Client/ServerConnection.c b/src/Client/ServerConnection.c index 9edc087df..030d40356 100644 --- a/src/Client/ServerConnection.c +++ b/src/Client/ServerConnection.c @@ -89,7 +89,8 @@ void ServerConnection_BeginGeneration(Int32 width, Int32 height, Int32 length, I Event_RaiseVoid(&WorldEvents_NewMap); Gen_Done = false; - Gui_SetNewScreen(GeneratingScreen_MakeInstance()); + Gui_FreeActive(); + Gui_SetActive(GeneratingScreen_MakeInstance()); Gen_Width = width; Gen_Height = height; Gen_Length = length; Gen_Seed = seed; void* threadHandle; @@ -103,7 +104,7 @@ void ServerConnection_BeginGeneration(Int32 width, Int32 height, Int32 length, I } void ServerConnection_EndGeneration(void) { - Gui_SetNewScreen(NULL); + Gui_ReplaceActive(NULL); Gen_Done = false; if (Gen_Blocks == NULL) { @@ -285,7 +286,20 @@ UInt8 net_writeBuffer[131]; Int32 net_maxHandledPacket; bool net_writeFailed; Int32 net_ticks; +Real64 net_discAccumulator; +void MPConnection_BlockChanged(void* obj, Vector3I coords, BlockID oldBlock, BlockID block) { + Vector3I p = coords; + if (block == BLOCK_AIR) { + block = Inventory_SelectedBlock; + Classic_WriteSetBlock(&net_writeStream, p.X, p.Y, p.Z, false, block); + } else { + Classic_WriteSetBlock(&net_writeStream, p.X, p.Y, p.Z, true, block); + } + Net_SendPacket(); +} + +void ServerConnection_Free(void); void MPConnection_Connect(STRING_PURE String* ip, Int32 port) { Platform_SocketCreate(&net_socket); Event_RegisterBlock(&UserEvents_BlockChanged, NULL, MPConnection_BlockChanged); @@ -293,9 +307,16 @@ void MPConnection_Connect(STRING_PURE String* ip, Int32 port) { ReturnCode result = Platform_SocketConnect(net_socket, &Game_IPAddress, Game_Port); if (result != 0) { - ErrorHandler.LogError("connecting to server", ex); - game.Disconnect("Failed to connect to " + address + ":" + port, - "You failed to connect to the server. It's probably down!"); + UInt8 msgBuffer[String_BufferSize(STRING_SIZE * 2)]; + String msg = String_InitAndClearArray(msgBuffer); + String_Format3(&msg, "Error connecting to %s:%i: %i", ip, &port, &result); + ErrorHandler_Log(&msg); + + String_Clear(&msg); + String_Format2(&msg, "Failed to connect to %s:%i", ip, &port); + String reason = String_FromConst("You failed to connect to the server. It's probably down!"); + Game_Disconnect(&msg, &reason); + ServerConnection_Free(); return; } @@ -303,6 +324,7 @@ void MPConnection_Connect(STRING_PURE String* ip, Int32 port) { String streamName = String_FromConst("network socket"); Stream_ReadonlyMemory(&net_readStream, net_readBuffer, sizeof(net_readBuffer), &streamName); Stream_WriteonlyMemory(&net_writeStream, net_writeBuffer, sizeof(net_writeBuffer), &streamName); + net_readStream.Meta_Mem_Count = 0; /* initally no memory to read */ Handlers_Reset(); Classic_WriteLogin(&net_writeStream, &Game_Username, &Game_Mppass); @@ -335,13 +357,16 @@ void MPConnection_SendPlayerClick(MouseButton button, bool buttonDown, EntityID Net_SendPacket(); } -double testAcc = 0; -void CheckDisconnection(double delta) { - testAcc += delta; - if (testAcc < 1) return; - testAcc = 0; +void MPConnection_CheckDisconnection(Real64 delta) { + net_discAccumulator += delta; + if (net_discAccumulator < 1.0) return; + net_discAccumulator = 0.0; - if (net_writeFailed || (socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0)) { + UInt32 available = 0; bool selected = false; + ReturnCode availResult = Platform_SocketAvailable(net_socket, &available); + ReturnCode selectResult = Platform_SocketSelectRead(net_socket, 1000, &selected); + + if (net_writeFailed || availResult != 0 || selectResult != 0 || (selected && available == 0)) { String title = String_FromConst("Disconnected!"); String reason = String_FromConst("You've lost connection to the server"); Game_Disconnect(&title, &reason); @@ -351,9 +376,8 @@ void CheckDisconnection(double delta) { void MPConnection_Tick(ScheduledTask* task) { if (ServerConnection_Disconnected) return; DateTime now; Platform_CurrentUTCTime(&now); - if (DateTime_MsBetween(&net_lastPacket, &now) >= 30 * 1000) { - CheckDisconnection(task.Interval); + MPConnection_CheckDisconnection(task->Interval); } if (ServerConnection_Disconnected) return; @@ -365,16 +389,23 @@ void MPConnection_Tick(ScheduledTask* task) { recvResult = Platform_SocketRead(net_socket, src, 4096 * 4, &modified); net_readStream.Meta_Mem_Count += modified; } + if (recvResult != 0) { - ErrorHandler.LogError("reading packets", ex); - game.Disconnect("&eLost connection to the server", "I/O error when reading packets"); + UInt8 msgBuffer[String_BufferSize(STRING_SIZE * 2)]; + String msg = String_InitAndClearArray(msgBuffer); + String_Format3(&msg, "Error reading from %s:%i: %i", &Game_IPAddress, &Game_Port, &recvResult); + ErrorHandler_Log(&msg); + + String title = String_FromConst("&eLost connection to the server"); + String reason = String_FromConst("I/O error when reading packets"); + Game_Disconnect(&title, &reason); return; } while (net_readStream.Meta_Mem_Count > 0) { UInt8 opcode = net_readStream.Meta_Mem_Buffer[0]; /* Workaround for older D3 servers which wrote one byte too many for HackControl packets */ - if (cpeData.needD3Fix && net_lastOpcode == OPCODE_CPE_HACK_CONTROL && (opcode == 0x00 || opcode == 0xFF)) { + if (cpe_needD3Fix && net_lastOpcode == OPCODE_CPE_HACK_CONTROL && (opcode == 0x00 || opcode == 0xFF)) { Platform_LogConst("Skipping invalid HackControl byte from D3 server"); Stream_Skip(&net_readStream, 1); @@ -384,9 +415,7 @@ void MPConnection_Tick(ScheduledTask* task) { continue; } - if (opcode > net_maxHandledPacket) { - throw new InvalidOperationException("Invalid opcode: " + opcode); - } + if (opcode > net_maxHandledPacket) { ErrorHandler_Fail("Invalid opcode"); } if (net_readStream.Meta_Mem_Count < Net_PacketSizes[opcode]) break; Stream_Skip(&net_readStream, 1); /* remove opcode */ @@ -394,13 +423,16 @@ void MPConnection_Tick(ScheduledTask* task) { Net_Handler handler = Net_Handlers[opcode]; Platform_CurrentUTCTime(&net_lastPacket); - if (handler == NULL) { - throw new InvalidOperationException("Unsupported opcode: " + opcode); - } + if (handler == NULL) { ErrorHandler_Fail("Unsupported opcode"); } handler(&net_readStream); } - reader.RemoveProcessed(); + /* Keep last few unprocessed bytes, don't care about rest since they'll be overwritten on socket read */ + Int32 i; + for (i = 0; i < net_readStream.Meta_Mem_Count; i++) { + net_readBuffer[i] = net_readStream.Meta_Mem_Buffer[i]; + } + net_readStream.Meta_Mem_Buffer = net_readBuffer; /* Network is ticked 60 times a second. We only send position updates 20 times a second */ if ((net_ticks % 3) == 0) { @@ -434,17 +466,6 @@ void Net_SendPacket(void) { net_writeStream.Meta_Mem_Count = sizeof(net_writeBuffer); } -void MPConnection_BlockChanged(void* obj, Vector3I coords, BlockID oldBlock, BlockID block) { - Vector3I p = coords; - if (block == BLOCK_AIR) { - block = Inventory_SelectedBlock; - Classic_WriteSetBlock(&net_writeStream, p.X, p.Y, p.Z, false, block); - } else { - Classic_WriteSetBlock(&net_writeStream, p.X, p.Y, p.Z, true, block); - } - Net_SendPacket(); -} - Stream* MPConnection_ReadStream(void) { return &net_readStream; } Stream* MPConnection_WriteStream(void) { return &net_writeStream; } void ServerConnection_InitMultiplayer(void) { @@ -467,7 +488,7 @@ void MPConnection_OnNewMap(void) { /* wipe all existing entity states */ Int32 i; for (i = 0; i < ENTITIES_MAX_COUNT; i++) { - classic.RemoveEntity((byte)i); + Handlers_RemoveEntity((EntityID)i); } } diff --git a/src/Client/String.c b/src/Client/String.c index 1c9ad7b2a..38f007314 100644 --- a/src/Client/String.c +++ b/src/Client/String.c @@ -625,14 +625,14 @@ void StringsBuffer_Resize(void** buffer, UInt32* elems, UInt32 elemSize, UInt32 /* We use a statically allocated buffer initally, so can't realloc first time */ void* dst; void* cur = *buffer; + UInt32 curElems = *elems; - UInt32 curElems = *elems, newSize = (curElems + expandElems) * elemSize; if (curElems <= defElems) { - dst = Platform_MemAlloc(newSize); + dst = Platform_MemAlloc(curElems + expandElems, elemSize); if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for StringsBuffer"); Platform_MemCpy(dst, cur, curElems * elemSize); } else { - dst = Platform_MemRealloc(cur, newSize); + dst = Platform_MemRealloc(cur, curElems + expandElems, elemSize); if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for resizing StringsBuffer"); } diff --git a/src/Client/Vectors.c b/src/Client/Vectors.c index 42cabc7f8..33303cf5c 100644 --- a/src/Client/Vectors.c +++ b/src/Client/Vectors.c @@ -250,7 +250,7 @@ void Matrix_OrthographicOffCenter(Matrix* result, Real32 left, Real32 right, Rea } void Matrix_PerspectiveFieldOfView(Matrix* result, Real32 fovy, Real32 aspect, Real32 zNear, Real32 zFar) { - Real32 c = (Real32)(zNear * Math_TanF(0.5 * fovy)); + Real32 c = zNear * Math_TanF(0.5f * fovy); Matrix_PerspectiveOffCenter(result, -c * aspect, c * aspect, -c, c, zNear, zFar); } diff --git a/src/Client/WeatherRenderer.c b/src/Client/WeatherRenderer.c index a3498eeeb..c30887db2 100644 --- a/src/Client/WeatherRenderer.c +++ b/src/Client/WeatherRenderer.c @@ -26,7 +26,7 @@ Real64 weather_accumulator; Vector3I weather_lastPos; void WeatherRenderer_InitHeightmap(void) { - Weather_Heightmap = Platform_MemAlloc(World_Width * World_Length * sizeof(Int16)); + Weather_Heightmap = Platform_MemAlloc(World_Width * World_Length, sizeof(Int16)); if (Weather_Heightmap == NULL) { ErrorHandler_Fail("WeatherRenderer - Failed to allocate heightmap"); } diff --git a/src/Client/WinPlatform.c b/src/Client/WinPlatform.c index b0a56997f..4e6b2d207 100644 --- a/src/Client/WinPlatform.c +++ b/src/Client/WinPlatform.c @@ -13,6 +13,7 @@ #include #include +#pragma comment(lib, "ws2_32.lib") HDC hdc; HANDLE heap; bool stopwatch_highResolution; @@ -74,12 +75,14 @@ void Platform_Exit(ReturnCode code) { ExitProcess(code); } -void* Platform_MemAlloc(UInt32 numBytes) { +void* Platform_MemAlloc(UInt32 numElems, UInt32 elemsSize) { + UInt32 numBytes = numElems * elemsSize; /* TODO: avoid overflow here */ return malloc(numBytes); //return HeapAlloc(heap, 0, numBytes); } -void* Platform_MemRealloc(void* mem, UInt32 numBytes) { +void* Platform_MemRealloc(void* mem, UInt32 numElems, UInt32 elemsSize) { + UInt32 numBytes = numElems * elemsSize; /* TODO: avoid overflow here */ return realloc(mem, numBytes); //return HeapReAlloc(heap, 0, mem, numBytes); } @@ -439,5 +442,22 @@ ReturnCode Platform_SocketClose(void* socket) { } ReturnCode Platform_SocketAvailable(void* socket, UInt32* available) { - return ioctlsocket(socket, FIONBIO, available); + return ioctlsocket(socket, FIONREAD, available); +} + +ReturnCode Platform_SocketSelectRead(void* socket, Int32 microseconds, bool* success) { + void* args[2]; + args[0] = (void*)1; + args[1] = socket; + + TIMEVAL time; + time.tv_usec = microseconds % (1000 * 1000); + time.tv_sec = microseconds / (1000 * 1000); + + Int32 selectCount = select(1, &args, NULL, NULL, &time); + if (selectCount == SOCKET_ERROR) { + *success = false; return WSAGetLastError(); + } else { + *success = args[0] != 0; return 0; + } } \ No newline at end of file