From aa1334db9e560e08c7bd0b5d653e1a8c736b6b15 Mon Sep 17 00:00:00 2001 From: p2r3 Date: Tue, 26 Aug 2025 16:07:43 +0300 Subject: [PATCH] make event timing independent of tickrate --- include/globals.h | 5 +++-- src/main.c | 1 + src/procedures.c | 26 +++++++++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/globals.h b/include/globals.h index 3bb3502..efc8f6f 100644 --- a/include/globals.h +++ b/include/globals.h @@ -31,8 +31,7 @@ // Time between server ticks in microseconds (default = 1s) #define TIME_BETWEEN_TICKS 1000000 // Calculated from TIME_BETWEEN_TICKS -#define TICKS_PER_SECOND (1000000 / TIME_BETWEEN_TICKS) -#define TICKS_TO_EAT (unsigned int)(1.6f * TICKS_PER_SECOND) +#define TICKS_PER_SECOND ((float)1000000 / TIME_BETWEEN_TICKS) // How many visited chunks to "remember" // The server will not re-send chunks that the player has recently been in #define VISITED_HISTORY 4 @@ -114,6 +113,8 @@ typedef struct { typedef struct { uint8_t type; short x; + // When the mob is dead (health is 0), the Y coordinate acts + // as a timer for deleting and deallocating the mob uint8_t y; short z; // Lower 5 bits: health diff --git a/src/main.c b/src/main.c index 39462ef..3c881e0 100644 --- a/src/main.c +++ b/src/main.c @@ -98,6 +98,7 @@ void handlePacket (int client_fd, int length, int packet_id) { // For more info on the arguments, see the spawnMob function for (int i = 0; i < MAX_MOBS; i ++) { if (mob_data[i].type == 0) continue; + if ((mob_data[i].data & 31) == 0) continue; sc_spawnEntity( client_fd, 65536 + i, recv_buffer, mob_data[i].type, mob_data[i].x, mob_data[i].y, mob_data[i].z, diff --git a/src/procedures.c b/src/procedures.c index be28a0e..731bc72 100644 --- a/src/procedures.c +++ b/src/procedures.c @@ -842,6 +842,7 @@ void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t da else if (held_item == I_netherite_sword) damage *= 8; // Enable attack cooldown player->flags |= 0x01; + player->flagval_8 = 0; } // Whether this attack caused the target entity to die @@ -859,6 +860,7 @@ void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t da uint8_t mob_health = mob->data & 31; if (mob_health <= damage) { mob->data -= mob_health; + mob->y = 0; entity_died = true; // Handle mob drops if (attacker_id < 65536) switch (mob->type) { @@ -896,10 +898,15 @@ void handleServerTick (int64_t time_since_last_tick) { sc_keepAlive(player_data[i].client_fd); sc_updateTime(player_data[i].client_fd, world_time); // Reset player attack cooldown - player_data[i].flags &= ~0x01; + if (player_data[i].flags & 0x01) { + if (player_data[i].flagval_8 > (unsigned int)(0.6f * TICKS_PER_SECOND)) { + player_data[i].flags &= ~0x01; + player_data[i].flagval_8 = 0; + } else player_data[i].flagval_8 ++; + } // Handle eating animation if (player_data[i].flags & 0x10) { - if (player_data[i].flagval_16 >= TICKS_TO_EAT) { + if (player_data[i].flagval_16 >= (unsigned int)(1.6f * TICKS_PER_SECOND)) { handlePlayerEating(&player_data[i], false); player_data[i].flags &= ~0x10; player_data[i].flagval_16 = 0; @@ -930,8 +937,12 @@ void handleServerTick (int64_t time_since_last_tick) { for (int i = 0; i < MAX_MOBS; i ++) { if (mob_data[i].type == 0) continue; - // Mob has died, deallocate it + // Handle deallocation on mob death if ((mob_data[i].data & 31) == 0) { + if (mob_data[i].y < (unsigned int)TICKS_PER_SECOND) { + mob_data[i].y ++; + continue; + } mob_data[i].type = 0; for (int j = 0; j < MAX_PLAYERS; j ++) { if (player_data[j].client_fd == -1) continue; @@ -952,8 +963,13 @@ void handleServerTick (int64_t time_since_last_tick) { uint32_t r = fast_rand(); - // Skip 25% of passive mob ticks randomly - if (passive && (r & 3)) continue; + if (passive) { + // Update passive mobs once per 4 seconds on average + if (r % (4 * (unsigned int)TICKS_PER_SECOND)) continue; + } else { + // Update hostile mobs once per second on average + if (r % (unsigned int)TICKS_PER_SECOND) continue; + } // Find the player closest to this mob PlayerData* closest_player;