From 04c3683ba1d493eb815aa685de7f3f317a766fb9 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 27 Nov 2018 18:36:57 +1100 Subject: [PATCH] Fix game being stuffed after getting disconnected --- src/BlockPhysics.c | 12 ++++---- src/BlockPhysics.h | 1 + src/Chat.c | 4 +-- src/Core.h | 2 +- src/Entity.c | 2 +- src/Game.c | 15 +++++++--- src/Game.h | 7 ++++- src/InputHandler.c | 6 ++-- src/Model.h | 2 -- src/Screens.c | 2 +- src/ServerConnection.c | 66 +++++++++++++++++++++--------------------- src/ServerConnection.h | 33 +++++++++++++++++---- src/World.c | 10 +++---- src/World.h | 10 ++++--- 14 files changed, 103 insertions(+), 69 deletions(-) diff --git a/src/BlockPhysics.c b/src/BlockPhysics.c index 2afdcc5d9..2f47767a1 100644 --- a/src/BlockPhysics.c +++ b/src/BlockPhysics.c @@ -144,16 +144,16 @@ static bool Physics_IsEdgeWater(int x, int y, int z) { } -static void Physics_BlockChanged(void* obj, Vector3I p, BlockID old, BlockID now) { +void Physics_OnBlockChanged(int x, int y, int z, BlockID old, BlockID now) { PhysicsHandler handler; int index; if (!Physics_Enabled) return; - if (now == BLOCK_AIR && Physics_IsEdgeWater(p.X, p.Y, p.Z)) { + if (now == BLOCK_AIR && Physics_IsEdgeWater(x, y, z)) { now = BLOCK_STILL_WATER; - Game_UpdateBlock(p.X, p.Y, p.Z, BLOCK_STILL_WATER); + Game_UpdateBlock(x, y, z, BLOCK_STILL_WATER); } - index = World_Pack(p.X, p.Y, p.Z); + index = World_Pack(x, y, z); if (now == BLOCK_AIR) { handler = Physics_OnDelete[old]; @@ -162,7 +162,7 @@ static void Physics_BlockChanged(void* obj, Vector3I p, BlockID old, BlockID now handler = Physics_OnPlace[now]; if (handler) handler(index, now); } - Physics_ActivateNeighbours(p.X, p.Y, p.Z, index); + Physics_ActivateNeighbours(x, y, z, index); } static void Physics_TickRandomBlocks(void) { @@ -515,7 +515,6 @@ static void Physics_HandleTnt(int index, BlockID block) { void Physics_Init(void) { Event_RegisterVoid(&WorldEvents_MapLoaded, NULL, Physics_OnNewMapLoaded); - Event_RegisterBlock(&UserEvents_BlockChanged, NULL, Physics_BlockChanged); Physics_Enabled = Options_GetBool(OPT_BLOCK_PHYSICS, true); TickQueue_Init(&physics_lavaQ); TickQueue_Init(&physics_waterQ); @@ -559,7 +558,6 @@ void Physics_Init(void) { void Physics_Free(void) { Event_UnregisterVoid(&WorldEvents_MapLoaded, NULL, Physics_OnNewMapLoaded); - Event_UnregisterBlock(&UserEvents_BlockChanged, NULL, Physics_BlockChanged); } void Physics_Tick(void) { diff --git a/src/BlockPhysics.h b/src/BlockPhysics.h index 3c0987d64..09d31c6f2 100644 --- a/src/BlockPhysics.h +++ b/src/BlockPhysics.h @@ -7,6 +7,7 @@ extern bool Physics_Enabled; void Physics_SetEnabled(bool enabled); +void Physics_OnBlockChanged(int x, int y, int z, BlockID old, BlockID now); void Physics_Init(void); void Physics_Free(void); void Physics_Tick(void); diff --git a/src/Chat.c b/src/Chat.c index 905f74cd4..937cfb229 100644 --- a/src/Chat.c +++ b/src/Chat.c @@ -461,7 +461,7 @@ static void CuboidCommand_DoCuboid(void) { for (y = min.Y; y <= max.Y; y++) { for (z = min.Z; z <= max.Z; z++) { for (x = min.X; x <= max.X; x++) { - Game_UpdateBlock(x, y, z, toPlace); + Game_ChangeBlock(x, y, z, toPlace); } } } @@ -566,7 +566,7 @@ void Chat_Send(const String* text, bool logUsage) { if (Commands_IsCommandPrefix(text)) { Commands_Execute(text); } else { - ServerConnection_SendChat(text); + ServerConnection.SendChat(text); } } diff --git a/src/Core.h b/src/Core.h index fbd14b37b..da5005918 100644 --- a/src/Core.h +++ b/src/Core.h @@ -21,7 +21,7 @@ typedef signed __int64 int64_t; #define CC_INLINE inline #define CC_NOINLINE __declspec(noinline) -#define CC_ALIGN_HINT(x) /* TODO: Why does this cause LNK2005 errors */ +#define CC_ALIGN_HINT(x) __declspec(align(x)) #ifndef CC_EXPORT #define CC_EXPORT __declspec(dllexport, noinline) #endif diff --git a/src/Entity.c b/src/Entity.c index e3902035a..6cd2e45a9 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -940,7 +940,7 @@ static void LocalPlayer_DoRespawn(void) { if (World_IsValidPos_3I(pos)) { AABB_Make(&bb, &spawn, &p->Base.Size); for (y = pos.Y; y <= World_Height; y++) { - spawnY = Respawn_HighestFreeY(&bb); + spawnY = Respawn_HighestSolidY(&bb); if (spawnY == RESPAWN_NOT_FOUND) { block = World_GetPhysicsBlock(pos.X, y, pos.Z); diff --git a/src/Game.c b/src/Game.c index 6c60eadbc..d5eab3de5 100644 --- a/src/Game.c +++ b/src/Game.c @@ -194,6 +194,7 @@ void Game_Disconnect(const String* title, const String* reason) { Event_RaiseVoid(&WorldEvents_NewMap); Gui_FreeActive(); Gui_SetActive(DisconnectScreen_MakeInstance(title, reason)); + Game_Reset(); } void Game_Reset(void) { @@ -211,13 +212,13 @@ void Game_Reset(void) { void Game_UpdateBlock(int x, int y, int z, BlockID block) { struct ChunkInfo* chunk; int cx = x >> 4, cy = y >> 4, cz = z >> 4; - BlockID oldBlock = World_GetBlock(x, y, z); + BlockID old = World_GetBlock(x, y, z); World_SetBlock(x, y, z, block); if (Weather_Heightmap) { - EnvRenderer_OnBlockChanged(x, y, z, oldBlock, block); + EnvRenderer_OnBlockChanged(x, y, z, old, block); } - Lighting_OnBlockChanged(x, y, z, oldBlock, block); + Lighting_OnBlockChanged(x, y, z, old, block); /* Refresh the chunk the block was located in. */ chunk = MapRenderer_GetChunk(cx, cy, cz); @@ -225,6 +226,12 @@ void Game_UpdateBlock(int x, int y, int z, BlockID block) { MapRenderer_RefreshChunk(cx, cy, cz); } +void Game_ChangeBlock(int x, int y, int z, BlockID block) { + BlockID old = World_GetBlock(x, y, z); + Game_UpdateBlock(x, y, z, block); + ServerConnection.SendBlock(x, y, z, old, block); +} + bool Game_CanPick(BlockID block) { if (Block_Draw[block] == DRAW_GAS) return false; if (Block_Draw[block] == DRAW_SPRITE) return true; @@ -526,7 +533,7 @@ void Game_Load(void) { Gui_FreeActive(); Gui_SetActive(LoadingScreen_MakeInstance(&title, &String_Empty)); - ServerConnection_BeginConnect(); + ServerConnection.BeginConnect(); } void Game_SetFpsLimit(enum FpsLimit method) { diff --git a/src/Game.h b/src/Game.h index e45150628..c4256755b 100644 --- a/src/Game.h +++ b/src/Game.h @@ -82,7 +82,12 @@ void Game_UserSetViewDistance(int distance); void Game_UpdateProjection(void); void Game_Disconnect(const String* title, const String* reason); void Game_Reset(void); -void Game_UpdateBlock(int x, int y, int z, BlockID block); +/* Sets the block in the map at the given coordinates, then updates state associated with the block. */ +/* (updating state means recalculating light, redrawing chunk block is in, etc) */ +/* NOTE: This does NOT notify the server, use Game_ChangeBlock for that. */ +CC_EXPORT void Game_UpdateBlock(int x, int y, int z, BlockID block); +/* Calls Game_UpdateBlock, then sends the block change to the server. */ +CC_EXPORT void Game_ChangeBlock(int x, int y, int z, BlockID block); bool Game_CanPick(BlockID block); bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, const String* file, uint8_t* skinType); bool Game_ValidateBitmap(const String* file, Bitmap* bmp); diff --git a/src/InputHandler.c b/src/InputHandler.c index 4bb01b5b5..d6c97cdfd 100644 --- a/src/InputHandler.c +++ b/src/InputHandler.c @@ -44,7 +44,7 @@ static void InputHandler_ButtonStateUpdate(MouseButton button, bool pressed) { } input_buttonsDown[button] = pressed; - ServerConnection_SendPlayerClick(button, pressed, + ServerConnection.SendPlayerClick(button, pressed, (EntityID)input_pickingId, &Game_SelectedPos); } @@ -347,7 +347,7 @@ void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right) old = World_GetBlock(p.X, p.Y, p.Z); if (Block_Draw[old] == DRAW_GAS || !Block_CanDelete[old]) return; - Game_UpdateBlock(p.X, p.Y, p.Z, BLOCK_AIR); + Game_ChangeBlock(p.X, p.Y, p.Z, BLOCK_AIR); Event_RaiseBlock(&UserEvents_BlockChanged, p, old, BLOCK_AIR); } else if (right) { p = Game_SelectedPos.TranslatedPos; @@ -362,7 +362,7 @@ void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right) if (Block_Draw[block] == DRAW_GAS && Block_Draw[old] != DRAW_GAS) return; if (!InputHandler_CheckIsFree(block)) return; - Game_UpdateBlock(p.X, p.Y, p.Z, block); + Game_ChangeBlock(p.X, p.Y, p.Z, block); Event_RaiseBlock(&UserEvents_BlockChanged, p, old, block); } else if (middle) { p = Game_SelectedPos.BlockPos; diff --git a/src/Model.h b/src/Model.h index 349080a89..efc32a9b9 100644 --- a/src/Model.h +++ b/src/Model.h @@ -106,8 +106,6 @@ extern GfxResourceID Model_Vb; extern VertexP3fT2fC4b Model_Vertices[MODEL_MAX_VERTICES]; extern struct Model* Human_ModelPtr; -void Models_Init(void); -void Models_Free(void); /* Returns pointer to model whose name caselessly matches given name. */ CC_EXPORT struct Model* Model_Get(const String* name); /* Returns index of cached texture whose name caselessly matches given name. */ diff --git a/src/Screens.c b/src/Screens.c index 54f1df7bb..dab50deb5 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -1521,7 +1521,7 @@ static bool DisconnectScreen_MouseDown(void* screen, int x, int y, MouseButton b Gui_FreeActive(); Gui_SetActive(LoadingScreen_MakeInstance(&title, &String_Empty)); - ServerConnection_BeginConnect(); + ServerConnection.BeginConnect(); } return true; } diff --git a/src/ServerConnection.c b/src/ServerConnection.c index 3025dd4cd..9d4076fa2 100644 --- a/src/ServerConnection.c +++ b/src/ServerConnection.c @@ -28,17 +28,12 @@ static char server_motdBuffer[STRING_SIZE]; static char server_appBuffer[STRING_SIZE]; static int server_ticks; +struct ServerConnectionFuncs ServerConnection; bool ServerConnection_IsSinglePlayer, ServerConnection_Disconnected; String ServerConnection_ServerName = String_FromArray(server_nameBuffer); String ServerConnection_ServerMOTD = String_FromArray(server_motdBuffer); String ServerConnection_AppName = String_FromArray(server_appBuffer); -void (*ServerConnection_BeginConnect)(void); -void (*ServerConnection_SendChat)(const String* text); -void (*ServerConnection_SendPosition)(Vector3 pos, float rotY, float headX); -void (*ServerConnection_SendPlayerClick)(MouseButton button, bool isDown, EntityID targetId, struct PickedPos* pos); -void (*ServerConnection_Tick)(struct ScheduledTask* task); - uint8_t* ServerConnection_WriteBuffer; bool ServerConnection_SupportsExtPlayerList, ServerConnection_SupportsPlayerClick; bool ServerConnection_SupportsPartialMessages, ServerConnection_SupportsFullCP437; @@ -205,6 +200,10 @@ static void SPConnection_AddPart(const String* text) { Chat_Add(&tmp); } +static void SPConnection_SendBlock(int x, int y, int z, BlockID old, BlockID now) { + Physics_OnBlockChanged(x, y, z, old, now); +} + static void SPConnection_SendChat(const String* text) { String left, part; if (!text->length) return; @@ -232,19 +231,21 @@ static void SPConnection_Tick(struct ScheduledTask* task) { server_ticks++; } +static struct ServerConnectionFuncs SPConnection = { + SPConnection_BeginConnect, SPConnection_Tick, + SPConnection_SendBlock, SPConnection_SendChat, + SPConnection_SendPosition, SPConnection_SendPlayerClick +}; + static void SPConnection_Init(void) { ServerConnection_ResetState(); Physics_Init(); + ServerConnection_SupportsFullCP437 = !Game_ClassicMode; ServerConnection_SupportsPartialMessages = true; ServerConnection_IsSinglePlayer = true; - ServerConnection_BeginConnect = SPConnection_BeginConnect; - ServerConnection_SendChat = SPConnection_SendChat; - ServerConnection_SendPosition = SPConnection_SendPosition; - ServerConnection_SendPlayerClick = SPConnection_SendPlayerClick; - ServerConnection_Tick = SPConnection_Tick; - + ServerConnection = SPConnection; ServerConnection_WriteBuffer = NULL; } @@ -269,16 +270,6 @@ static bool net_connecting; static TimeMS net_connectTimeout; #define NET_TIMEOUT_MS (15 * 1000) -static void MPConnection_BlockChanged(void* obj, Vector3I p, BlockID old, BlockID now) { - if (now == BLOCK_AIR) { - now = Inventory_SelectedBlock; - Classic_WriteSetBlock(p.X, p.Y, p.Z, false, now); - } else { - Classic_WriteSetBlock(p.X, p.Y, p.Z, true, now); - } - Net_SendPacket(); -} - static void ServerConnection_Free(void); static void MPConnection_FinishConnect(void) { net_connecting = false; @@ -334,7 +325,6 @@ static void MPConnection_TickConnect(void) { static void MPConnection_BeginConnect(void) { ReturnCode res; - Event_RegisterBlock(&UserEvents_BlockChanged, NULL, MPConnection_BlockChanged); Socket_Create(&net_socket); ServerConnection_Disconnected = false; @@ -348,6 +338,16 @@ static void MPConnection_BeginConnect(void) { } } +static void MPConnection_SendBlock(int x, int y, int z, BlockID old, BlockID now) { + if (now == BLOCK_AIR) { + now = Inventory_SelectedBlock; + Classic_WriteSetBlock(x, y, z, false, now); + } else { + Classic_WriteSetBlock(x, y, z, true, now); + } + Net_SendPacket(); +} + static void MPConnection_SendChat(const String* text) { String left, part; if (!text->length || net_connecting) return; @@ -514,17 +514,18 @@ void Net_SendPacket(void) { } } +static struct ServerConnectionFuncs MPConnection = { + MPConnection_BeginConnect, MPConnection_Tick, + MPConnection_SendBlock, MPConnection_SendChat, + MPConnection_SendPosition, MPConnection_SendPlayerClick +}; + static void MPConnection_Init(void) { ServerConnection_ResetState(); ServerConnection_IsSinglePlayer = false; - ServerConnection_BeginConnect = MPConnection_BeginConnect; - ServerConnection_SendChat = MPConnection_SendChat; - ServerConnection_SendPosition = MPConnection_SendPosition; - ServerConnection_SendPlayerClick = MPConnection_SendPlayerClick; - ServerConnection_Tick = MPConnection_Tick; - - net_readCurrent = net_readBuffer; + ServerConnection = MPConnection; + net_readCurrent = net_readBuffer; ServerConnection_WriteBuffer = net_writeBuffer; } @@ -561,8 +562,8 @@ static void ServerConnection_Init(void) { MPConnection_Init(); } - Gfx_LostContextFunction = ServerConnection_Tick; - ScheduledTask_Add(GAME_NET_TICKS, ServerConnection_Tick); + Gfx_LostContextFunction = ServerConnection.Tick; + ScheduledTask_Add(GAME_NET_TICKS, ServerConnection.Tick); String_AppendConst(&ServerConnection_AppName, PROGRAM_APP_NAME); } @@ -571,7 +572,6 @@ static void ServerConnection_Free(void) { Physics_Free(); } else { if (ServerConnection_Disconnected) return; - Event_UnregisterBlock(&UserEvents_BlockChanged, NULL, MPConnection_BlockChanged); Socket_Close(net_socket); ServerConnection_Disconnected = true; } diff --git a/src/ServerConnection.h b/src/ServerConnection.h index ae014ef74..16162ff25 100644 --- a/src/ServerConnection.h +++ b/src/ServerConnection.h @@ -46,22 +46,45 @@ int PingList_NextPingData(void); void PingList_Update(int data); int PingList_AveragePingMs(void); +/* Whether the player is connected to singleplayer/loopback server. */ extern bool ServerConnection_IsSinglePlayer; +/* Whether the player has been disconnected from the server. */ extern bool ServerConnection_Disconnected; +/* The current name of the server. (Shows as first line when loading) */ extern String ServerConnection_ServerName; +/* The current MOTD of the server. (Shows as second line when loading) */ extern String ServerConnection_ServerMOTD; +/* The software name the client identifies itself as being to the server. */ +/* By default this is the same as PROGRAM_APP_NAME */ extern String ServerConnection_AppName; -extern void (*ServerConnection_BeginConnect)(void); -extern void (*ServerConnection_SendChat)(const String* text); -extern void (*ServerConnection_SendPosition)(Vector3 pos, float rotY, float headX); -extern void (*ServerConnection_SendPlayerClick)(MouseButton button, bool isDown, EntityID targetId, struct PickedPos* pos); -extern void (*ServerConnection_Tick)(struct ScheduledTask* task); +struct ServerConnectionFuncs { + /* Begins connecting to the server. */ + /* NOTE: Usually asynchronous, but not always. */ + void (*BeginConnect)(void); + /* Ticks state of the server. */ + void (*Tick)(struct ScheduledTask* task); + /* Sends a block update to the server. */ + void (*SendBlock)(int x, int y, int z, BlockID old, BlockID now); + /* Sends a chat message to the server. */ + void (*SendChat)(const String* text); + /* Sends a position update to the server. */ + void (*SendPosition)(Vector3 pos, float rotY, float headX); + /* Sends a PlayerClick packet to the server. */ + void (*SendPlayerClick)(MouseButton button, bool isDown, EntityID targetId, struct PickedPos* pos); +}; + +/* Currently active connection to a server. */ +extern struct ServerConnectionFuncs ServerConnection; extern uint8_t* ServerConnection_WriteBuffer; +/* Whether the server supports separate tab list from entities in world. */ extern bool ServerConnection_SupportsExtPlayerList; +/* Whether the server supports packet with detailed info on mouse clicks. */ extern bool ServerConnection_SupportsPlayerClick; +/* Whether the server supports combining multiple chat packets into one. */ extern bool ServerConnection_SupportsPartialMessages; +/* Whether the server supports all of code page 437, not just ASCII. */ extern bool ServerConnection_SupportsFullCP437; void ServerConnection_RetrieveTexturePack(const String* url); diff --git a/src/World.c b/src/World.c index 5283cf9b3..23f1ecd3f 100644 --- a/src/World.c +++ b/src/World.c @@ -253,11 +253,11 @@ void Env_SetShadowCol(PackedCol col) { /*########################################################################################################################* *-------------------------------------------------------Respawning--------------------------------------------------------* *#########################################################################################################################*/ -float Respawn_HighestFreeY(struct AABB* bb) { +float Respawn_HighestSolidY(struct AABB* bb) { int minX = Math_Floor(bb->Min.X), maxX = Math_Floor(bb->Max.X); int minY = Math_Floor(bb->Min.Y), maxY = Math_Floor(bb->Max.Y); int minZ = Math_Floor(bb->Min.Z), maxZ = Math_Floor(bb->Max.Z); - float spawnY = RESPAWN_NOT_FOUND; + float highestY = RESPAWN_NOT_FOUND; BlockID block; struct AABB blockBB; @@ -274,11 +274,11 @@ float Respawn_HighestFreeY(struct AABB* bb) { if (Block_Collide[block] != COLLIDE_SOLID) continue; if (!AABB_Intersects(bb, &blockBB)) continue; - if (blockBB.Max.Y > spawnY) spawnY = blockBB.Max.Y; + if (blockBB.Max.Y > highestY) highestY = blockBB.Max.Y; } } } - return spawnY; + return highestY; } Vector3 Respawn_FindSpawnPosition(float x, float z, Vector3 modelSize) { @@ -292,7 +292,7 @@ Vector3 Respawn_FindSpawnPosition(float x, float z, Vector3 modelSize) { spawn.Y = 0.0f; for (y = World_Height; y >= 0; y--) { - highestY = Respawn_HighestFreeY(&bb); + highestY = Respawn_HighestSolidY(&bb); if (highestY != RESPAWN_NOT_FOUND) { spawn.Y = highestY; break; } diff --git a/src/World.h b/src/World.h index c1f9efa25..fd20b436d 100644 --- a/src/World.h +++ b/src/World.h @@ -129,9 +129,11 @@ CC_EXPORT void Env_SetSunCol(PackedCol col); CC_EXPORT void Env_SetShadowCol(PackedCol col); #define RESPAWN_NOT_FOUND -100000.0f -/* Finds the highest free Y coordinate in the given bounding box */ -float Respawn_HighestFreeY(struct AABB* bb); -/* Finds a suitable spawn position for the entity. */ -/* Works by iterating downwards from top of world until ground is found. */ +/* Finds the highest Y coordinate of any solid block that intersects the given bounding box */ +/* So essentially, means max(Y + Block_MaxBB[block].Y) over all solid blocks the AABB touches */ +/* Returns RESPAWN_NOT_FOUND when no intersecting solid blocks are found. */ +float Respawn_HighestSolidY(struct AABB* bb); +/* Finds a suitable initial spawn position for the entity. */ +/* Works by iterating downwards from top of world until solid ground is found. */ Vector3 Respawn_FindSpawnPosition(float x, float z, Vector3 modelSize); #endif