forked from EXTERNAL/bareiron
deferred block updates: falling sand
This commit is contained in:
@@ -74,6 +74,10 @@
|
||||
// Determines the fixed amount of memory allocated to blocks
|
||||
#define MAX_BLOCK_CHANGES 20000
|
||||
|
||||
// How many "deferred" (happen at a later time than triggered) block updates to store.
|
||||
// Determines the fixed amount of memory allocated to that list
|
||||
#define MAX_DEFERRED_BLOCK_UPDATES 64
|
||||
|
||||
// If defined, writes and reads world data to/from disk (or flash).
|
||||
// This is a synchronous operation, and can cause performance issues if
|
||||
// frequent random disk access is slow. Data is still stored in and
|
||||
@@ -195,6 +199,13 @@ typedef struct {
|
||||
uint8_t block;
|
||||
} BlockChange;
|
||||
|
||||
typedef struct {
|
||||
short x;
|
||||
short z;
|
||||
uint8_t y;
|
||||
uint8_t awaitTicks;
|
||||
} DeferredBlockUpdate;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
@@ -267,6 +278,11 @@ typedef struct {
|
||||
extern BlockChange block_changes[MAX_BLOCK_CHANGES];
|
||||
extern int block_changes_count;
|
||||
|
||||
extern DeferredBlockUpdate deferred_block_updates[MAX_DEFERRED_BLOCK_UPDATES];
|
||||
extern int deferred_block_updates_count;
|
||||
extern uint8_t is_processing_deferred_block_updates;
|
||||
extern uint8_t had_too_many_deferred_block_updates;
|
||||
|
||||
extern PlayerData player_data[MAX_PLAYERS];
|
||||
extern int player_data_count;
|
||||
|
||||
|
@@ -44,6 +44,8 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short
|
||||
void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t face);
|
||||
|
||||
void checkFluidUpdate (short x, uint8_t y, short z, uint8_t block);
|
||||
void processBlockUpdate (short x, uint8_t y, short z, uint8_t block);
|
||||
void deferBlockUpdate (short x, uint8_t y, short z, uint8_t awaitTicks);
|
||||
|
||||
void spawnMob (uint8_t type, short x, uint8_t y, short z, uint8_t health);
|
||||
void interactEntity (int entity_id, int interactor_id);
|
||||
|
@@ -50,6 +50,11 @@ uint16_t client_count;
|
||||
BlockChange block_changes[MAX_BLOCK_CHANGES];
|
||||
int block_changes_count = 0;
|
||||
|
||||
DeferredBlockUpdate deferred_block_updates[MAX_DEFERRED_BLOCK_UPDATES];
|
||||
int deferred_block_updates_count = 0;
|
||||
uint8_t is_processing_deferred_block_updates = 0;
|
||||
uint8_t had_too_many_deferred_block_updates = false;
|
||||
|
||||
PlayerData player_data[MAX_PLAYERS];
|
||||
int player_data_count = 0;
|
||||
|
||||
|
@@ -595,6 +595,11 @@ int main () {
|
||||
// Check if it's time to yield to the idle task
|
||||
task_yield();
|
||||
|
||||
if (had_too_many_deferred_block_updates) {
|
||||
printf("WARNING: Too many deferred block updates\n");
|
||||
had_too_many_deferred_block_updates = 0;
|
||||
}
|
||||
|
||||
// Attempt to accept a new connection
|
||||
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||
if (clients[i] != -1) continue;
|
||||
|
@@ -1143,6 +1143,39 @@ void playPickupAnimation (PlayerData *player, uint16_t item, double x, double y,
|
||||
}
|
||||
#endif
|
||||
|
||||
void processBlockUpdate (short x, uint8_t y, short z, uint8_t block) {
|
||||
#ifdef DO_FLUID_FLOW
|
||||
checkFluidUpdate(x, y, z, block);
|
||||
#endif
|
||||
|
||||
if (isColumnBlock(block) && y) {
|
||||
uint8_t below = getBlockAt(x, y - 1, z);
|
||||
// TODO: if below block breaks sand
|
||||
if (isReplaceableBlock(below)) {
|
||||
// TODO: drop item of below block
|
||||
makeBlockChange(x, y, z, 0);
|
||||
makeBlockChange(x, y - 1, z, 0);
|
||||
makeBlockChange(x, y - 1, z, block);
|
||||
// update this (now moved) block and the block above next tick
|
||||
deferBlockUpdate(x, y - 1, z, 0);
|
||||
deferBlockUpdate(x, y + 1, z, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deferBlockUpdate (short x, uint8_t y, short z, uint8_t awaitTicks) {
|
||||
if (deferred_block_updates_count == MAX_DEFERRED_BLOCK_UPDATES) {
|
||||
had_too_many_deferred_block_updates = true;
|
||||
return;
|
||||
}
|
||||
|
||||
DeferredBlockUpdate *u = &deferred_block_updates[deferred_block_updates_count ++];
|
||||
u->x = x;
|
||||
u->y = y;
|
||||
u->z = z;
|
||||
u->awaitTicks = awaitTicks + is_processing_deferred_block_updates;
|
||||
}
|
||||
|
||||
void handlePlayerAction (PlayerData *player, int action, short x, short y, short z) {
|
||||
|
||||
// Re-sync slot when player drops an item
|
||||
@@ -1192,29 +1225,13 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short
|
||||
givePlayerItem(player, item, 1);
|
||||
}
|
||||
|
||||
// Update nearby fluids
|
||||
// Update nearby blocks
|
||||
uint8_t block_above = getBlockAt(x, y + 1, z);
|
||||
#ifdef DO_FLUID_FLOW
|
||||
checkFluidUpdate(x, y + 1, z, block_above);
|
||||
checkFluidUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||
checkFluidUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||
checkFluidUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||
checkFluidUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
||||
#endif
|
||||
|
||||
// Check if any blocks above this should break, and if so,
|
||||
// iterate upward over all blocks in the column and break them
|
||||
uint8_t y_offset = 1;
|
||||
while (isColumnBlock(block_above)) {
|
||||
// Destroy the next block
|
||||
makeBlockChange(x, y + y_offset, z, 0);
|
||||
// Check for item drops *without a tool*
|
||||
uint16_t item = getMiningResult(0, block_above);
|
||||
if (item) givePlayerItem(player, item, 1);
|
||||
// Select the next block in the column
|
||||
y_offset ++;
|
||||
block_above = getBlockAt(x, y + y_offset, z);
|
||||
}
|
||||
processBlockUpdate(x, y + 1, z, block_above);
|
||||
processBlockUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||
processBlockUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||
processBlockUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||
processBlockUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
||||
}
|
||||
|
||||
void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t face) {
|
||||
@@ -1361,11 +1378,11 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
||||
if (*count == 0) *item = 0;
|
||||
// Calculate fluid flow
|
||||
#ifdef DO_FLUID_FLOW
|
||||
checkFluidUpdate(x, y + 1, z, getBlockAt(x, y + 1, z));
|
||||
checkFluidUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||
checkFluidUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||
checkFluidUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||
checkFluidUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
||||
processBlockUpdate(x, y + 1, z, getBlockAt(x, y + 1, z));
|
||||
processBlockUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||
processBlockUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||
processBlockUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||
processBlockUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1685,6 +1702,22 @@ void handleServerTick (int64_t time_since_last_tick) {
|
||||
*/
|
||||
if (rng_seed == 0) rng_seed = world_seed;
|
||||
|
||||
// block updates might add more deferred block updates,
|
||||
// so we temporarily make all new block updates add one more tick to the defer tick counter
|
||||
is_processing_deferred_block_updates = 1;
|
||||
int next_update_idx = 0;
|
||||
for (int i = 0; i < deferred_block_updates_count; i ++) {
|
||||
DeferredBlockUpdate *u = &deferred_block_updates[i];
|
||||
if (u->awaitTicks) {
|
||||
u->awaitTicks --;
|
||||
deferred_block_updates[next_update_idx ++] = *u;
|
||||
} else {
|
||||
processBlockUpdate(u->x, u->y, u->z, getBlockAt(u->x, u->y, u->z));
|
||||
}
|
||||
}
|
||||
deferred_block_updates_count = next_update_idx;
|
||||
is_processing_deferred_block_updates = 0;
|
||||
|
||||
// Tick mob behavior
|
||||
for (int i = 0; i < MAX_MOBS; i ++) {
|
||||
if (mob_data[i].type == 0) continue;
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
int64_t last_disk_sync_time = 0;
|
||||
|
||||
// TODO: store deferred block updates
|
||||
|
||||
// Restores world data from disk, or writes world file if it doesn't exist
|
||||
int initSerializer () {
|
||||
|
||||
|
Reference in New Issue
Block a user