From ecaa62da69ad5fb0cd360b77b52e15158d21159e Mon Sep 17 00:00:00 2001 From: p2r3 Date: Fri, 29 Aug 2025 15:57:38 +0300 Subject: [PATCH] explicitly handle running out of block changes --- include/procedures.h | 2 +- src/main.c | 1 + src/procedures.c | 47 +++++++++++++++++++++++++++++++++++--------- src/worldgen.c | 1 + 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/include/procedures.h b/include/procedures.h index c775bdc..361d033 100644 --- a/include/procedures.h +++ b/include/procedures.h @@ -22,7 +22,7 @@ uint8_t serverSlotToClientSlot (int window_id, uint8_t slot); uint8_t clientSlotToServerSlot (int window_id, uint8_t slot); uint8_t getBlockChange (short x, uint8_t y, short z); -void makeBlockChange (short x, uint8_t y, short z, uint8_t block); +uint8_t makeBlockChange (short x, uint8_t y, short z, uint8_t block); uint8_t isInstantlyMined (PlayerData *player, uint8_t block); uint8_t isColumnBlock (uint8_t block); diff --git a/src/main.c b/src/main.c index ecc4b8a..6d7188b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/src/procedures.c b/src/procedures.c index 2982893..94d8c86 100644 --- a/src/procedures.c +++ b/src/procedures.c @@ -1,4 +1,5 @@ #include +#include #include #include "globals.h" @@ -316,13 +317,30 @@ uint8_t getBlockChange (short x, uint8_t y, short z) { return 0xFF; } -void makeBlockChange (short x, uint8_t y, short z, uint8_t block) { +// Handle running out of memory for new block changes +void failBlockChange (short x, uint8_t y, short z, uint8_t block) { + + // Get previous block at this location + uint8_t before = getBlockAt(x, y, z); + + // Broadcast a new update to all players + for (int i = 0; i < MAX_PLAYERS; i ++) { + if (player_data[i].client_fd == -1) continue; + if (player_data[i].flags & 0x20) continue; + // Reset the block they tried to change + sc_blockUpdate(player_data[i].client_fd, x, y, z, before); + // Broadcast a chat message warning about the limit + sc_systemChat(player_data[i].client_fd, "Block changes limit exceeded. Restore original terrain to continue.", 67); + } + +} + +uint8_t makeBlockChange (short x, uint8_t y, short z, uint8_t block) { // Transmit block update to all in-game clients for (int i = 0; i < MAX_PLAYERS; i ++) { if (player_data[i].client_fd == -1) continue; if (player_data[i].flags & 0x20) continue; - if (getClientState(player_data[i].client_fd) != STATE_PLAY) continue; sc_blockUpdate(player_data[i].client_fd, x, y, z, block); } @@ -365,12 +383,13 @@ void makeBlockChange (short x, uint8_t y, short z, uint8_t block) { #endif if (is_base_block) block_changes[i].block = 0xFF; else block_changes[i].block = block; - return writeBlockChangesToDisk(i, i); + writeBlockChangesToDisk(i, i); + return 0; } } // Don't create a new entry if it contains the base terrain block - if (is_base_block) return; + if (is_base_block) return 0; #ifdef ALLOW_CHESTS if (block == B_chest) { @@ -403,12 +422,20 @@ void makeBlockChange (short x, uint8_t y, short z, uint8_t block) { } // Write changes to disk (if applicable) writeBlockChangesToDisk(last_real_entry + 1, last_real_entry + 15); - break; + return 0; } - return; + // If we're here, no changes were made + failBlockChange(x, y, z, block); + return 1; } #endif + // Handle running out of memory for new block changes + if (first_gap == MAX_BLOCK_CHANGES) { + failBlockChange(x, y, z, block); + return 1; + } + // Fall back to storing the change at the first possible gap block_changes[first_gap].x = x; block_changes[first_gap].y = y; @@ -421,6 +448,7 @@ void makeBlockChange (short x, uint8_t y, short z, uint8_t block) { block_changes_count ++; } + return 0; } // Returns the result of mining a block, taking into account the block type and tools @@ -837,7 +865,8 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short // If this is a "start mining" packet, the block must be instamine if (action == 0 && !isInstantlyMined(player, block)) return; - makeBlockChange(x, y, z, 0); + // Don't continue if the block change failed + if (makeBlockChange(x, y, z, 0)) return; uint16_t held_item = player->inventory_items[player->hotbar]; uint16_t item = getMiningResult(held_item, block); @@ -989,12 +1018,12 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t isReplaceableBlock(getBlockAt(x, y, z)) && (!isColumnBlock(block) || getBlockAt(x, y - 1, z) != B_air) ) { + // Apply server-side block change + if (makeBlockChange(x, y, z, block)) return; // Decrease item amount in selected slot *count -= 1; // Clear item id in slot if amount is zero if (*count == 0) *item = 0; - // Apply server-side block change - makeBlockChange(x, y, z, block); // Calculate fluid flow #ifdef DO_FLUID_FLOW checkFluidUpdate(x, y + 1, z, getBlockAt(x, y + 1, z)); diff --git a/src/worldgen.c b/src/worldgen.c index 2468034..1614138 100644 --- a/src/worldgen.c +++ b/src/worldgen.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "globals.h"