From a824c2d63bb6a75e08b2d8dfd8a747eb6b9ac5c9 Mon Sep 17 00:00:00 2001 From: p2r3 Date: Sat, 30 Aug 2025 20:48:01 +0300 Subject: [PATCH] add item pickup animations --- include/globals.h | 6 ++++++ include/packets.h | 1 + src/packets.c | 12 ++++++++++++ src/procedures.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/globals.h b/include/globals.h index 0cdb88d..f21c0a2 100644 --- a/include/globals.h +++ b/include/globals.h @@ -67,6 +67,12 @@ // If defined, enables flight for all players. As a side-effect, allows // players to sprint when starving. // #define ENABLE_PLAYER_FLIGHT +// If defined, enables the item pickup animation when mining a block/ +// Does not affect how item pickups work! Items from broken blocks still +// get placed directly in the inventory, this is just an animation. +// Relatively inexpensive, though requires sending a few more packets +// every time a block is broken. +#define ENABLE_PICKUP_ANIMATION // If defined, logs unrecognized packet IDs // #define DEV_LOG_UNKNOWN_PACKETS diff --git a/include/packets.h b/include/packets.h index 1f424aa..4065ddf 100644 --- a/include/packets.h +++ b/include/packets.h @@ -54,6 +54,7 @@ int sc_respawn (int client_fd); int sc_systemChat (int client_fd, char* message, uint16_t len); int sc_entityEvent (int client_fd, int entity_id, uint8_t status); int sc_removeEntity (int client_fd, int entity_id); +int sc_pickupItem (int client_fd, int collected, int collector, uint8_t count); int sc_registries (int client_fd); #endif diff --git a/src/packets.c b/src/packets.c index 89357c9..e7228d2 100644 --- a/src/packets.c +++ b/src/packets.c @@ -1147,6 +1147,18 @@ int cs_playerCommand (int client_fd) { return 0; } +// S->C Pickup Item (take_item_entity) +int sc_pickupItem (int client_fd, int collected, int collector, uint8_t count) { + + writeVarInt(client_fd, 1 + sizeVarInt(collected) + sizeVarInt(collector) + sizeVarInt(count)); + writeByte(client_fd, 0x75); + + writeVarInt(client_fd, collected); + writeVarInt(client_fd, collector); + writeVarInt(client_fd, count); + +} + // S->C Registry Data (multiple packets) and Update Tags (configuration, multiple packets) int sc_registries (int client_fd) { diff --git a/src/procedures.c b/src/procedures.c index f7593c5..eee26a4 100644 --- a/src/procedures.c +++ b/src/procedures.c @@ -4,6 +4,7 @@ #include "globals.h" #include "tools.h" +#include "varnum.h" #include "packets.h" #include "registries.h" #include "worldgen.h" @@ -847,6 +848,41 @@ void checkFluidUpdate (short x, uint8_t y, short z, uint8_t block) { } +#ifdef ENABLE_PICKUP_ANIMATION +// Plays the item pickup animation with the given item at the given coordinates +void playPickupAnimation (PlayerData *player, uint16_t item, double x, double y, double z) { + + // Spawn a new item entity at the input coordinates + // ID -1 is safe, as elsewhere it's reserved as a placeholder + // The player's name is used as the UUID as it's cheap and unique enough + sc_spawnEntity(player->client_fd, -1, (uint8_t *)player->name, 69, x + 0.5, y + 0.5, z + 0.5, 0, 0); + + // Write a Set Entity Metadata packet for the item + // There's no packets.c entry for this, as it's not cheaply generalizable + writeVarInt(player->client_fd, 12 + sizeVarInt(item)); + writeByte(player->client_fd, 0x5C); + writeVarInt(player->client_fd, -1); + + // Describe slot data array entry + writeByte(player->client_fd, 8); + writeByte(player->client_fd, 7); + // Send slot data + writeByte(player->client_fd, 1); + writeVarInt(player->client_fd, item); + writeByte(player->client_fd, 0); + writeByte(player->client_fd, 0); + // Terminate entity metadata array + writeByte(player->client_fd, 0xFF); + + // Send the Pickup Item packet targeting this entity + sc_pickupItem(player->client_fd, -1, player->client_fd, 1); + + // Remove the item entity from the client right away + sc_removeEntity(player->client_fd, -1); + +} +#endif + void handlePlayerAction (PlayerData *player, int action, short x, short y, short z) { // Re-sync slot when player drops an item @@ -884,11 +920,17 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short // Don't continue if the block change failed if (makeBlockChange(x, y, z, 0)) return; + bumpToolDurability(player); uint16_t held_item = player->inventory_items[player->hotbar]; uint16_t item = getMiningResult(held_item, block); - if (item) givePlayerItem(player, item, 1); - bumpToolDurability(player); + + if (item) { + #ifdef ENABLE_PICKUP_ANIMATION + playPickupAnimation(player, item, x, y, z); + #endif + givePlayerItem(player, item, 1); + } // Update nearby fluids uint8_t block_above = getBlockAt(x, y + 1, z);