forked from EXTERNAL/bareiron
implement sheep shearing
* Added shearing sheeps * Added empty line * Changed comment in MobData to say what the middle 1 bit is used for * Replaced if statements with a switch statement and early returns * Send mob metadata to players that join * Fixed mob metadata getting freed when exiting the switch statement * remove currently unnecessary check * use bitwise and in place of modulo * style nitpicks --------- Co-authored-by: p2r3 <p2r3@p2r3.com>
This commit is contained in:
@@ -241,7 +241,7 @@ typedef struct {
|
|||||||
uint8_t y;
|
uint8_t y;
|
||||||
short z;
|
short z;
|
||||||
// Lower 5 bits: health
|
// Lower 5 bits: health
|
||||||
// Middle 1 bit: reserved for future use
|
// Middle 1 bit: sheep sheared, unused for other mobs
|
||||||
// Upper 2 bits: panic timer
|
// Upper 2 bits: panic timer
|
||||||
uint8_t data;
|
uint8_t data;
|
||||||
} MobData;
|
} MobData;
|
||||||
|
@@ -21,6 +21,7 @@ int givePlayerItem (PlayerData *player, uint16_t item, uint8_t count);
|
|||||||
void spawnPlayer (PlayerData *player);
|
void spawnPlayer (PlayerData *player);
|
||||||
|
|
||||||
void broadcastPlayerMetadata (PlayerData *player);
|
void broadcastPlayerMetadata (PlayerData *player);
|
||||||
|
void broadcastMobMetadata (int client_fd, int entity_id);
|
||||||
|
|
||||||
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);
|
||||||
@@ -44,6 +45,7 @@ void handlePlayerUseItem (PlayerData *player, short x, short y, short z, uint8_t
|
|||||||
void checkFluidUpdate (short x, uint8_t y, short z, uint8_t block);
|
void checkFluidUpdate (short x, uint8_t y, short z, uint8_t block);
|
||||||
|
|
||||||
void spawnMob (uint8_t type, short x, uint8_t y, short z, uint8_t health);
|
void spawnMob (uint8_t type, short x, uint8_t y, short z, uint8_t health);
|
||||||
|
void interactEntity (int entity_id, int interactor_id);
|
||||||
void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t damage);
|
void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t damage);
|
||||||
void handleServerTick (int64_t time_since_last_tick);
|
void handleServerTick (int64_t time_since_last_tick);
|
||||||
|
|
||||||
|
@@ -156,6 +156,7 @@ void handlePacket (int client_fd, int length, int packet_id, int state) {
|
|||||||
mob_data[i].type, mob_data[i].x, mob_data[i].y, mob_data[i].z,
|
mob_data[i].type, mob_data[i].x, mob_data[i].y, mob_data[i].z,
|
||||||
0, 0
|
0, 0
|
||||||
);
|
);
|
||||||
|
broadcastMobMetadata(client_fd, -2 - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1179,7 +1179,9 @@ int cs_interact (int client_fd) {
|
|||||||
// Ignore sneaking flag
|
// Ignore sneaking flag
|
||||||
recv_all(client_fd, recv_buffer, 1, false);
|
recv_all(client_fd, recv_buffer, 1, false);
|
||||||
|
|
||||||
if (type == 1) {
|
if (type == 0) { // Interact
|
||||||
|
interactEntity(entity_id, client_fd);
|
||||||
|
} else if (type == 1) { // Attack
|
||||||
hurtEntity(entity_id, client_fd, D_generic, 1);
|
hurtEntity(entity_id, client_fd, D_generic, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
100
src/procedures.c
100
src/procedures.c
@@ -373,18 +373,18 @@ void broadcastPlayerMetadata (PlayerData *player) {
|
|||||||
uint8_t sneaking = (player->flags & 0x04) != 0;
|
uint8_t sneaking = (player->flags & 0x04) != 0;
|
||||||
uint8_t sprinting = (player->flags & 0x08) != 0;
|
uint8_t sprinting = (player->flags & 0x08) != 0;
|
||||||
|
|
||||||
uint8_t player_bit_mask = 0;
|
uint8_t entity_bit_mask = 0;
|
||||||
if (sneaking) player_bit_mask |= 0x02;
|
if (sneaking) entity_bit_mask |= 0x02;
|
||||||
if (sprinting) player_bit_mask |= 0x08;
|
if (sprinting) entity_bit_mask |= 0x08;
|
||||||
|
|
||||||
int pose = 0;
|
int pose = 0;
|
||||||
if (sneaking) pose = 5;
|
if (sneaking) pose = 5;
|
||||||
|
|
||||||
EntityData metadata[] = {
|
EntityData metadata[] = {
|
||||||
{
|
{
|
||||||
0, // Index (Bit Mask)
|
0, // Index (Entity Bit Mask)
|
||||||
0, // Type (Byte)
|
0, // Type (Byte)
|
||||||
player_bit_mask, // Value
|
entity_bit_mask, // Value
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
6, // Index (Pose),
|
6, // Index (Pose),
|
||||||
@@ -405,6 +405,50 @@ void broadcastPlayerMetadata (PlayerData *player) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sends a mob's entity metadata to the given player.
|
||||||
|
// If client_fd is -1, broadcasts to all player
|
||||||
|
void broadcastMobMetadata (int client_fd, int entity_id) {
|
||||||
|
|
||||||
|
MobData *mob = &mob_data[-entity_id - 2];
|
||||||
|
|
||||||
|
EntityData *metadata;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
switch (mob->type) {
|
||||||
|
case 106: // Sheep
|
||||||
|
if (!((mob->data >> 5) & 1)) // Don't send metadata if sheep isn't sheared
|
||||||
|
return;
|
||||||
|
|
||||||
|
metadata = malloc(sizeof *metadata);
|
||||||
|
metadata[0] = (EntityData){
|
||||||
|
17, // Index (Sheep Bit Mask),
|
||||||
|
0, // Type (Byte),
|
||||||
|
(uint8_t)0x10, // Value
|
||||||
|
};
|
||||||
|
length = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client_fd == -1) {
|
||||||
|
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||||
|
PlayerData* player = &player_data[i];
|
||||||
|
client_fd = player->client_fd;
|
||||||
|
|
||||||
|
if (client_fd == -1) continue;
|
||||||
|
if (player->flags & 0x20) continue;
|
||||||
|
|
||||||
|
sc_setEntityMetadata(client_fd, entity_id, metadata, length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sc_setEntityMetadata(client_fd, entity_id, metadata, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -1344,11 +1388,57 @@ void spawnMob (uint8_t type, short x, uint8_t y, short z, uint8_t health) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Freshly spawned mobs currently don't need metadata updates.
|
||||||
|
// If this changes, uncomment this line.
|
||||||
|
// broadcastMobMetadata(-1, i);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void interactEntity (int entity_id, int interactor_id) {
|
||||||
|
|
||||||
|
PlayerData *player;
|
||||||
|
if (getPlayerData(interactor_id, &player)) return;
|
||||||
|
|
||||||
|
MobData *mob = &mob_data[-entity_id - 2];
|
||||||
|
|
||||||
|
switch (mob->type) {
|
||||||
|
case 106: // Sheep
|
||||||
|
if (player->inventory_items[player->hotbar] != I_shears)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((mob->data >> 5) & 1) // Check if sheep has already been sheared
|
||||||
|
return;
|
||||||
|
|
||||||
|
mob->data |= 1 << 5; // Set sheared to true
|
||||||
|
|
||||||
|
bumpToolDurability(player);
|
||||||
|
|
||||||
|
#ifdef ENABLE_PICKUP_ANIMATION
|
||||||
|
playPickupAnimation(player, I_white_wool, mob->x, mob->y, mob->z);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t item_count = 1 + (fast_rand() & 1); // 1-2
|
||||||
|
givePlayerItem(player, I_white_wool, item_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||||
|
PlayerData* player = &player_data[i];
|
||||||
|
int client_fd = player->client_fd;
|
||||||
|
|
||||||
|
if (client_fd == -1) continue;
|
||||||
|
if (player->flags & 0x20) continue;
|
||||||
|
|
||||||
|
sc_entityAnimation(client_fd, interactor_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcastMobMetadata(-1, entity_id);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t damage) {
|
void hurtEntity (int entity_id, int attacker_id, uint8_t damage_type, uint8_t damage) {
|
||||||
|
|
||||||
if (attacker_id > 0) { // Attacker is a player
|
if (attacker_id > 0) { // Attacker is a player
|
||||||
|
Reference in New Issue
Block a user