Multiplayer of C client connects (Although pretty much doing anything causes a crash)

This commit is contained in:
UnknownShadow200 2018-04-27 09:23:46 +10:00
parent 1eca5206f2
commit ca000b317c
32 changed files with 601 additions and 535 deletions

View File

@ -195,7 +195,7 @@ void Animations_Draw(AnimationData* data, Int32 texId, Int32 size) {
UInt8* ptr = buffer; UInt8* ptr = buffer;
if (size > ANIMS_FAST_SIZE) { if (size > ANIMS_FAST_SIZE) {
/* cannot allocate memory on the stack for very big animation.png frames */ /* 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"); if (ptr == NULL) ErrorHandler_Fail("Failed to allocate memory for anim frame");
} }

View File

@ -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) { void Bitmap_Allocate(Bitmap* bmp, Int32 width, Int32 height) {
bmp->Width = width; bmp->Height = height; bmp->Width = width; bmp->Height = height;
bmp->Stride = width * BITMAP_SIZEOF_PIXEL; 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) { if (bmp->Scan0 == NULL) {
ErrorHandler_Fail("Bitmap - failed to allocate memory"); 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"); if (bmp->Height < 0 || bmp->Height > PNG_MAX_DIMS) ErrorHandler_Fail("PNG image too tall");
bmp->Stride = bmp->Width * BITMAP_SIZEOF_PIXEL; 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"); if (bmp->Scan0 == NULL) ErrorHandler_Fail("Failed to allocate memory for PNG bitmap");
bitsPerSample = Stream_ReadU8(stream); bitsPerSample = Stream_ReadU8(stream);

View File

@ -46,7 +46,7 @@ void TickQueue_Resize(TickQueue* queue) {
UInt32 capacity = queue->BufferSize * 2; UInt32 capacity = queue->BufferSize * 2;
if (capacity < 32) capacity = 32; if (capacity < 32) capacity = 32;
UInt32* newBuffer = Platform_MemAlloc(capacity * sizeof(UInt32)); UInt32* newBuffer = Platform_MemAlloc(capacity, sizeof(UInt32));
if (newBuffer == NULL) { if (newBuffer == NULL) {
ErrorHandler_Fail("TickQueue - failed to allocate memory"); ErrorHandler_Fail("TickQueue - failed to allocate memory");
} }

View File

@ -180,7 +180,7 @@ void BordersRenderer_RebuildSides(Int32 y, Int32 axisSize) {
VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b v[4096];
VertexP3fT2fC4b* ptr = v; VertexP3fT2fC4b* ptr = v;
if (borders_sidesVertices > 4096) { 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"); if (ptr == NULL) ErrorHandler_Fail("BordersRenderer_Sides - failed to allocate memory");
} }
VertexP3fT2fC4b* temp = ptr; VertexP3fT2fC4b* temp = ptr;
@ -223,7 +223,7 @@ void BordersRenderer_RebuildEdges(Int32 y, Int32 axisSize) {
VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b v[4096];
VertexP3fT2fC4b* ptr = v; VertexP3fT2fC4b* ptr = v;
if (borders_edgesVertices > 4096) { 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"); if (ptr == NULL) ErrorHandler_Fail("BordersRenderer_Edges - failed to allocate memory");
} }
VertexP3fT2fC4b* temp = ptr; VertexP3fT2fC4b* temp = ptr;

View File

@ -63,7 +63,7 @@ void Builder1DPart_Prepare(Builder1DPart* part) {
if (vCount > part->verticesBufferCount) { if (vCount > part->verticesBufferCount) {
Platform_MemFree(&part->vertices); Platform_MemFree(&part->vertices);
part->vertices = Platform_MemAlloc((vCount + 2) * sizeof(VertexP3fT2fC4b)); part->vertices = Platform_MemAlloc(vCount + 2, sizeof(VertexP3fT2fC4b));
part->verticesBufferCount = vCount; part->verticesBufferCount = vCount;
if (part->vertices == NULL) { if (part->vertices == NULL) {
ErrorHandler_Fail("Builder1DPart_Prepare - failed to allocate memory"); ErrorHandler_Fail("Builder1DPart_Prepare - failed to allocate memory");

View File

@ -125,23 +125,23 @@ void ChunkUpdater_FreeAllocations(void) {
} }
void ChunkUpdater_PerformAllocations(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"); 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"); 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"); 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"); if (ChunkUpdater_Distances == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate chunk distances");
UInt32 partsCount = MapRenderer_ChunksCount * MapRenderer_1DUsedCount; UInt32 partsCount = MapRenderer_ChunksCount * MapRenderer_1DUsedCount;
UInt32 partsSize = (partsCount * (UInt32)sizeof(ChunkPartInfo)) * 2; MapRenderer_PartsBuffer_Raw = Platform_MemAlloc(partsCount * 2, sizeof(ChunkPartInfo));
MapRenderer_PartsBuffer_Raw = Platform_MemAlloc(partsSize);
if (MapRenderer_PartsBuffer_Raw == NULL) ErrorHandler_Fail("ChunkUpdater - failed to allocate chunk parts buffer"); 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); Platform_MemSet(MapRenderer_PartsBuffer_Raw, 0, partsSize);
MapRenderer_PartsNormal = MapRenderer_PartsBuffer_Raw; MapRenderer_PartsNormal = MapRenderer_PartsBuffer_Raw;
MapRenderer_PartsTranslucent = MapRenderer_PartsBuffer_Raw + partsCount; MapRenderer_PartsTranslucent = MapRenderer_PartsBuffer_Raw + partsCount;

View File

@ -205,9 +205,8 @@ void D3D9_DoMipmaps(IDirect3DTexture9* texture, Int32 x, Int32 y, Bitmap* bmp, b
x /= 2; y /= 2; x /= 2; y /= 2;
if (width > 1) width /= 2; if (width > 1) width /= 2;
if (height > 1) height /= 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"); if (cur == NULL) ErrorHandler_Fail("Allocating memory for mipmaps");
GfxCommon_GenMipmaps(width, height, cur, prev); GfxCommon_GenMipmaps(width, height, cur, prev);

View File

@ -142,6 +142,7 @@ typedef struct NetPlayer_ {
bool ShouldRender; bool ShouldRender;
} NetPlayer; } NetPlayer;
void NetPlayer_Init(NetPlayer* player, STRING_PURE String* displayName, STRING_PURE String* skinName); 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. */ /* Represents the user/player's own entity. */
typedef struct LocalPlayer_ { typedef struct LocalPlayer_ {

View File

@ -138,7 +138,7 @@ void EnvRenderer_UpdateFog(void) {
Gfx_SetFogDensity((Real32)density); Gfx_SetFogDensity((Real32)density);
} else { } else {
Gfx_SetFogMode(FOG_LINEAR); Gfx_SetFogMode(FOG_LINEAR);
Gfx_SetFogEnd(Game_ViewDistance); Gfx_SetFogEnd((Real32)Game_ViewDistance);
} }
Gfx_ClearColour(fogCol); Gfx_ClearColour(fogCol);
Gfx_SetFogColour(fogCol); Gfx_SetFogColour(fogCol);
@ -214,7 +214,7 @@ void EnvRenderer_RebuildClouds(Int32 extent, Int32 axisSize) {
VertexP3fT2fC4b v[4096]; VertexP3fT2fC4b v[4096];
VertexP3fT2fC4b* ptr = v; VertexP3fT2fC4b* ptr = v;
if (env_cloudVertices > 4096) { 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"); 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 v[4096];
VertexP3fC4b* ptr = v; VertexP3fC4b* ptr = v;
if (env_skyVertices > 4096) { 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"); if (ptr == NULL) ErrorHandler_Fail("EnvRenderer_Sky - failed to allocate memory");
} }

View File

@ -12,7 +12,7 @@
void Map_ReadBlocks(Stream* stream) { void Map_ReadBlocks(Stream* stream) {
World_BlocksSize = World_Width * World_Length * World_Height; 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) { if (World_Blocks == NULL) {
ErrorHandler_Fail("Failed to allocate memory for reading blocks array from file"); 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) { if (count < NBT_SMALL_SIZE) {
Stream_Read(stream, tag.DataSmall, count); Stream_Read(stream, tag.DataSmall, count);
} else { } else {
tag.DataBig = Platform_MemAlloc(count); tag.DataBig = Platform_MemAlloc(count, sizeof(UInt8));
if (tag.DataBig == NULL) ErrorHandler_Fail("Nbt_ReadTag - allocating memory"); if (tag.DataBig == NULL) ErrorHandler_Fail("Nbt_ReadTag - allocating memory");
Stream_Read(stream, tag.DataBig, count); Stream_Read(stream, tag.DataBig, count);
} }
@ -396,7 +396,7 @@ bool Cw_Callback_1(NbtTag* tag) {
if (IsTag(tag, "BlockArray")) { if (IsTag(tag, "BlockArray")) {
World_BlocksSize = tag->DataSize; World_BlocksSize = tag->DataSize;
if (tag->DataSize < NBT_SMALL_SIZE) { 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"); if (World_Blocks == NULL) ErrorHandler_Fail("Failed to allocate memory for map");
Platform_MemCpy(World_Blocks, tag->DataSmall, tag->DataSize); Platform_MemCpy(World_Blocks, tag->DataSmall, tag->DataSize);
} else { } else {

View File

@ -173,7 +173,8 @@ void Game_UpdateProjection(void) {
void Game_Disconnect(STRING_PURE String* title, STRING_PURE String* reason) { void Game_Disconnect(STRING_PURE String* title, STRING_PURE String* reason) {
World_Reset(); World_Reset();
Event_RaiseVoid(&WorldEvents_NewMap); Event_RaiseVoid(&WorldEvents_NewMap);
Gui_SetNewScreen(DisconnectScreen_MakeInstance(title, reason)); Gui_FreeActive();
Gui_SetActive(DisconnectScreen_MakeInstance(title, reason));
Drawer2D_Init(); Drawer2D_Init();
Block_Reset(); Block_Reset();
@ -530,7 +531,8 @@ void Game_Load(void) {
String_Format2(&loadTitle, "Connecting to %s:%i..", &Game_IPAddress, &Game_Port); String_Format2(&loadTitle, "Connecting to %s:%i..", &Game_IPAddress, &Game_Port);
String loadMsg = String_MakeNull(); String loadMsg = String_MakeNull();
Gui_SetNewScreen(LoadingScreen_MakeInstance(&loadTitle, &loadMsg)); Gui_FreeActive();
Gui_SetActive(LoadingScreen_MakeInstance(&loadTitle, &loadMsg));
ServerConnection_Connect(&Game_IPAddress, Game_Port); ServerConnection_Connect(&Game_IPAddress, Game_Port);
} }
@ -672,7 +674,8 @@ void Game_RenderFrame(Real64 delta) {
Camera_Active->UpdateMouse(); Camera_Active->UpdateMouse();
if (!Window_GetFocused() && !Gui_GetActiveScreen()->HandlesAllInput) { if (!Window_GetFocused() && !Gui_GetActiveScreen()->HandlesAllInput) {
Gui_SetNewScreen(PauseScreen_MakeInstance()); Gui_FreeActive();
Gui_SetActive(PauseScreen_MakeInstance());
} }
bool allowZoom = Gui_Active == NULL && !Gui_HUD->HandlesAllInput; bool allowZoom = Gui_Active == NULL && !Gui_HUD->HandlesAllInput;
@ -779,7 +782,6 @@ void Cw_Save(Stream* stream) { }
void Dat_Load(Stream* stream) { } void Dat_Load(Stream* stream) { }
void Schematic_Save(Stream* stream) { } void Schematic_Save(Stream* stream) { }
void Gfx_MakeApiInfo(void) { } void Gfx_MakeApiInfo(void) { }
void ServerConnection_InitMultiplayer(void) { }
bool Convert_TryParseInt64(STRING_PURE String* str, Int64* value) { return true; } bool Convert_TryParseInt64(STRING_PURE String* str, Int64* value) { return true; }
DateTime DateTime_FromTotalMs(Int64 ms) { DateTime time; return time; } DateTime DateTime_FromTotalMs(Int64 ms) { DateTime time; return time; }
Screen* UrlWarningOverlay_MakeInstance(STRING_PURE String* url) { return NULL; } Screen* UrlWarningOverlay_MakeInstance(STRING_PURE String* url) { return NULL; }

View File

@ -23,8 +23,8 @@ IGameComponent GameMode_MakeComponent(void) {
bool GameMode_HandlesKeyDown(Key key) { bool GameMode_HandlesKeyDown(Key key) {
Screen* activeScreen = Gui_GetActiveScreen(); Screen* activeScreen = Gui_GetActiveScreen();
if (key == KeyBind_Get(KeyBind_Inventory) && activeScreen == Gui_HUD) { if (key == KeyBind_Get(KeyBind_Inventory) && activeScreen == Gui_HUD) {
Screen* screen = InventoryScreen_MakeInstance(); Gui_FreeActive();
Gui_SetNewScreen(screen); Gui_SetActive(InventoryScreen_MakeInstance());
return true; return true;
} else if (key == KeyBind_Get(KeyBind_DropBlock) && !Game_ClassicMode) { } else if (key == KeyBind_Get(KeyBind_DropBlock) && !Game_ClassicMode) {
if (Inventory_CanChangeSelected() && Inventory_SelectedBlock != BLOCK_AIR) { if (Inventory_CanChangeSelected() && Inventory_SelectedBlock != BLOCK_AIR) {

View File

@ -112,7 +112,7 @@ void Gui_Reset(void) {
void Gui_Free(void) { void Gui_Free(void) {
Event_UnregisterStream(&TextureEvents_FileChanged, NULL, Gui_FileChanged); Event_UnregisterStream(&TextureEvents_FileChanged, NULL, Gui_FileChanged);
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
Elem_TryFree(Gui_Status); Elem_TryFree(Gui_Status);
if (Gui_Active != NULL) { Elem_TryFree(Gui_Active); } if (Gui_Active != NULL) { Elem_TryFree(Gui_Active); }
@ -138,9 +138,16 @@ Screen* Gui_GetUnderlyingScreen(void) {
return Gui_Active == NULL ? Gui_HUD : Gui_Active; 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); InputHandler_ScreenChanged(Gui_Active, screen);
if (Gui_Active != NULL && freeOld) { Elem_TryFree(Gui_Active); }
if (screen == NULL) { if (screen == NULL) {
Game_SetCursorVisible(false); Game_SetCursorVisible(false);
@ -152,8 +159,6 @@ void Gui_SetScreen(Screen* screen, bool freeOld) {
if (screen != NULL) { Elem_Init(screen); } if (screen != NULL) { Elem_Init(screen); }
Gui_Active = screen; Gui_Active = screen;
} }
void Gui_SetNewScreen(Screen* screen) { Gui_SetScreen(screen, true); }
void Gui_RefreshHud(void) { Elem_Recreate(Gui_HUD); } void Gui_RefreshHud(void) { Elem_Recreate(Gui_HUD); }
void Gui_ShowOverlay_Impl(Screen* overlay, bool atFront) { void Gui_ShowOverlay_Impl(Screen* overlay, bool atFront) {

View File

@ -77,8 +77,11 @@ Screen* Gui_GetActiveScreen(void);
/* Gets the non-overlay screen that the user is currently interacting with. /* 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. */ This means if an overlay is active, it will return the screen under it. */
Screen* Gui_GetUnderlyingScreen(void); 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_RefreshHud(void);
void Gui_ShowOverlay(Screen* overlay, bool atFront); void Gui_ShowOverlay(Screen* overlay, bool atFront);
void Gui_RenderGui(Real64 delta); void Gui_RenderGui(Real64 delta);

View File

@ -174,8 +174,8 @@ bool InputHandler_HandleCoreKey(Key key) {
InputHandler_CycleDistanceForwards(viewDists, count); InputHandler_CycleDistanceForwards(viewDists, count);
} }
} else if ((key == KeyBind_Get(KeyBind_PauseOrExit) || key == Key_Pause) && World_Blocks != NULL) { } else if ((key == KeyBind_Get(KeyBind_PauseOrExit) || key == Key_Pause) && World_Blocks != NULL) {
Screen* screen = PauseScreen_MakeInstance(); Gui_FreeActive();
Gui_SetNewScreen(screen); Gui_SetActive(PauseScreen_MakeInstance());
} else if (GameMode_HandlesKeyDown(key)) { } else if (GameMode_HandlesKeyDown(key)) {
} else if (key == KeyBind_Get(KeyBind_IDOverlay)) { } else if (key == KeyBind_Get(KeyBind_IDOverlay)) {
if (Gui_OverlaysCount > 0) return true; if (Gui_OverlaysCount > 0) return true;

View File

@ -331,8 +331,7 @@ void Lighting_OnNewMap(void) {
} }
void Lighting_OnNewMapLoaded(void) { void Lighting_OnNewMapLoaded(void) {
UInt32 size = World_Width * World_Length * sizeof(Int16); Lighting_heightmap = Platform_MemAlloc(World_Width * World_Length, sizeof(Int16));
Lighting_heightmap = Platform_MemAlloc(size);
if (Lighting_heightmap == NULL) { if (Lighting_heightmap == NULL) {
ErrorHandler_Fail("WorldLighting - failed to allocate heightmap"); ErrorHandler_Fail("WorldLighting - failed to allocate heightmap");
} }

View File

@ -17,7 +17,7 @@ void Gen_Init(void) {
Gen_CurrentProgress = 0.0f; Gen_CurrentProgress = 0.0f;
Gen_CurrentState = ""; 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) { if (Gen_Blocks == NULL) {
ErrorHandler_Fail("MapGen - failed to allocate Blocks array"); ErrorHandler_Fail("MapGen - failed to allocate Blocks array");
} }
@ -465,7 +465,7 @@ void NotchyGen_PlantTrees(void) {
void NotchyGen_Generate(void) { void NotchyGen_Generate(void) {
Gen_Init(); Gen_Init();
Heightmap = Platform_MemAlloc(Gen_Width * Gen_Length * sizeof(Int16)); Heightmap = Platform_MemAlloc(Gen_Width * Gen_Length, sizeof(Int16));
if (Heightmap == NULL) { if (Heightmap == NULL) {
ErrorHandler_Fail("NotchyGen - Failed to allocate Heightmap array"); ErrorHandler_Fail("NotchyGen - Failed to allocate Heightmap array");
} }

View File

@ -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; } 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; } 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_SwitchOptions(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(OptionsGroupScreen_MakeInstance()); }
void Menu_SwitchPause(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(PauseScreen_MakeInstance()); } void Menu_SwitchPause(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(PauseScreen_MakeInstance()); }
void Menu_SwitchClassicOptions(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicOptionsScreen_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_SwitchKeysClassic(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicKeyBindingsScreen_MakeInstance()); }
void Menu_SwitchKeysClassicHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicHacksKeyBindingsScreen_MakeInstance()); } void Menu_SwitchKeysClassicHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicHacksKeyBindingsScreen_MakeInstance()); }
void Menu_SwitchKeysNormal(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(NormalKeyBindingsScreen_MakeInstance()); } void Menu_SwitchKeysNormal(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(NormalKeyBindingsScreen_MakeInstance()); }
void Menu_SwitchKeysHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HacksKeyBindingsScreen_MakeInstance()); } void Menu_SwitchKeysHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(HacksKeyBindingsScreen_MakeInstance()); }
void Menu_SwitchKeysOther(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(OtherKeyBindingsScreen_MakeInstance()); } void Menu_SwitchKeysOther(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(OtherKeyBindingsScreen_MakeInstance()); }
void Menu_SwitchKeysMouse(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(MouseKeyBindingsScreen_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_SwitchMisc(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(MiscOptionsScreen_MakeInstance()); }
void Menu_SwitchGui(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(GuiOptionsScreen_MakeInstance()); } void Menu_SwitchGui(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GuiOptionsScreen_MakeInstance()); }
void Menu_SwitchGfx(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(GraphicsOptionsScreen_MakeInstance()); } void Menu_SwitchGfx(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GraphicsOptionsScreen_MakeInstance()); }
void Menu_SwitchHacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HacksSettingsScreen_MakeInstance()); } void Menu_SwitchHacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(HacksSettingsScreen_MakeInstance()); }
void Menu_SwitchEnv(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(EnvSettingsScreen_MakeInstance()); } void Menu_SwitchEnv(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(EnvSettingsScreen_MakeInstance()); }
void Menu_SwitchNostalgia(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(NostalgiaScreen_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_SwitchGenLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(GenLevelScreen_MakeInstance()); }
void Menu_SwitchClassicGenLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(ClassicGenScreen_MakeInstance()); } void Menu_SwitchClassicGenLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(ClassicGenScreen_MakeInstance()); }
void Menu_SwitchLoadLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(LoadLevelScreen_MakeInstance()); } void Menu_SwitchLoadLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(LoadLevelScreen_MakeInstance()); }
void Menu_SwitchSaveLevel(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(SaveLevelScreen_MakeInstance()); } void Menu_SwitchSaveLevel(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(SaveLevelScreen_MakeInstance()); }
void Menu_SwitchTexPacks(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(TexturePackScreen_MakeInstance()); } void Menu_SwitchTexPacks(GuiElement* a, GuiElement* b) { Gui_ReplaceActive(TexturePackScreen_MakeInstance()); }
void Menu_SwitchHotkeys(GuiElement* a, GuiElement* b) { Gui_SetNewScreen(HotkeyListScreen_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) { bool ListScreen_HandlesKeyDown(GuiElement* elem, Key key) {
ListScreen* screen = (ListScreen*)elem; ListScreen* screen = (ListScreen*)elem;
if (key == Key_Escape) { if (key == Key_Escape) {
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
} else if (key == Key_Left) { } else if (key == Key_Left) {
ListScreen_PageClick(screen, false); ListScreen_PageClick(screen, false);
} else if (key == Key_Right) { } 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_HandlesMouseScroll(GuiElement* elem, Real32 delta) { return true; }
bool MenuScreen_HandlesKeyDown(GuiElement* elem, Key key) { 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; return key < Key_F1 || key > Key_F35;
} }
bool MenuScreen_HandlesKeyPress(GuiElement* elem, UInt8 key) { return true; } 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_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) { void PauseScreen_CheckHacksAllowed(void* obj) {
if (Game_UseClassicOptions) return; 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_Add(hotkey.BaseKey, hotkey.Flags, &text, hotkey.StaysOpen);
Hotkeys_UserAddedHotkey(hotkey.BaseKey, hotkey.Flags, hotkey.StaysOpen, &text); Hotkeys_UserAddedHotkey(hotkey.BaseKey, hotkey.Flags, hotkey.StaysOpen, &text);
} }
Gui_SetNewScreen(HotkeyListScreen_MakeInstance()); Gui_ReplaceActive(HotkeyListScreen_MakeInstance());
} }
void EditHotkeyScreen_RemoveHotkey(GuiElement* elem, GuiElement* widget) { 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_Remove(hotkey.BaseKey, hotkey.Flags);
Hotkeys_UserRemovedHotkey(hotkey.BaseKey, hotkey.Flags); Hotkeys_UserRemovedHotkey(hotkey.BaseKey, hotkey.Flags);
} }
Gui_SetNewScreen(HotkeyListScreen_MakeInstance()); Gui_ReplaceActive(HotkeyListScreen_MakeInstance());
} }
void EditHotkeyScreen_Init(GuiElement* elem) { void EditHotkeyScreen_Init(GuiElement* elem) {
@ -1351,7 +1351,7 @@ void SaveLevelScreen_Render(GuiElement* elem, Real64 delta) {
String_Format1(&msg, "&eSaved map to: %s", &path); String_Format1(&msg, "&eSaved map to: %s", &path);
Chat_Add(&msg); Chat_Add(&msg);
Gui_SetNewScreen(PauseScreen_MakeInstance()); Gui_ReplaceActive(PauseScreen_MakeInstance());
String_Clear(&path); String_Clear(&path);
} }
@ -1479,7 +1479,7 @@ void HotkeyListScreen_EntryClick(GuiElement* screenElem, GuiElement* w) {
HotkeyData original = { 0 }; HotkeyData original = { 0 };
if (String_CaselessEqualsConst(&text, LIST_SCREEN_EMPTY)) { 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); Int32 sepIndex = String_IndexOf(&text, '|', 0);
@ -1501,7 +1501,7 @@ void HotkeyListScreen_EntryClick(GuiElement* screenElem, GuiElement* w) {
HotkeyData h = HotkeysList[i]; HotkeyData h = HotkeysList[i];
if (h.BaseKey == baseKey && h.Flags == flags) { original = h; break; } if (h.BaseKey == baseKey && h.Flags == flags) { original = h; break; }
} }
Gui_SetNewScreen(EditHotkeyScreen_MakeInstance(original)); Gui_ReplaceActive(EditHotkeyScreen_MakeInstance(original));
} }
Screen* HotkeyListScreen_MakeInstance(void) { Screen* HotkeyListScreen_MakeInstance(void) {

View File

@ -107,9 +107,8 @@ void GL_DoMipmaps(GfxResourceID texId, Int32 x, Int32 y, Bitmap* bmp, bool parti
x /= 2; y /= 2; x /= 2; y /= 2;
if (width > 1) width /= 2; if (width > 1) width /= 2;
if (height > 1) height /= 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"); if (cur == NULL) ErrorHandler_Fail("Allocating memory for mipmaps");
GfxCommon_GenMipmaps(width, height, cur, prev); GfxCommon_GenMipmaps(width, height, cur, prev);

View File

@ -20,6 +20,7 @@
#include "AsyncDownloader.h" #include "AsyncDownloader.h"
#include "Drawer2D.h" #include "Drawer2D.h"
#include "ErrorHandler.h" #include "ErrorHandler.h"
#include "TexturePack.h"
/*########################################################################################################################* /*########################################################################################################################*
*-----------------------------------------------------Common handlers-----------------------------------------------------* *-----------------------------------------------------Common handlers-----------------------------------------------------*
@ -68,73 +69,6 @@ void Handlers_RemoveEndPlus(STRING_TRANSIENT String* value) {
String_DeleteAt(value, value->length - 1); 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) { 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. */ /* Only redraw the tab list if something changed. */
if (TabList_Valid(id)) { if (TabList_Valid(id)) {
@ -160,6 +94,76 @@ void Handlers_RemoveTablistEntry(EntityID id) {
TabList_Remove(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) { void Handlers_DisableAddEntityHack(void) {
if (!addEntityHack) return; if (!addEntityHack) return;
addEntityHack = false; addEntityHack = false;
@ -169,30 +173,146 @@ void Handlers_DisableAddEntityHack(void) {
Int32 mask = id >> 3, bit = 1 << (id & 0x7); Int32 mask = id >> 3, bit = 1 << (id & 0x7);
if (!(needRemoveNames[mask] & bit)) continue; if (!(needRemoveNames[mask] & bit)) continue;
RemoveTablistEntry((EntityID)id); Handlers_RemoveTablistEntry((EntityID)id);
needRemoveNames[mask] &= (UInt8)~bit; needRemoveNames[mask] &= (UInt8)~bit;
} }
} }
void Handlers_Reset(void) {
addEntityHack = true; /*########################################################################################################################*
Classic_Reset(); *------------------------------------------------------WoM protocol-------------------------------------------------------*
CPE_Reset(); *#########################################################################################################################*/
BlockDefs_Reset(); /* Partially based on information from http://files.worldofminecraft.com/texturing/ */
WoM_Reset(); /* 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) { void WoM_CheckMotd(void) {
Classic_Tick(); String motd = ServerConnection_ServerMOTD;
CPE_Tick(); if (motd.length == 0) return;
WoM_Tick();
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-----------------------------------------------------* *----------------------------------------------------Classic protocol-----------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
bool receivedFirstPosition;
DateTime mapReceiveStart; DateTime mapReceiveStart;
InflateState mapInflateState; InflateState mapInflateState;
Stream mapInflateStream; Stream mapInflateStream;
@ -205,10 +325,54 @@ Stream mapPartStream;
Screen* prevScreen; Screen* prevScreen;
bool prevCursorVisible, receivedFirstPosition; 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) { void Classic_Handshake(Stream* stream) {
UInt8 protocolVer = Stream_ReadU8(stream); UInt8 protocolVer = Stream_ReadU8(stream);
ReadString(stream, &ServerConnection_ServerName); Handlers_ReadString(stream, ServerConnection_ServerName.buffer);
ReadString(stream, &ServerConnection_ServerMOTD); Handlers_ReadString(stream, ServerConnection_ServerMOTD.buffer);
Chat_SetLogName(&ServerConnection_ServerName); Chat_SetLogName(&ServerConnection_ServerName);
HacksComp* hacks = &LocalPlayer_Instance.Hacks; HacksComp* hacks = &LocalPlayer_Instance.Hacks;
@ -221,31 +385,20 @@ void Classic_Handshake(Stream* stream) {
void Classic_Ping(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) { void Classic_StartLoading(Stream* stream) {
World_Reset(); World_Reset();
Event_RaiseVoid(&WorldEvents_NewMap); Event_RaiseVoid(&WorldEvents_NewMap);
mapPartStream = *stream; mapPartStream = *stream;
prevScreen = Gui_Active; prevScreen = Gui_Active;
if (prevScreen is LoadingMapScreen) { if (prevScreen == LoadingScreen_UNSAFE_RawPointer) {
/* otherwise replacing LoadingScreen with LoadingScreen will cause issues */
Gui_FreeActive();
prevScreen = NULL; prevScreen = NULL;
} }
prevCursorVisible = Game_GetCursorVisible(); prevCursorVisible = Game_GetCursorVisible();
Gui_SetNewScreen(new LoadingMapScreen(game, net.ServerName, net.ServerMotd), false); Gui_SetActive(LoadingScreen_MakeInstance(&ServerConnection_ServerName, &ServerConnection_ServerMOTD));
WoM_CheckMotd(); WoM_CheckMotd();
receivedFirstPosition = false; receivedFirstPosition = false;
GZipHeader_Init(&gzHeader); GZipHeader_Init(&gzHeader);
@ -258,6 +411,19 @@ void Classic_StartLoading(Stream* stream) {
Platform_CurrentUTCTime(&mapReceiveStart); 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) { void Classic_LevelDataChunk(Stream* stream) {
/* Workaround for some servers that send LevelDataChunk before LevelInit due to their async sending behaviour */ /* Workaround for some servers that send LevelDataChunk before LevelInit due to their async sending behaviour */
if (!mapInflateInited) Classic_StartLoading(stream); if (!mapInflateInited) Classic_StartLoading(stream);
@ -281,7 +447,7 @@ void Classic_LevelDataChunk(Stream* stream) {
if (mapSizeIndex == 4) { if (mapSizeIndex == 4) {
if (map == NULL) { if (map == NULL) {
mapVolume = (mapSize[0] << 24) | (mapSize[1] << 16) | (mapSize[2] << 8) | mapSize[3]; 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"); 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) { void Classic_LevelFinalise(Stream* stream) {
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
Gui_Active = prevScreen; Gui_Active = prevScreen;
if (prevScreen != NULL && prevCursorVisible != Game_GetCursorVisible()) { if (prevScreen != NULL && prevCursorVisible != Game_GetCursorVisible()) {
Game_SetCursorVisible(prevCursorVisible); Game_SetCursorVisible(prevCursorVisible);
@ -314,7 +480,7 @@ void Classic_LevelFinalise(Stream* stream) {
World_SetNewMap(map, mapVolume, mapWidth, mapHeight, mapLength); World_SetNewMap(map, mapVolume, mapWidth, mapHeight, mapLength);
Event_RaiseVoid(&WorldEvents_MapLoaded); Event_RaiseVoid(&WorldEvents_MapLoaded);
Wom_CheckSendWomID(); WoM_CheckSendWomID();
map = NULL; map = NULL;
mapInflateInited = false; mapInflateInited = false;
@ -430,7 +596,7 @@ void Classic_Kick(Stream* stream) {
void Classic_SetPermission(Stream* stream) { void Classic_SetPermission(Stream* stream) {
HacksComp* hacks = &LocalPlayer_Instance.Hacks; HacksComp* hacks = &LocalPlayer_Instance.Hacks;
HacksComp_SetUserType(hacks, Stream_ReadU8(stream), !cpe_blockPerms); HacksComp_SetUserType(hacks, Stream_ReadU8(stream), !cpe_blockPerms);
HacksComp_UpdateHacksState(hacks); HacksComp_UpdateState(hacks);
} }
void Classic_ReadAbsoluteLocation(Stream* stream, EntityID id, bool interpolate) { 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); 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) { void Classic_Reset(void) {
mapInflateInited = false; mapInflateInited = false;
receivedFirstPosition = false; receivedFirstPosition = false;
@ -533,17 +655,94 @@ void Classic_Tick(void) {
*#########################################################################################################################*/ *#########################################################################################################################*/
Int32 cpe_serverExtensionsCount, cpe_pingTicks; Int32 cpe_serverExtensionsCount, cpe_pingTicks;
bool cpe_sendHeldBlock, cpe_useMessageTypes;
Int32 cpe_envMapVer = 2, cpe_blockDefsExtVer = 2; 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", "ClickDistance", "CustomBlocks", "HeldBlock", "EmoteFix", "TextHotKey", "ExtPlayerList",
"EnvColors", "SelectionCuboid", "BlockPermissions", "ChangeModel", "EnvMapAppearance", "EnvColors", "SelectionCuboid", "BlockPermissions", "ChangeModel", "EnvMapAppearance",
"EnvWeatherType", "MessageTypes", "HackControl", "PlayerClick", "FullCP437", "LongerMessages", "EnvWeatherType", "MessageTypes", "HackControl", "PlayerClick", "FullCP437", "LongerMessages",
"BlockDefinitions", "BlockDefinitionsExt", "BulkBlockUpdate", "TextColors", "EnvMapAspect", "BlockDefinitions", "BlockDefinitionsExt", "BulkBlockUpdate", "TextColors", "EnvMapAspect",
"EntityProperty", "ExtEntityPositions", "TwoWayPing", "InventoryOrder", "InstantMOTD", "FastMap", "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) { void CPE_ExtInfo(Stream* stream) {
UInt8 appNameBuffer[String_BufferSize(STRING_SIZE)]; UInt8 appNameBuffer[String_BufferSize(STRING_SIZE)];
@ -669,8 +868,8 @@ void CPE_ExtAddPlayerName(Stream* stream) {
UInt8 groupRank = Stream_ReadU8(stream); UInt8 groupRank = Stream_ReadU8(stream);
String_StripCols(&playerName); String_StripCols(&playerName);
Handler_RemoveEndPlus(&playerName); Handlers_RemoveEndPlus(&playerName);
Handler_RemoveEndPlus(&listName); Handlers_RemoveEndPlus(&listName);
/* Some server software will declare they support ExtPlayerList, but send AddEntity then AddPlayerName */ /* 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 */ /* 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) { void CPE_ChangeModel(Stream* stream) {
UInt8 modelNameBuffer[String_BufferSize(STRING_SIZE)]; UInt8 modelNameBuffer[String_BufferSize(STRING_SIZE)];
UInt8 id = Stream_ReadU8(stream); UInt8 id = Stream_ReadU8(stream);
String modelName = Handlers_ReadString(stream, &modelNameBuffer); String modelName = Handlers_ReadString(stream, modelNameBuffer);
String_MakeLowercase(&modelName); String_MakeLowercase(&modelName);
Entity* entity = Entities_List[id]; Entity* entity = Entities_List[id];
@ -920,13 +1119,13 @@ void CPE_SetEntityProperty(Stream* stream) {
Real32 scale; Real32 scale;
switch (type) { switch (type) {
update.Flags |= LOCATIONUPDATE_FLAG_ROTX; update.Flags |= LOCATIONUPDATE_FLAG_ROTX;
update.RotX = LocationUpdate_Clamp(value); break; update.RotX = LocationUpdate_Clamp((Real32)value); break;
case 1: case 1:
update.Flags |= LOCATIONUPDATE_FLAG_HEADY; update.Flags |= LOCATIONUPDATE_FLAG_HEADY;
update.HeadY = LocationUpdate_Clamp(value); break; update.HeadY = LocationUpdate_Clamp((Real32)value); break;
case 2: case 2:
update.Flags |= LOCATIONUPDATE_FLAG_ROTZ; update.Flags |= LOCATIONUPDATE_FLAG_ROTZ;
update.RotZ = LocationUpdate_Clamp(value); break; update.RotZ = LocationUpdate_Clamp((Real32)value); break;
case 3: case 3:
case 4: 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) { void CPE_Reset(void) {
cpe_serverExtensionsCount = 0; cpe_pingTicks = 0; cpe_serverExtensionsCount = 0; cpe_pingTicks = 0;
cpe_sendHeldBlock = false; cpe_useMessageTypes = false; cpe_sendHeldBlock = false; cpe_useMessageTypes = false;
@ -1084,7 +1206,7 @@ void CPE_Tick(void) {
cpe_pingTicks++; cpe_pingTicks++;
if (cpe_pingTicks >= 20 && cpe_twoWayPing) { if (cpe_pingTicks >= 20 && cpe_twoWayPing) {
Stream* stream = ServerConnection_WriteStream(); Stream* stream = ServerConnection_WriteStream();
CPE_WriteTwoWayPing(stream, false, PingList_NextTwoWayPingData()); CPE_WriteTwoWayPing(stream, false, PingList_NextPingData());
cpe_pingTicks = 0; cpe_pingTicks = 0;
} }
} }
@ -1093,65 +1215,16 @@ void CPE_Tick(void) {
/*########################################################################################################################* /*########################################################################################################################*
*------------------------------------------------------Custom blocks------------------------------------------------------* *------------------------------------------------------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) { void OnBlockUpdated(BlockID block, bool didBlockLight) {
if (World_Blocks == NULL) return; if (World_Blocks == NULL) return;
/* Need to refresh lighting when a block's light blocking state changes */ /* Need to refresh lighting when a block's light blocking state changes */
if (Block_BlocksLight[block] != didBlockLight) { Lighting_Refresh(); } 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 BlockDefs_DefineBlockCommonStart(Stream* stream, bool uniqueSideTexs) {
BlockID block = Handlers_ReadBlock(stream); BlockID block = Handlers_ReadBlock(stream);
bool didBlockLight = Block_BlocksLight[block]; bool didBlockLight = Block_BlocksLight[block];
Block_ResetBlockProps(block); Block_ResetProps(block);
UInt8 nameBuffer[String_BufferSize(STRING_SIZE)]; UInt8 nameBuffer[String_BufferSize(STRING_SIZE)];
String name = Handlers_ReadString(stream, nameBuffer); String name = Handlers_ReadString(stream, nameBuffer);
@ -1202,6 +1275,55 @@ void BlockDefs_DefineBlockCommonEnd(Stream* stream, UInt8 shape, BlockID block)
Block_DefineCustom(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 #if FALSE
void HandleDefineModel(void) { void HandleDefineModel(void) {
int start = reader.index - 1; 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/ */ void Handlers_Reset(void) {
/* NOTE: http://files.worldofminecraft.com/ has been down for quite a while, so support was removed on Oct 10, 2015 */ addEntityHack = true;
Classic_Reset();
UInt8 wom_identifierBuffer[String_BufferSize(STRING_SIZE)]; CPE_Reset();
String wom_identifier = String_FromEmptyArray(wom_identifierBuffer); BlockDefs_Reset();
Int32 wom_counter; WoM_Reset();
bool wom_sendId, wom_sentId;
void WoM_UpdateIdentifier(void) {
String_Clear(&wom_identifier);
String_Format1(&wom_identifier, "womenv_%i", &wom_counter);
} }
void WoM_CheckMotd(void) { void Handlers_Tick(void) {
String motd = ServerConnection_ServerMOTD; Classic_Tick();
if (motd.length == 0) return; CPE_Tick();
WoM_Tick();
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);
}
} }

View File

@ -9,10 +9,12 @@
typedef struct PickedPos_ PickedPos; typedef struct PickedPos_ PickedPos;
typedef struct Stream_ Stream; typedef struct Stream_ Stream;
void Handlers_RemoveEntity(EntityID id);
void Handlers_Reset(void); void Handlers_Reset(void);
void Handlers_Tick(void); void Handlers_Tick(void);
void Handlers_RemoveEntity(EntityID id); 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_WriteChat(Stream* stream, STRING_PURE String* text, bool partial);
void Classic_WritePosition(Stream* stream, Vector3 pos, Real32 rotY, Real32 headX); 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); void Classic_WriteSetBlock(Stream* stream, Int32 x, Int32 y, Int32 z, bool place, BlockID block);

View File

@ -169,7 +169,7 @@ Int32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entityE
} }
Searcher_StatesCount = elements; Searcher_StatesCount = elements;
Searcher_States = Platform_MemAlloc(elements * sizeof(SearcherState)); Searcher_States = Platform_MemAlloc(elements, sizeof(SearcherState));
if (Searcher_States == NULL) { if (Searcher_States == NULL) {
ErrorHandler_Fail("Failed to allocate memory for Searcher_FindReachableBlocks"); ErrorHandler_Fail("Failed to allocate memory for Searcher_FindReachableBlocks");
} }

View File

@ -17,8 +17,8 @@ void Platform_Init(void);
void Platform_Free(void); void Platform_Free(void);
void Platform_Exit(ReturnCode code); void Platform_Exit(ReturnCode code);
void* Platform_MemAlloc(UInt32 numBytes); void* Platform_MemAlloc(UInt32 numElems, UInt32 elemsSize);
void* Platform_MemRealloc(void* mem, UInt32 numBytes); void* Platform_MemRealloc(void* mem, UInt32 numElems, UInt32 elemsSize);
void Platform_MemFree(void** mem); void Platform_MemFree(void** mem);
void Platform_MemSet(void* dst, UInt8 value, UInt32 numBytes); void Platform_MemSet(void* dst, UInt8 value, UInt32 numBytes);
void Platform_MemCpy(void* dst, void* src, 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_SocketWrite(void* socket, UInt8* buffer, UInt32 count, UInt32* modified);
ReturnCode Platform_SocketClose(void* socket); ReturnCode Platform_SocketClose(void* socket);
ReturnCode Platform_SocketAvailable(void* socket, UInt32* available); ReturnCode Platform_SocketAvailable(void* socket, UInt32* available);
ReturnCode Platform_SocketSelectRead(void* socket, Int32 microseconds, bool* success);
#endif #endif

View File

@ -47,8 +47,11 @@ int main(int argc, char* argv[]) {
} }
String title = String_FromConst(PROGRAM_APP_NAME); String title = String_FromConst(PROGRAM_APP_NAME);
// if (argc == 1 || arc == 2) { argc = 5;
if (true) { 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, argc > 1 ? argv[1] : "Singleplayer");
String_AppendConst(&Game_Username, "Singleplayer"); String_AppendConst(&Game_Username, "Singleplayer");
} else if (argc < 5) { } else if (argc < 5) {

View File

@ -174,12 +174,12 @@ bool InventoryScreen_HandlesKeyDown(GuiElement* elem, Key key) {
TableWidget* table = &screen->Table; TableWidget* table = &screen->Table;
if (key == KeyBind_Get(KeyBind_PauseOrExit)) { if (key == KeyBind_Get(KeyBind_PauseOrExit)) {
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
} else if (key == KeyBind_Get(KeyBind_Inventory) && screen->ReleasedInv) { } else if (key == KeyBind_Get(KeyBind_Inventory) && screen->ReleasedInv) {
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
} else if (key == Key_Enter && table->SelectedIndex != -1) { } else if (key == Key_Enter && table->SelectedIndex != -1) {
Inventory_SetSelectedBlock(table->Elements[table->SelectedIndex]); Inventory_SetSelectedBlock(table->Elements[table->SelectedIndex]);
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
} else if (Elem_HandlesKeyDown(table, key)) { } else if (Elem_HandlesKeyDown(table, key)) {
} else { } else {
HUDScreen* hud = (HUDScreen*)Gui_HUD; 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); bool handled = Elem_HandlesMouseDown(table, x, y, btn);
if ((!handled || table->PendingClose) && btn == MouseButton_Left) { if ((!handled || table->PendingClose) && btn == MouseButton_Left) {
bool hotbar = Key_IsControlPressed() || Key_IsShiftPressed(); bool hotbar = Key_IsControlPressed() || Key_IsShiftPressed();
if (!hotbar) Gui_SetNewScreen(NULL); if (!hotbar) Gui_ReplaceActive(NULL);
} }
return true; return true;
} }
@ -618,6 +618,7 @@ Screen* LoadingScreen_MakeInstance(STRING_PURE String* title, STRING_PURE String
LoadingScreen_Make(screen, &LoadingScreen_VTABLE, title, message); LoadingScreen_Make(screen, &LoadingScreen_VTABLE, title, message);
return (Screen*)screen; 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 empty = String_MakeNull();
String_Format2(&connect, "Connecting to %s: %i..", &Game_IPAddress, &Game_Port); String_Format2(&connect, "Connecting to %s: %i..", &Game_IPAddress, &Game_Port);
Screen* loadScreen = LoadingScreen_MakeInstance(&connect, &empty); Gui_ReplaceActive(LoadingScreen_MakeInstance(&connect, &empty));
Gui_SetNewScreen(loadScreen);
ServerConnection_Connect(&Game_IPAddress, Game_Port); ServerConnection_Connect(&Game_IPAddress, Game_Port);
} }
return true; return true;

View File

@ -1,7 +1,6 @@
#ifndef CC_SCREENS_H #ifndef CC_SCREENS_H
#define CC_SCREENS_H #define CC_SCREENS_H
#include "Gui.h" #include "Gui.h"
/* Contains all 2D non-menu screen implementations. /* Contains all 2D non-menu screen implementations.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 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() */ /* Raw pointer to inventory screen. DO NOT USE THIS. Use InventoryScreen_MakeInstance() */
extern Screen* InventoryScreen_UNSAFE_RawPointer; 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_OpenInput(Screen* hud, STRING_PURE String* text);
void HUDScreen_AppendInput(Screen* hud, STRING_PURE String* text); void HUDScreen_AppendInput(Screen* hud, STRING_PURE String* text);
Widget* HUDScreen_GetHotbar(Screen* hud); Widget* HUDScreen_GetHotbar(Screen* hud);

View File

@ -127,7 +127,7 @@ UInt32 selections_count;
SelectionBox selections_list[SELECTIONS_MAX]; SelectionBox selections_list[SELECTIONS_MAX];
UInt8 selections_ids[SELECTIONS_MAX]; UInt8 selections_ids[SELECTIONS_MAX];
GfxResourceID selections_VB, selections_LineVB; GfxResourceID selections_VB, selections_LineVB;
bool selections_allocated; bool selections_used;
void Selections_Add(UInt8 id, Vector3I p1, Vector3I p2, PackedCol col) { void Selections_Add(UInt8 id, Vector3I p1, Vector3I p2, PackedCol col) {
SelectionBox sel; SelectionBox sel;
@ -163,7 +163,7 @@ void Selections_ContextLost(void* obj) {
} }
void Selections_ContextRecreated(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_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FC4B, SELECTIONS_MAX_VERTICES);
selections_LineVB = 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); 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_ContextRecreated(NULL);
selections_allocated = true;
} }
VertexP3fC4b vertices[SELECTIONS_MAX_VERTICES]; VertexP3fC4b* ptr = vertices; VertexP3fC4b vertices[SELECTIONS_MAX_VERTICES]; VertexP3fC4b* ptr = vertices;

View File

@ -89,7 +89,8 @@ void ServerConnection_BeginGeneration(Int32 width, Int32 height, Int32 length, I
Event_RaiseVoid(&WorldEvents_NewMap); Event_RaiseVoid(&WorldEvents_NewMap);
Gen_Done = false; 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; Gen_Width = width; Gen_Height = height; Gen_Length = length; Gen_Seed = seed;
void* threadHandle; void* threadHandle;
@ -103,7 +104,7 @@ void ServerConnection_BeginGeneration(Int32 width, Int32 height, Int32 length, I
} }
void ServerConnection_EndGeneration(void) { void ServerConnection_EndGeneration(void) {
Gui_SetNewScreen(NULL); Gui_ReplaceActive(NULL);
Gen_Done = false; Gen_Done = false;
if (Gen_Blocks == NULL) { if (Gen_Blocks == NULL) {
@ -285,7 +286,20 @@ UInt8 net_writeBuffer[131];
Int32 net_maxHandledPacket; Int32 net_maxHandledPacket;
bool net_writeFailed; bool net_writeFailed;
Int32 net_ticks; 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) { void MPConnection_Connect(STRING_PURE String* ip, Int32 port) {
Platform_SocketCreate(&net_socket); Platform_SocketCreate(&net_socket);
Event_RegisterBlock(&UserEvents_BlockChanged, NULL, MPConnection_BlockChanged); 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); ReturnCode result = Platform_SocketConnect(net_socket, &Game_IPAddress, Game_Port);
if (result != 0) { if (result != 0) {
ErrorHandler.LogError("connecting to server", ex); UInt8 msgBuffer[String_BufferSize(STRING_SIZE * 2)];
game.Disconnect("Failed to connect to " + address + ":" + port, String msg = String_InitAndClearArray(msgBuffer);
"You failed to connect to the server. It's probably down!"); 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(); ServerConnection_Free();
return; return;
} }
@ -303,6 +324,7 @@ void MPConnection_Connect(STRING_PURE String* ip, Int32 port) {
String streamName = String_FromConst("network socket"); String streamName = String_FromConst("network socket");
Stream_ReadonlyMemory(&net_readStream, net_readBuffer, sizeof(net_readBuffer), &streamName); Stream_ReadonlyMemory(&net_readStream, net_readBuffer, sizeof(net_readBuffer), &streamName);
Stream_WriteonlyMemory(&net_writeStream, net_writeBuffer, sizeof(net_writeBuffer), &streamName); Stream_WriteonlyMemory(&net_writeStream, net_writeBuffer, sizeof(net_writeBuffer), &streamName);
net_readStream.Meta_Mem_Count = 0; /* initally no memory to read */
Handlers_Reset(); Handlers_Reset();
Classic_WriteLogin(&net_writeStream, &Game_Username, &Game_Mppass); Classic_WriteLogin(&net_writeStream, &Game_Username, &Game_Mppass);
@ -335,13 +357,16 @@ void MPConnection_SendPlayerClick(MouseButton button, bool buttonDown, EntityID
Net_SendPacket(); Net_SendPacket();
} }
double testAcc = 0; void MPConnection_CheckDisconnection(Real64 delta) {
void CheckDisconnection(double delta) { net_discAccumulator += delta;
testAcc += delta; if (net_discAccumulator < 1.0) return;
if (testAcc < 1) return; net_discAccumulator = 0.0;
testAcc = 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 title = String_FromConst("Disconnected!");
String reason = String_FromConst("You've lost connection to the server"); String reason = String_FromConst("You've lost connection to the server");
Game_Disconnect(&title, &reason); Game_Disconnect(&title, &reason);
@ -351,9 +376,8 @@ void CheckDisconnection(double delta) {
void MPConnection_Tick(ScheduledTask* task) { void MPConnection_Tick(ScheduledTask* task) {
if (ServerConnection_Disconnected) return; if (ServerConnection_Disconnected) return;
DateTime now; Platform_CurrentUTCTime(&now); DateTime now; Platform_CurrentUTCTime(&now);
if (DateTime_MsBetween(&net_lastPacket, &now) >= 30 * 1000) { if (DateTime_MsBetween(&net_lastPacket, &now) >= 30 * 1000) {
CheckDisconnection(task.Interval); MPConnection_CheckDisconnection(task->Interval);
} }
if (ServerConnection_Disconnected) return; if (ServerConnection_Disconnected) return;
@ -365,16 +389,23 @@ void MPConnection_Tick(ScheduledTask* task) {
recvResult = Platform_SocketRead(net_socket, src, 4096 * 4, &modified); recvResult = Platform_SocketRead(net_socket, src, 4096 * 4, &modified);
net_readStream.Meta_Mem_Count += modified; net_readStream.Meta_Mem_Count += modified;
} }
if (recvResult != 0) { if (recvResult != 0) {
ErrorHandler.LogError("reading packets", ex); UInt8 msgBuffer[String_BufferSize(STRING_SIZE * 2)];
game.Disconnect("&eLost connection to the server", "I/O error when reading packets"); 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; return;
} }
while (net_readStream.Meta_Mem_Count > 0) { while (net_readStream.Meta_Mem_Count > 0) {
UInt8 opcode = net_readStream.Meta_Mem_Buffer[0]; UInt8 opcode = net_readStream.Meta_Mem_Buffer[0];
/* Workaround for older D3 servers which wrote one byte too many for HackControl packets */ /* 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"); Platform_LogConst("Skipping invalid HackControl byte from D3 server");
Stream_Skip(&net_readStream, 1); Stream_Skip(&net_readStream, 1);
@ -384,9 +415,7 @@ void MPConnection_Tick(ScheduledTask* task) {
continue; continue;
} }
if (opcode > net_maxHandledPacket) { if (opcode > net_maxHandledPacket) { ErrorHandler_Fail("Invalid opcode"); }
throw new InvalidOperationException("Invalid opcode: " + opcode);
}
if (net_readStream.Meta_Mem_Count < Net_PacketSizes[opcode]) break; if (net_readStream.Meta_Mem_Count < Net_PacketSizes[opcode]) break;
Stream_Skip(&net_readStream, 1); /* remove opcode */ Stream_Skip(&net_readStream, 1); /* remove opcode */
@ -394,13 +423,16 @@ void MPConnection_Tick(ScheduledTask* task) {
Net_Handler handler = Net_Handlers[opcode]; Net_Handler handler = Net_Handlers[opcode];
Platform_CurrentUTCTime(&net_lastPacket); Platform_CurrentUTCTime(&net_lastPacket);
if (handler == NULL) { if (handler == NULL) { ErrorHandler_Fail("Unsupported opcode"); }
throw new InvalidOperationException("Unsupported opcode: " + opcode);
}
handler(&net_readStream); 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 */ /* Network is ticked 60 times a second. We only send position updates 20 times a second */
if ((net_ticks % 3) == 0) { if ((net_ticks % 3) == 0) {
@ -434,17 +466,6 @@ void Net_SendPacket(void) {
net_writeStream.Meta_Mem_Count = sizeof(net_writeBuffer); 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_ReadStream(void) { return &net_readStream; }
Stream* MPConnection_WriteStream(void) { return &net_writeStream; } Stream* MPConnection_WriteStream(void) { return &net_writeStream; }
void ServerConnection_InitMultiplayer(void) { void ServerConnection_InitMultiplayer(void) {
@ -467,7 +488,7 @@ void MPConnection_OnNewMap(void) {
/* wipe all existing entity states */ /* wipe all existing entity states */
Int32 i; Int32 i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) { for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
classic.RemoveEntity((byte)i); Handlers_RemoveEntity((EntityID)i);
} }
} }

View File

@ -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 */ /* We use a statically allocated buffer initally, so can't realloc first time */
void* dst; void* dst;
void* cur = *buffer; void* cur = *buffer;
UInt32 curElems = *elems;
UInt32 curElems = *elems, newSize = (curElems + expandElems) * elemSize;
if (curElems <= defElems) { if (curElems <= defElems) {
dst = Platform_MemAlloc(newSize); dst = Platform_MemAlloc(curElems + expandElems, elemSize);
if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for StringsBuffer"); if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for StringsBuffer");
Platform_MemCpy(dst, cur, curElems * elemSize); Platform_MemCpy(dst, cur, curElems * elemSize);
} else { } else {
dst = Platform_MemRealloc(cur, newSize); dst = Platform_MemRealloc(cur, curElems + expandElems, elemSize);
if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for resizing StringsBuffer"); if (dst == NULL) ErrorHandler_Fail("Failed allocating memory for resizing StringsBuffer");
} }

View File

@ -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) { 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); Matrix_PerspectiveOffCenter(result, -c * aspect, c * aspect, -c, c, zNear, zFar);
} }

View File

@ -26,7 +26,7 @@ Real64 weather_accumulator;
Vector3I weather_lastPos; Vector3I weather_lastPos;
void WeatherRenderer_InitHeightmap(void) { 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) { if (Weather_Heightmap == NULL) {
ErrorHandler_Fail("WeatherRenderer - Failed to allocate heightmap"); ErrorHandler_Fail("WeatherRenderer - Failed to allocate heightmap");
} }

View File

@ -13,6 +13,7 @@
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
HDC hdc; HDC hdc;
HANDLE heap; HANDLE heap;
bool stopwatch_highResolution; bool stopwatch_highResolution;
@ -74,12 +75,14 @@ void Platform_Exit(ReturnCode code) {
ExitProcess(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 malloc(numBytes);
//return HeapAlloc(heap, 0, 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 realloc(mem, numBytes);
//return HeapReAlloc(heap, 0, mem, numBytes); //return HeapReAlloc(heap, 0, mem, numBytes);
} }
@ -439,5 +442,22 @@ ReturnCode Platform_SocketClose(void* socket) {
} }
ReturnCode Platform_SocketAvailable(void* socket, UInt32* available) { 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;
}
} }