Commit Diff


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);