forked from EXTERNAL/bareiron
implement hunger system
This commit is contained in:
@@ -30,6 +30,9 @@
|
|||||||
#define VIEW_DISTANCE 2
|
#define VIEW_DISTANCE 2
|
||||||
// Time between server ticks in microseconds (default = 1s)
|
// Time between server ticks in microseconds (default = 1s)
|
||||||
#define TIME_BETWEEN_TICKS 1000000
|
#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)
|
||||||
// How many visited chunks to "remember"
|
// How many visited chunks to "remember"
|
||||||
// The server will not re-send chunks that the player has recently been in
|
// The server will not re-send chunks that the player has recently been in
|
||||||
#define VISITED_HISTORY 4
|
#define VISITED_HISTORY 4
|
||||||
@@ -88,16 +91,23 @@ typedef struct {
|
|||||||
uint8_t grounded_y;
|
uint8_t grounded_y;
|
||||||
uint8_t health;
|
uint8_t health;
|
||||||
uint8_t hunger;
|
uint8_t hunger;
|
||||||
|
uint16_t saturation;
|
||||||
uint8_t hotbar;
|
uint8_t hotbar;
|
||||||
uint16_t inventory_items[41];
|
uint16_t inventory_items[41];
|
||||||
uint16_t craft_items[9];
|
uint16_t craft_items[9];
|
||||||
uint16_t cursor_item;
|
|
||||||
uint8_t inventory_count[41];
|
uint8_t inventory_count[41];
|
||||||
uint8_t craft_count[9];
|
uint8_t craft_count[9];
|
||||||
uint8_t cursor_count;
|
// Usage depends on player's flags, see below
|
||||||
|
// When no flags are set, acts as cursor item ID
|
||||||
|
uint16_t flagval_16;
|
||||||
|
// Usage depends on player's flags, see below
|
||||||
|
// When no flags are set, acts as cursor item count
|
||||||
|
uint8_t flagval_8;
|
||||||
// 0x01 - attack cooldown
|
// 0x01 - attack cooldown
|
||||||
// 0x02 - has not spawned yet
|
// 0x02 - has not spawned yet
|
||||||
// 0x04 - sneaking
|
// 0x04 - sneaking
|
||||||
|
// 0x08 - sprinting
|
||||||
|
// 0x10 - eating, makes extra8 act as eating timer
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} PlayerData;
|
} PlayerData;
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ int cs_clientInformation (int client_fd);
|
|||||||
int cs_pluginMessage (int client_fd);
|
int cs_pluginMessage (int client_fd);
|
||||||
int cs_playerAction (int client_fd);
|
int cs_playerAction (int client_fd);
|
||||||
int cs_useItemOn (int client_fd);
|
int cs_useItemOn (int client_fd);
|
||||||
|
int cs_useItem (int client_fd);
|
||||||
int cs_setPlayerPositionAndRotation (int client_fd, double *x, double *y, double *z, float *yaw, float *pitch, uint8_t *on_ground);
|
int cs_setPlayerPositionAndRotation (int client_fd, double *x, double *y, double *z, float *yaw, float *pitch, uint8_t *on_ground);
|
||||||
int cs_setPlayerPosition (int client_fd, double *x, double *y, double *z, uint8_t *on_ground);
|
int cs_setPlayerPosition (int client_fd, double *x, double *y, double *z, uint8_t *on_ground);
|
||||||
int cs_setPlayerRotation (int client_fd, float *yaw, float *pitch, uint8_t *on_ground);
|
int cs_setPlayerRotation (int client_fd, float *yaw, float *pitch, uint8_t *on_ground);
|
||||||
@@ -16,7 +17,10 @@ int cs_setHeldItem (int client_fd);
|
|||||||
int cs_clickContainer (int client_fd);
|
int cs_clickContainer (int client_fd);
|
||||||
int cs_closeContainer (int client_fd);
|
int cs_closeContainer (int client_fd);
|
||||||
int cs_clientStatus (int client_fd);
|
int cs_clientStatus (int client_fd);
|
||||||
int cs_chat(int client_fd);
|
int cs_chat (int client_fd);
|
||||||
|
int cs_interact (int client_fd);
|
||||||
|
int cs_playerInput (int client_fd);
|
||||||
|
int cs_playerCommand (int client_fd);
|
||||||
|
|
||||||
// Clientbound packets
|
// Clientbound packets
|
||||||
int sc_loginSuccess (int client_fd, uint8_t *uuid, char *name);
|
int sc_loginSuccess (int client_fd, uint8_t *uuid, char *name);
|
||||||
@@ -47,10 +51,8 @@ int sc_damageEvent (int client_fd, int id, int type);
|
|||||||
int sc_setHealth (int client_fd, uint8_t health, uint8_t food);
|
int sc_setHealth (int client_fd, uint8_t health, uint8_t food);
|
||||||
int sc_respawn (int client_fd);
|
int sc_respawn (int client_fd);
|
||||||
int sc_systemChat (int client_fd, char* message, uint16_t len);
|
int sc_systemChat (int client_fd, char* message, uint16_t len);
|
||||||
int cs_interact (int client_fd);
|
|
||||||
int sc_entityEvent (int client_fd, int entity_id, uint8_t status);
|
int sc_entityEvent (int client_fd, int entity_id, uint8_t status);
|
||||||
int sc_removeEntity (int client_fd, int entity_id);
|
int sc_removeEntity (int client_fd, int entity_id);
|
||||||
int cs_playerInput (int client_fd);
|
|
||||||
int sc_registries (int client_fd);
|
int sc_registries (int client_fd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -29,7 +29,7 @@ uint8_t recv_buffer[256] = {0};
|
|||||||
uint32_t world_seed = 0xA103DE6C;
|
uint32_t world_seed = 0xA103DE6C;
|
||||||
uint32_t rng_seed = 0xE2B9419;
|
uint32_t rng_seed = 0xE2B9419;
|
||||||
|
|
||||||
uint16_t world_time = 0;
|
uint16_t world_time = 13000;
|
||||||
|
|
||||||
uint16_t client_count;
|
uint16_t client_count;
|
||||||
|
|
||||||
|
22
src/main.c
22
src/main.c
@@ -216,6 +216,20 @@ void handlePacket (int client_fd, int length, int packet_id) {
|
|||||||
// Don't continue if all we got was rotation data
|
// Don't continue if all we got was rotation data
|
||||||
if (packet_id == 0x1F) break;
|
if (packet_id == 0x1F) break;
|
||||||
|
|
||||||
|
// Players send movement packets roughly 20 times per second when
|
||||||
|
// moving, and much less frequently when standing still. We can
|
||||||
|
// use this correlation between actions and packet count to cheaply
|
||||||
|
// simulate hunger with a timer-based system, where the timer ticks
|
||||||
|
// down with each position packet. The timer value itself then
|
||||||
|
// naturally works as a substitute for saturation.
|
||||||
|
if (player->saturation == 0) {
|
||||||
|
if (player->hunger > 0) player->hunger--;
|
||||||
|
player->saturation = 200;
|
||||||
|
sc_setHealth(client_fd, player->health, player->hunger);
|
||||||
|
} else if (player->flags & 0x08) {
|
||||||
|
player->saturation -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Cast the values to short to get integer position
|
// Cast the values to short to get integer position
|
||||||
short cx = x, cy = y, cz = z;
|
short cx = x, cy = y, cz = z;
|
||||||
// Determine the player's chunk coordinates
|
// Determine the player's chunk coordinates
|
||||||
@@ -337,6 +351,10 @@ void handlePacket (int client_fd, int length, int packet_id) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x29:
|
||||||
|
if (state == STATE_PLAY) cs_playerCommand(client_fd);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x2A:
|
case 0x2A:
|
||||||
if (state == STATE_PLAY) cs_playerInput(client_fd);
|
if (state == STATE_PLAY) cs_playerInput(client_fd);
|
||||||
break;
|
break;
|
||||||
@@ -353,6 +371,10 @@ void handlePacket (int client_fd, int length, int packet_id) {
|
|||||||
if (state == STATE_PLAY) cs_useItemOn(client_fd);
|
if (state == STATE_PLAY) cs_useItemOn(client_fd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x40:
|
||||||
|
if (state == STATE_PLAY) cs_useItem(client_fd);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef DEV_LOG_UNKNOWN_PACKETS
|
#ifdef DEV_LOG_UNKNOWN_PACKETS
|
||||||
printf("Unknown packet: 0x");
|
printf("Unknown packet: 0x");
|
||||||
|
@@ -477,6 +477,23 @@ int sc_openScreen (int client_fd, uint8_t window, const char *title, uint16_t le
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C->S Use Item
|
||||||
|
int cs_useItem (int client_fd) {
|
||||||
|
|
||||||
|
uint8_t hand = readByte(client_fd);
|
||||||
|
int sequence = readVarInt(client_fd);
|
||||||
|
|
||||||
|
// Ignore yaw/pitch
|
||||||
|
recv_all(client_fd, recv_buffer, 8, false);
|
||||||
|
|
||||||
|
PlayerData *player;
|
||||||
|
if (getPlayerData(client_fd, &player)) return 1;
|
||||||
|
|
||||||
|
handlePlayerUseItem(player, 0, 0, 0, 255);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// C->S Use Item On
|
// C->S Use Item On
|
||||||
int cs_useItemOn (int client_fd) {
|
int cs_useItemOn (int client_fd) {
|
||||||
|
|
||||||
@@ -535,13 +552,13 @@ int cs_clickContainer (int client_fd) {
|
|||||||
} else if (mode == 0 && clicked_slot == -999) {
|
} else if (mode == 0 && clicked_slot == -999) {
|
||||||
// when clicking outside inventory, return the dropped item to the player
|
// when clicking outside inventory, return the dropped item to the player
|
||||||
if (button == 0) {
|
if (button == 0) {
|
||||||
givePlayerItem(player, player->cursor_item, player->cursor_count);
|
givePlayerItem(player, player->flagval_16, player->flagval_8);
|
||||||
player->cursor_item = 0;
|
player->flagval_16 = 0;
|
||||||
player->cursor_count = 0;
|
player->flagval_8 = 0;
|
||||||
} else {
|
} else {
|
||||||
givePlayerItem(player, player->cursor_item, 1);
|
givePlayerItem(player, player->flagval_16, 1);
|
||||||
player->cursor_count -= 1;
|
player->flagval_8 -= 1;
|
||||||
if (player->cursor_count == 0) player->cursor_item = 0;
|
if (player->flagval_8 == 0) player->flagval_16 = 0;
|
||||||
}
|
}
|
||||||
apply_changes = false;
|
apply_changes = false;
|
||||||
}
|
}
|
||||||
@@ -593,16 +610,16 @@ int cs_clickContainer (int client_fd) {
|
|||||||
|
|
||||||
// assign cursor-carried item slot
|
// assign cursor-carried item slot
|
||||||
if (readByte(client_fd)) {
|
if (readByte(client_fd)) {
|
||||||
player->cursor_item = readVarInt(client_fd);
|
player->flagval_16 = readVarInt(client_fd);
|
||||||
player->cursor_count = readVarInt(client_fd);
|
player->flagval_8 = readVarInt(client_fd);
|
||||||
// ignore components
|
// ignore components
|
||||||
tmp = readVarInt(client_fd);
|
tmp = readVarInt(client_fd);
|
||||||
recv_all(client_fd, recv_buffer, tmp, false);
|
recv_all(client_fd, recv_buffer, tmp, false);
|
||||||
tmp = readVarInt(client_fd);
|
tmp = readVarInt(client_fd);
|
||||||
recv_all(client_fd, recv_buffer, tmp, false);
|
recv_all(client_fd, recv_buffer, tmp, false);
|
||||||
} else {
|
} else {
|
||||||
player->cursor_item = 0;
|
player->flagval_16 = 0;
|
||||||
player->cursor_count = 0;
|
player->flagval_8 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -711,10 +728,10 @@ int cs_closeContainer (int client_fd) {
|
|||||||
if (client_slot != 255) sc_setContainerSlot(player->client_fd, window_id, client_slot, 0, 0);
|
if (client_slot != 255) sc_setContainerSlot(player->client_fd, window_id, client_slot, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
givePlayerItem(player, player->cursor_item, player->cursor_count);
|
givePlayerItem(player, player->flagval_16, player->flagval_8);
|
||||||
sc_setCursorItem(client_fd, 0, 0);
|
sc_setCursorItem(client_fd, 0, 0);
|
||||||
player->cursor_item = 0;
|
player->flagval_16 = 0;
|
||||||
player->cursor_count = 0;
|
player->flagval_8 = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1054,6 +1071,22 @@ int cs_playerInput (int client_fd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cs_playerCommand (int client_fd) {
|
||||||
|
|
||||||
|
readVarInt(client_fd); // Ignore entity ID
|
||||||
|
uint8_t action = readByte(client_fd);
|
||||||
|
readVarInt(client_fd); // Ignore "Jump Boost" value
|
||||||
|
|
||||||
|
PlayerData *player;
|
||||||
|
if (getPlayerData(client_fd, &player)) return 1;
|
||||||
|
|
||||||
|
// Handle sprinting
|
||||||
|
if (action == 1) player->flags |= 0x08;
|
||||||
|
else if (action == 2) player->flags &= ~0x08;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// S->C Registry Data (multiple packets) and Update Tags (configuration, multiple packets)
|
// S->C Registry Data (multiple packets) and Update Tags (configuration, multiple packets)
|
||||||
int sc_registries (int client_fd) {
|
int sc_registries (int client_fd) {
|
||||||
|
|
||||||
|
150
src/procedures.c
150
src/procedures.c
@@ -47,6 +47,7 @@ int getClientIndex (int client_fd) {
|
|||||||
void resetPlayerData (PlayerData *player) {
|
void resetPlayerData (PlayerData *player) {
|
||||||
player->health = 20;
|
player->health = 20;
|
||||||
player->hunger = 20;
|
player->hunger = 20;
|
||||||
|
player->saturation = 2500;
|
||||||
player->x = 8;
|
player->x = 8;
|
||||||
player->z = 8;
|
player->z = 8;
|
||||||
player->y = 80;
|
player->y = 80;
|
||||||
@@ -571,7 +572,62 @@ uint8_t getItemStackSize (uint16_t item) {
|
|||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlePlayerAction (PlayerData *player, int action, short x, short y, short z) {
|
// Handles the player eating their currently held item
|
||||||
|
// Returns whether the operation was succesful (item was consumed)
|
||||||
|
// If `just_check` is set to true, the item doesn't get consumed
|
||||||
|
uint8_t handlePlayerEating (PlayerData *player, uint8_t just_check) {
|
||||||
|
|
||||||
|
// Exit early if player is unable to eat
|
||||||
|
if (player->hunger >= 20) return false;
|
||||||
|
|
||||||
|
uint16_t *held_item = &player->inventory_items[player->hotbar];
|
||||||
|
uint8_t *held_count = &player->inventory_count[player->hotbar];
|
||||||
|
|
||||||
|
// Exit early if player isn't holding anything
|
||||||
|
if (*held_item == 0 || *held_count == 0) return false;
|
||||||
|
|
||||||
|
uint8_t food = 0;
|
||||||
|
uint16_t saturation = 0;
|
||||||
|
|
||||||
|
// The saturation ratio from vanilla to here is about 1:500
|
||||||
|
switch (*held_item) {
|
||||||
|
case I_chicken: food = 2; saturation = 600; break;
|
||||||
|
case I_beef: food = 3; saturation = 900; break;
|
||||||
|
case I_porkchop: food = 3; saturation = 300; break;
|
||||||
|
case I_mutton: food = 2; saturation = 600; break;
|
||||||
|
case I_cooked_chicken: food = 6; saturation = 3600; break;
|
||||||
|
case I_cooked_beef: food = 8; saturation = 6400; break;
|
||||||
|
case I_cooked_porkchop: food = 8; saturation = 6400; break;
|
||||||
|
case I_cooked_mutton: food = 6; saturation = 4800; break;
|
||||||
|
case I_rotten_flesh: food = 4; saturation = 0; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If just checking the item, return before making any changes
|
||||||
|
if (just_check) return food != 0;
|
||||||
|
|
||||||
|
// Apply saturation and food boost
|
||||||
|
player->saturation += saturation;
|
||||||
|
player->hunger += food;
|
||||||
|
if (player->hunger > 20) player->hunger = 20;
|
||||||
|
|
||||||
|
// Consume held item
|
||||||
|
*held_count -= 1;
|
||||||
|
if (*held_count == 0) *held_item = 0;
|
||||||
|
|
||||||
|
// Update the client of these changes
|
||||||
|
sc_setHealth(player->client_fd, player->health, player->hunger);
|
||||||
|
sc_entityEvent(player->client_fd, player->client_fd, 9);
|
||||||
|
sc_setContainerSlot(
|
||||||
|
player->client_fd, 0,
|
||||||
|
serverSlotToClientSlot(0, player->hotbar),
|
||||||
|
*held_count, *held_item
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
if (action == 3 || action == 4) {
|
if (action == 3 || action == 4) {
|
||||||
@@ -584,6 +640,13 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Finish eating" action, called any time eating stops
|
||||||
|
if (action == 5) {
|
||||||
|
// Reset eating timer and clear eating flag
|
||||||
|
player->flagval_16 = 0;
|
||||||
|
player->flags &= ~0x10;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore further actions not pertaining to mining blocks
|
// Ignore further actions not pertaining to mining blocks
|
||||||
if (action != 0 && action != 2) return;
|
if (action != 0 && action != 2) return;
|
||||||
|
|
||||||
@@ -621,11 +684,43 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short
|
|||||||
y_offset ++;
|
y_offset ++;
|
||||||
block_above = getBlockAt(x, y + y_offset, z);
|
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) {
|
||||||
|
|
||||||
|
// If the selected slot doesn't hold any items, exit
|
||||||
|
uint8_t *count = &player->inventory_count[player->hotbar];
|
||||||
|
if (*count == 0) return;
|
||||||
|
|
||||||
|
// Check special item handling
|
||||||
|
uint16_t *item = &player->inventory_items[player->hotbar];
|
||||||
|
if (*item == I_bone_meal) {
|
||||||
|
uint8_t target = getBlockAt(x, y, z);
|
||||||
|
uint8_t target_below = getBlockAt(x, y - 1, z);
|
||||||
|
if (target == B_oak_sapling) {
|
||||||
|
// Consume the bone meal (yes, even before checks)
|
||||||
|
// Wasting bone meal on misplanted saplings is vanilla behavior
|
||||||
|
if ((*count -= 1) == 0) *item = 0;
|
||||||
|
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), *count, *item);
|
||||||
|
if ( // Saplings can only grow when placed on these blocks
|
||||||
|
target_below == B_dirt ||
|
||||||
|
target_below == B_grass_block ||
|
||||||
|
target_below == B_snowy_grass_block ||
|
||||||
|
target_below == B_mud
|
||||||
|
) {
|
||||||
|
// Bone meal has a 25% chance of growing a tree from a sapling
|
||||||
|
if ((fast_rand() & 3) == 0) placeTreeStructure(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (handlePlayerEating(player, true)) {
|
||||||
|
// Reset eating timer and set eating flag
|
||||||
|
player->flagval_16 = 0;
|
||||||
|
player->flags |= 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit if no coordinates were provided
|
||||||
|
if (face == 255) return;
|
||||||
|
|
||||||
// Check interaction with containers when not sneaking
|
// Check interaction with containers when not sneaking
|
||||||
if (!(player->flags & 0x04)) {
|
if (!(player->flags & 0x04)) {
|
||||||
uint8_t target = getBlockAt(x, y, z);
|
uint8_t target = getBlockAt(x, y, z);
|
||||||
@@ -655,32 +750,6 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the selected slot doesn't hold any items, exit
|
|
||||||
uint8_t *count = &player->inventory_count[player->hotbar];
|
|
||||||
if (*count == 0) return;
|
|
||||||
|
|
||||||
// Check special item handling
|
|
||||||
uint16_t *item = &player->inventory_items[player->hotbar];
|
|
||||||
if (*item == I_bone_meal) {
|
|
||||||
uint8_t target = getBlockAt(x, y, z);
|
|
||||||
uint8_t target_below = getBlockAt(x, y - 1, z);
|
|
||||||
if (target == B_oak_sapling) {
|
|
||||||
// Consume the bone meal (yes, even before checks)
|
|
||||||
// Wasting bone meal on misplanted saplings is vanilla behavior
|
|
||||||
if ((*count -= 1) == 0) *item = 0;
|
|
||||||
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), *count, *item);
|
|
||||||
if ( // Saplings can only grow when placed on these blocks
|
|
||||||
target_below == B_dirt ||
|
|
||||||
target_below == B_grass_block ||
|
|
||||||
target_below == B_snowy_grass_block ||
|
|
||||||
target_below == B_mud
|
|
||||||
) {
|
|
||||||
// Bone meal has a 25% chance of growing a tree from a sapling
|
|
||||||
if ((fast_rand() & 3) == 0) placeTreeStructure(x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the selected item doesn't correspond to a block, exit
|
// If the selected item doesn't correspond to a block, exit
|
||||||
uint8_t block = I_to_B(*item);
|
uint8_t block = I_to_B(*item);
|
||||||
if (block == 0) return;
|
if (block == 0) return;
|
||||||
@@ -817,16 +886,35 @@ void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t da
|
|||||||
// Takes the time since the last tick in microseconds as the only arguemnt
|
// Takes the time since the last tick in microseconds as the only arguemnt
|
||||||
void handleServerTick (int64_t time_since_last_tick) {
|
void handleServerTick (int64_t time_since_last_tick) {
|
||||||
|
|
||||||
// Send Keep Alive and Update Time packets to all in-game clients
|
// Update world time
|
||||||
world_time = (world_time + time_since_last_tick / 50000) % 24000;
|
world_time = (world_time + time_since_last_tick / 50000) % 24000;
|
||||||
|
|
||||||
|
// Update player events
|
||||||
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||||
if (player_data[i].client_fd == -1) continue;
|
if (player_data[i].client_fd == -1) continue;
|
||||||
|
// Send Keep Alive and Update Time packets
|
||||||
sc_keepAlive(player_data[i].client_fd);
|
sc_keepAlive(player_data[i].client_fd);
|
||||||
sc_updateTime(player_data[i].client_fd, world_time);
|
sc_updateTime(player_data[i].client_fd, world_time);
|
||||||
// Reset attack cooldown if at least a second has passed
|
// Reset player attack cooldown
|
||||||
if (time_since_last_tick >= 1000000) {
|
|
||||||
player_data[i].flags &= ~0x01;
|
player_data[i].flags &= ~0x01;
|
||||||
|
// Handle eating animation
|
||||||
|
if (player_data[i].flags & 0x10) {
|
||||||
|
if (player_data[i].flagval_16 >= TICKS_TO_EAT) {
|
||||||
|
handlePlayerEating(&player_data[i], false);
|
||||||
|
player_data[i].flags &= ~0x10;
|
||||||
|
player_data[i].flagval_16 = 0;
|
||||||
|
} else player_data[i].flagval_16 ++;
|
||||||
}
|
}
|
||||||
|
// Heal from saturation
|
||||||
|
if (player_data[i].health >= 20) continue;
|
||||||
|
if (player_data[i].saturation >= 600) {
|
||||||
|
player_data[i].saturation -= 600;
|
||||||
|
player_data[i].health ++;
|
||||||
|
} else if (player_data[i].hunger > 17) {
|
||||||
|
player_data[i].hunger --;
|
||||||
|
player_data[i].health ++;
|
||||||
|
}
|
||||||
|
sc_setHealth(player_data[i].client_fd, player_data[i].health, player_data[i].hunger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user