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 <p2r3@p2r3.com>
This commit is contained in:
SDFTDusername
2025-09-15 21:01:22 +02:00
committed by GitHub
parent e5dfe53d14
commit c5e8408052
6 changed files with 131 additions and 1 deletions

View File

@@ -248,6 +248,19 @@ typedef struct {
#pragma pack(pop) #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 BlockChange block_changes[MAX_BLOCK_CHANGES];
extern int block_changes_count; extern int block_changes_count;

View File

@@ -48,6 +48,7 @@ int sc_acknowledgeBlockChange (int client_fd, int sequence);
int sc_playerInfoUpdateAddPlayer (int client_fd, PlayerData player); 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_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_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_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_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); int sc_setHeadRotation (int client_fd, int id, uint8_t yaw);

View File

@@ -20,6 +20,8 @@ void disconnectClient (int *client_fd, int cause);
int givePlayerItem (PlayerData *player, uint16_t item, uint8_t count); int givePlayerItem (PlayerData *player, uint16_t item, uint8_t count);
void spawnPlayer (PlayerData *player); void spawnPlayer (PlayerData *player);
void broadcastPlayerMetadata (PlayerData *player);
uint8_t serverSlotToClientSlot (int window_id, uint8_t slot); uint8_t serverSlotToClientSlot (int window_id, uint8_t slot);
uint8_t clientSlotToServerSlot (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); 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 #endif

View File

@@ -764,6 +764,10 @@ int cs_setPlayerMovementFlags (int client_fd, uint8_t *on_ground) {
*on_ground = readByte(client_fd) & 0x01; *on_ground = readByte(client_fd) & 0x01;
PlayerData *player;
if (!getPlayerData(client_fd, &player))
broadcastPlayerMetadata(player);
return 0; return 0;
} }
@@ -910,6 +914,26 @@ int sc_spawnEntity (
return 0; 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) // S->C Spawn Entity (from PlayerData)
int sc_spawnEntityPlayer (int client_fd, PlayerData player) { int sc_spawnEntityPlayer (int client_fd, PlayerData player) {
return sc_spawnEntity( return sc_spawnEntity(
@@ -1198,6 +1222,8 @@ int cs_playerInput (int client_fd) {
if (flags & 0x20) player->flags |= 0x04; if (flags & 0x20) player->flags |= 0x04;
else player->flags &= ~0x04; else player->flags &= ~0x04;
broadcastPlayerMetadata(player);
return 0; return 0;
} }
@@ -1215,6 +1241,8 @@ int cs_playerCommand (int client_fd) {
if (action == 1) player->flags |= 0x08; if (action == 1) player->flags |= 0x08;
else if (action == 2) player->flags &= ~0x08; else if (action == 2) player->flags &= ~0x08;
broadcastPlayerMetadata(player);
return 0; return 0;
} }

View File

@@ -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) { uint8_t getBlockChange (short x, uint8_t y, short z) {
for (int i = 0; i < block_changes_count; i ++) { for (int i = 0; i < block_changes_count; i ++) {
if (block_changes[i].block == 0xFF) continue; if (block_changes[i].block == 0xFF) continue;
@@ -1784,3 +1821,47 @@ void broadcastChestUpdate (int origin_fd, uint8_t *storage_ptr, uint16_t item, u
} }
#endif #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;
}

View File

@@ -120,7 +120,7 @@ ssize_t send_all (int client_fd, const void *buf, ssize_t len) {
if (err == WSAEWOULDBLOCK || err == WSAEINTR) { if (err == WSAEWOULDBLOCK || err == WSAEINTR) {
#else #else
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
#endif #endif
// handle network timeout // handle network timeout
if (get_program_time() - last_update_time > NETWORK_TIMEOUT_TIME) { if (get_program_time() - last_update_time > NETWORK_TIMEOUT_TIME) {
disconnectClient(&client_fd, -2); disconnectClient(&client_fd, -2);