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
|
// Determines the fixed amount of memory allocated to blocks
|
||||||
#define MAX_BLOCK_CHANGES 20000
|
#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).
|
// If defined, writes and reads world data to/from disk (or flash).
|
||||||
// This is a synchronous operation, and can cause performance issues if
|
// This is a synchronous operation, and can cause performance issues if
|
||||||
// frequent random disk access is slow. Data is still stored in and
|
// frequent random disk access is slow. Data is still stored in and
|
||||||
@@ -195,6 +199,13 @@ typedef struct {
|
|||||||
uint8_t block;
|
uint8_t block;
|
||||||
} BlockChange;
|
} BlockChange;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short x;
|
||||||
|
short z;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t awaitTicks;
|
||||||
|
} DeferredBlockUpdate;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -267,6 +278,11 @@ typedef struct {
|
|||||||
extern BlockChange block_changes[MAX_BLOCK_CHANGES];
|
extern BlockChange block_changes[MAX_BLOCK_CHANGES];
|
||||||
extern int block_changes_count;
|
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 PlayerData player_data[MAX_PLAYERS];
|
||||||
extern int player_data_count;
|
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 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 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 spawnMob (uint8_t type, short x, uint8_t y, short z, uint8_t health);
|
||||||
void interactEntity (int entity_id, int interactor_id);
|
void interactEntity (int entity_id, int interactor_id);
|
||||||
|
@@ -50,6 +50,11 @@ uint16_t client_count;
|
|||||||
BlockChange block_changes[MAX_BLOCK_CHANGES];
|
BlockChange block_changes[MAX_BLOCK_CHANGES];
|
||||||
int block_changes_count = 0;
|
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];
|
PlayerData player_data[MAX_PLAYERS];
|
||||||
int player_data_count = 0;
|
int player_data_count = 0;
|
||||||
|
|
||||||
|
@@ -595,6 +595,11 @@ int main () {
|
|||||||
// Check if it's time to yield to the idle task
|
// Check if it's time to yield to the idle task
|
||||||
task_yield();
|
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
|
// Attempt to accept a new connection
|
||||||
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||||
if (clients[i] != -1) continue;
|
if (clients[i] != -1) continue;
|
||||||
|
@@ -1143,6 +1143,39 @@ void playPickupAnimation (PlayerData *player, uint16_t item, double x, double y,
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
void handlePlayerAction (PlayerData *player, int action, short x, short y, short z) {
|
||||||
|
|
||||||
// Re-sync slot when player drops an item
|
// 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);
|
givePlayerItem(player, item, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update nearby fluids
|
// Update nearby blocks
|
||||||
uint8_t block_above = getBlockAt(x, y + 1, z);
|
uint8_t block_above = getBlockAt(x, y + 1, z);
|
||||||
#ifdef DO_FLUID_FLOW
|
processBlockUpdate(x, y + 1, z, block_above);
|
||||||
checkFluidUpdate(x, y + 1, z, block_above);
|
processBlockUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||||
checkFluidUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
processBlockUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||||
checkFluidUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
processBlockUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||||
checkFluidUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
processBlockUpdate(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t face) {
|
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;
|
if (*count == 0) *item = 0;
|
||||||
// Calculate fluid flow
|
// Calculate fluid flow
|
||||||
#ifdef DO_FLUID_FLOW
|
#ifdef DO_FLUID_FLOW
|
||||||
checkFluidUpdate(x, y + 1, z, getBlockAt(x, y + 1, z));
|
processBlockUpdate(x, y + 1, z, getBlockAt(x, y + 1, z));
|
||||||
checkFluidUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
processBlockUpdate(x - 1, y, z, getBlockAt(x - 1, y, z));
|
||||||
checkFluidUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
processBlockUpdate(x + 1, y, z, getBlockAt(x + 1, y, z));
|
||||||
checkFluidUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
processBlockUpdate(x, y, z - 1, getBlockAt(x, y, z - 1));
|
||||||
checkFluidUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
processBlockUpdate(x, y, z + 1, getBlockAt(x, y, z + 1));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1685,6 +1702,22 @@ void handleServerTick (int64_t time_since_last_tick) {
|
|||||||
*/
|
*/
|
||||||
if (rng_seed == 0) rng_seed = world_seed;
|
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
|
// Tick mob behavior
|
||||||
for (int i = 0; i < MAX_MOBS; i ++) {
|
for (int i = 0; i < MAX_MOBS; i ++) {
|
||||||
if (mob_data[i].type == 0) continue;
|
if (mob_data[i].type == 0) continue;
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
int64_t last_disk_sync_time = 0;
|
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
|
// Restores world data from disk, or writes world file if it doesn't exist
|
||||||
int initSerializer () {
|
int initSerializer () {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user