commit c5e84080528d6b4a6defd2599770a5c60149de1c from: SDFTDusername <85052868+SDFTDusername@users.noreply.github.com> via: GitHub date: Mon Sep 15 19:01:22 2025 UTC implement player poses (sneak/sprint) * Added sending player metadata with poses to everyone * Renamed sendPlayerMetadataToAll to broadcastPlayerMetadata * Made entity metadata system flexible * Made broadcastPlayerMetadata create new metadata instead of using a global one * Moved writeEntityData, sizeEntityData and sizeEntityMetadata to procedures * style nitpicks --------- Co-authored-by: p2r3 commit - e5dfe53d14c67dcf18bf7c84a672eb490a0329dc commit + c5e84080528d6b4a6defd2599770a5c60149de1c blob - 06f8368e342a02b0d903ea07aeb4a7b94c37d186 blob + c5942b9ea0c23362acaca9e0cc6e065a5d6fdc4b --- include/globals.h +++ include/globals.h @@ -248,6 +248,19 @@ typedef struct { #pragma pack(pop) +union EntityDataValue { + uint8_t byte; + int pose; +}; + +typedef struct { + uint8_t index; + // 0 - Byte + // 21 - Pose + int type; + union EntityDataValue value; +} EntityData; + extern BlockChange block_changes[MAX_BLOCK_CHANGES]; extern int block_changes_count; blob - 4d3b36cd73eed7d55c33642fa532ddfe6a6a1d73 blob + ae832ac729d08016f73fc59fb9f192ae60644ce8 --- include/packets.h +++ include/packets.h @@ -48,6 +48,7 @@ int sc_acknowledgeBlockChange (int client_fd, int sequ int sc_playerInfoUpdateAddPlayer (int client_fd, PlayerData player); int sc_spawnEntity (int client_fd, int id, uint8_t *uuid, int type, double x, double y, double z, uint8_t yaw, uint8_t pitch); int sc_spawnEntityPlayer (int client_fd, PlayerData player); +int sc_setEntityMetadata (int client_fd, int id, EntityData *metadata, size_t length); int sc_entityAnimation (int client_fd, int id, uint8_t animation); int sc_teleportEntity (int client_fd, int id, double x, double y, double z, float yaw, float pitch); int sc_setHeadRotation (int client_fd, int id, uint8_t yaw); blob - 1dde7933359ecaa0ac637e183cf8e78eacf20109 blob + 62d09f06244a60ebd35fe543924216f2eb7fb58d --- include/procedures.h +++ include/procedures.h @@ -20,6 +20,8 @@ void disconnectClient (int *client_fd, int cause); int givePlayerItem (PlayerData *player, uint16_t item, uint8_t count); void spawnPlayer (PlayerData *player); +void broadcastPlayerMetadata (PlayerData *player); + uint8_t serverSlotToClientSlot (int window_id, uint8_t slot); uint8_t clientSlotToServerSlot (int window_id, uint8_t slot); @@ -47,4 +49,9 @@ void handleServerTick (int64_t time_since_last_tick); void broadcastChestUpdate (int origin_fd, uint8_t *storage_ptr, uint16_t item, uint8_t count, uint8_t slot); +ssize_t writeEntityData (int client_fd, EntityData *data); + +int sizeEntityData (EntityData *data); +int sizeEntityMetadata (EntityData *metadata, size_t length); + #endif blob - 5cc1a51e31e791d131addf9f6a7cbdfcd424504a blob + 8b67b5f0f1717df494922a2071a74a58629b77e0 --- src/packets.c +++ src/packets.c @@ -764,6 +764,10 @@ int cs_setPlayerMovementFlags (int client_fd, uint8_t *on_ground = readByte(client_fd) & 0x01; + PlayerData *player; + if (!getPlayerData(client_fd, &player)) + broadcastPlayerMetadata(player); + return 0; } @@ -910,6 +914,26 @@ int sc_spawnEntity ( return 0; } +// S->C Set Entity Metadata +int sc_setEntityMetadata (int client_fd, int id, EntityData *metadata, size_t length) { + int entity_metadata_size = sizeEntityMetadata(metadata, length); + if (entity_metadata_size == -1) return 1; + + writeVarInt(client_fd, 2 + sizeVarInt(id) + entity_metadata_size); + writeByte(client_fd, 0x5C); + + writeVarInt(client_fd, id); // Entity ID + + for (size_t i = 0; i < length; i ++) { + EntityData *data = &metadata[i]; + writeEntityData(client_fd, data); + } + + writeByte(client_fd, 0xFF); // End + + return 0; +} + // S->C Spawn Entity (from PlayerData) int sc_spawnEntityPlayer (int client_fd, PlayerData player) { return sc_spawnEntity( @@ -1198,6 +1222,8 @@ int cs_playerInput (int client_fd) { if (flags & 0x20) player->flags |= 0x04; else player->flags &= ~0x04; + broadcastPlayerMetadata(player); + return 0; } @@ -1215,6 +1241,8 @@ int cs_playerCommand (int client_fd) { if (action == 1) player->flags |= 0x08; else if (action == 2) player->flags &= ~0x08; + broadcastPlayerMetadata(player); + return 0; } blob - 464e7a4df918d7c63b3d2568dbc3d194f7974d27 blob + 7ba75da40d5d01df149e3fe5caa2ec4459485a32 --- src/procedures.c +++ src/procedures.c @@ -368,6 +368,43 @@ void spawnPlayer (PlayerData *player) { } +// Broadcasts a player's entity metadata (sneak/sprint state) to other players +void broadcastPlayerMetadata (PlayerData *player) { + uint8_t sneaking = (player->flags & 0x04) != 0; + uint8_t sprinting = (player->flags & 0x08) != 0; + + uint8_t player_bit_mask = 0; + if (sneaking) player_bit_mask |= 0x02; + if (sprinting) player_bit_mask |= 0x08; + + int pose = 0; + if (sneaking) pose = 5; + + EntityData metadata[] = { + { + 0, // Index (Bit Mask) + 0, // Type (Byte) + player_bit_mask, // Value + }, + { + 6, // Index (Pose), + 21, // Type (Pose), + pose, // Value (Standing) + } + }; + + for (int i = 0; i < MAX_PLAYERS; i ++) { + PlayerData* other_player = &player_data[i]; + int client_fd = other_player->client_fd; + + if (client_fd == -1) continue; + if (client_fd == player->client_fd) continue; + if (other_player->flags & 0x20) continue; + + sc_setEntityMetadata(client_fd, player->client_fd, metadata, 2); + } +} + uint8_t getBlockChange (short x, uint8_t y, short z) { for (int i = 0; i < block_changes_count; i ++) { if (block_changes[i].block == 0xFF) continue; @@ -1784,3 +1821,47 @@ void broadcastChestUpdate (int origin_fd, uint8_t *sto } #endif + +ssize_t writeEntityData (int client_fd, EntityData *data) { + writeByte(client_fd, data->index); + writeVarInt(client_fd, data->type); + + switch (data->type) { + case 0: // Byte + return writeByte(client_fd, data->value.byte); + case 21: // Pose + writeVarInt(client_fd, data->value.pose); + return 0; + + default: return -1; + } +} + +// Returns the networked size of an EntityData entry +int sizeEntityData (EntityData *data) { + int value_size; + + switch (data->type) { + case 0: // Byte + value_size = 1; + break; + case 21: // Pose + value_size = sizeVarInt(data->value.pose); + break; + + default: return -1; + } + + return 1 + sizeVarInt(data->type) + value_size; +} + +// Returns the networked size of an array of EntityData entries +int sizeEntityMetadata (EntityData *metadata, size_t length) { + int total_size = 0; + for (size_t i = 0; i < length; i ++) { + int size = sizeEntityData(&metadata[i]); + if (size == -1) return -1; + total_size += size; + } + return total_size; +} blob - fabb6f097be7f7314556a178a854c0acc6b2df05 blob + 0b7050f9785d2d07f62890ca08ae09b4c24b3ecc --- src/tools.c +++ src/tools.c @@ -120,7 +120,7 @@ ssize_t send_all (int client_fd, const void *buf, ssiz if (err == WSAEWOULDBLOCK || err == WSAEINTR) { #else if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { - #endif + #endif // handle network timeout if (get_program_time() - last_update_time > NETWORK_TIMEOUT_TIME) { disconnectClient(&client_fd, -2);