Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <stdint.h>
#include <unistd.h>

#include "registries.h"

#ifdef ESP_PLATFORM
#define WIFI_SSID "your-ssid"
#define WIFI_PASS "your-password"
Expand Down Expand Up @@ -105,6 +107,31 @@
// Size of the receive buffer for incoming string data
#define MAX_RECV_BUF_LEN 256

// Tools that should have a durability decrease when breaking a block
#define TOOLS { \
I_wooden_pickaxe, I_wooden_axe, I_wooden_shovel, \
I_stone_pickaxe, I_stone_axe, I_stone_shovel, \
I_iron_pickaxe, I_iron_axe, I_iron_shovel, \
I_golden_pickaxe, I_golden_axe, I_golden_shovel, \
I_diamond_pickaxe,I_diamond_axe,I_diamond_shovel, \
I_netherite_pickaxe, I_netherite_axe, I_netherite_shovel, \
I_shears \
}

// The durability of each tool
#define TOOL_DURABILITY { \
59, 59, 59, \
131, 131, 131, \
250, 250, 250, \
32, 32, 32, \
1561, 1561, 1561, \
2031, 2031, 2031, \
238 \
}

// You must to ensure this after changing the options ahead!!!
#define TOOL_COUNT 19

// If defined, sends the server brand to clients. Doesn't do much, but will
// show up in the top-left of the F3/debug menu, in the Minecraft client.
// You can change the brand string in the "brand" variable in src/globals.c
Expand Down Expand Up @@ -273,4 +300,7 @@ extern int player_data_count;

extern MobData mob_data[MAX_MOBS];

extern uint16_t tools[];
extern uint16_t tool_durability[];

#endif
1 change: 1 addition & 0 deletions include/packets.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ int sc_updateTime (int client_fd, uint64_t ticks);
int sc_setCenterChunk (int client_fd, int x, int y);
int sc_chunkDataAndUpdateLight (int client_fd, int _x, int _z);
int sc_keepAlive (int client_fd);
int sc_setContainerSlotWithComponent (int client_fd, int window_id, uint16_t slot, uint8_t count, uint16_t item, uint8_t component_to_add_amount, uint8_t component_type, uint16_t component_content);
int sc_setContainerSlot (int client_fd, int window_id, uint16_t slot, uint8_t count, uint16_t item);
int sc_setCursorItem (int client_fd, uint16_t item, uint8_t count);
int sc_setHeldItem (int client_fd, uint8_t slot);
Expand Down
5 changes: 5 additions & 0 deletions include/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ uint8_t readByte (int client_fd);
uint16_t readUint16 (int client_fd);
int16_t readInt16 (int client_fd);
uint32_t readUint32 (int client_fd);
int32_t readInt32 (int client_fd);
uint64_t readUint64 (int client_fd);
int64_t readInt64 (int client_fd);
float readFloat (int client_fd);
Expand All @@ -36,10 +37,14 @@ double readDouble (int client_fd);
ssize_t readLengthPrefixedData (int client_fd);
void readString (int client_fd);
void readStringN (int client_fd, uint32_t max_length);
uint8_t readSlotData(int client_fd, uint16_t *item, uint8_t *count);

uint32_t fast_rand ();
uint64_t splitmix64 (uint64_t state);

uint8_t is_tool(uint16_t item);
uint16_t get_tool_durability(int item);

#ifdef ESP_PLATFORM
#include "esp_timer.h"
#define get_program_time esp_timer_get_time
Expand Down
3 changes: 3 additions & 0 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ PlayerData player_data[MAX_PLAYERS];
int player_data_count = 0;

MobData mob_data[MAX_MOBS];

uint16_t tools[] = TOOLS;
uint16_t tool_durability[] = TOOL_DURABILITY;
105 changes: 87 additions & 18 deletions src/packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,14 +441,15 @@ int sc_keepAlive (int client_fd) {
}

// S->C Set Container Slot
int sc_setContainerSlot (int client_fd, int window_id, uint16_t slot, uint8_t count, uint16_t item) {
int sc_setContainerSlotWithComponent (int client_fd, int window_id, uint16_t slot, uint8_t count, uint16_t item, uint8_t component_to_add_amount, uint8_t component_type, uint16_t component_content) {

writeVarInt(client_fd,
1 +
sizeVarInt(window_id) +
1 + 2 +
sizeVarInt(count) +
(count > 0 ? sizeVarInt(item) + 2 : 0)
(count > 0 ? sizeVarInt(item) + sizeVarInt(component_to_add_amount) + 1 +
(component_to_add_amount == 1 ? sizeVarInt(component_type) + sizeVarInt(component_content) : 0) : 0)// ← length of "Components to add" array
);
writeByte(client_fd, 0x14);

Expand All @@ -459,14 +460,35 @@ int sc_setContainerSlot (int client_fd, int window_id, uint16_t slot, uint8_t co
writeVarInt(client_fd, count);
if (count > 0) {
writeVarInt(client_fd, item);
writeVarInt(client_fd, component_to_add_amount);
writeVarInt(client_fd, 0);
writeVarInt(client_fd, 0);
if (component_to_add_amount == 1) {
writeVarInt(client_fd, component_type);
writeVarInt(client_fd, component_content);
}
}

return 0;

}

// The original Set Container Slot function
int sc_setContainerSlot(int client_fd, int window_id, uint16_t slot, uint8_t count, uint16_t item) {

if (is_tool(item)){
if (count > 1) {
uint16_t calc_val = ((uint32_t)(count - 1) * get_tool_durability(item)) / 256;
return sc_setContainerSlotWithComponent(client_fd, window_id, slot, 1, item, 1, 3, (calc_val > 1) ? calc_val : 1);
}
else {
return sc_setContainerSlotWithComponent(client_fd, window_id, slot, 1, item, 0, 0, 0);
}
}
else{
return sc_setContainerSlotWithComponent(client_fd, window_id, slot, count, item, 0, 0, 0);
}
}

// S->C Block Update
int sc_blockUpdate (int client_fd, int64_t x, int64_t y, int64_t z, uint8_t block) {
writeVarInt(client_fd, 9 + sizeVarInt(block_palette[block]));
Expand Down Expand Up @@ -617,6 +639,11 @@ int cs_clickContainer (int client_fd) {
uint16_t *p_item;
uint8_t *p_count;

// Temp vars to prevent durability changes when moving tool in container slots
uint8_t amount = 0;
uint16_t *q_item = NULL;
uint8_t *q_count;

#ifdef ALLOW_CHESTS
// See the handlePlayerUseItem function for more info on this hack
uint8_t *storage_ptr;
Expand Down Expand Up @@ -644,8 +671,21 @@ int cs_clickContainer (int client_fd) {
p_count = &player->inventory_count[slot];
}

if (!readByte(client_fd)) { // no item?
if (!readSlotData(client_fd, &item, &count)) { // no item?
if (slot != 255 && apply_changes) {
if (is_tool(*p_item)) {
player->flagval_8 = *p_count;
player->flagval_16 = *p_item;
if (q_item && is_tool(*q_item)) {
*q_count = *p_count;
#ifdef ALLOW_CHESTS
if (window_id == 2 && amount > 40) {
broadcastChestUpdate(client_fd, storage_ptr, *q_item, *q_count, amount - 41);
}
#endif
}
}

*p_item = 0;
*p_count = 0;
#ifdef ALLOW_CHESTS
Expand All @@ -657,19 +697,49 @@ int cs_clickContainer (int client_fd) {
continue;
}

item = readVarInt(client_fd);
count = (uint8_t)readVarInt(client_fd);

// ignore components
readLengthPrefixedData(client_fd);
readLengthPrefixedData(client_fd);

if (count > 0 && apply_changes) {
if (mode == 1 && button == 0) {
if (is_tool(item)) {
if (is_tool(player->flagval_16)) {
*p_count = player->flagval_8;
*p_item = item;
#ifdef ALLOW_CHESTS
if (window_id == 2 && slot > 40) {
broadcastChestUpdate(client_fd, storage_ptr, item, *p_count, slot - 41);
}
#endif
} else {
q_count = p_count;
q_item = p_item;
#ifdef ALLOW_CHESTS
amount = slot;
#endif
}
} else {
*p_count = count;
}
}
else {
if (is_tool(player->flagval_16)) {
if (is_tool(*p_item)) {
amount = *p_count;
*p_count = player->flagval_8;
player->flagval_8 = amount;
} else {
*p_count = player->flagval_8;
}
} else if (is_tool(*p_item)) {
player->flagval_8 = *p_count;
*p_count = count;
} else {
*p_count = count;
}
}
*p_item = item;
#ifdef ALLOW_CHESTS
if (window_id == 2 && slot > 40) {
broadcastChestUpdate(client_fd, storage_ptr, item, count, slot - 41);
broadcastChestUpdate(client_fd, storage_ptr, item, *p_count, slot - 41);
}
#endif
}
Expand All @@ -688,16 +758,15 @@ int cs_clickContainer (int client_fd) {
}

// assign cursor-carried item slot
if (readByte(client_fd)) {
player->flagval_16 = readVarInt(client_fd);
player->flagval_8 = readVarInt(client_fd);
// ignore components
readLengthPrefixedData(client_fd);
readLengthPrefixedData(client_fd);
} else {
if (!readSlotData(client_fd, &player->flagval_16, &amount)) {
player->flagval_16 = 0;
player->flagval_8 = 0;
}
if (!is_tool(player->flagval_16)){
player->flagval_8 = amount;
} else if (player->flagval_8 == 0) {
player->flagval_8 = 1;
}

return 0;

Expand Down
35 changes: 21 additions & 14 deletions src/procedures.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,27 +717,34 @@ uint16_t getMiningResult (uint16_t held_item, uint8_t block) {

}

// Rolls a random number to determine whether the player's tool should break
// Rolls a random number to determine whether the player's tool should has a durability decrease
void bumpToolDurability (PlayerData *player) {

uint16_t held_item = player->inventory_items[player->hotbar];

// In order to avoid storing durability data, items break randomly with
// the probability weighted based on vanilla durability.
if (is_tool(held_item)) {
uint16_t n = get_tool_durability(held_item);
if (255 - player->inventory_count[player->hotbar] < 255 / n + 1) {
player->inventory_items[player->hotbar] = 0;
player->inventory_count[player->hotbar] = 0;
sc_entityEvent(player->client_fd, player->client_fd, 47);
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), 0, 0);
return;
}

uint32_t r = fast_rand();
if (
((held_item == I_wooden_pickaxe || held_item == I_wooden_axe || held_item == I_wooden_shovel) && r < 72796055) ||
((held_item == I_stone_pickaxe || held_item == I_stone_axe || held_item == I_stone_shovel) && r < 32786009) ||
((held_item == I_iron_pickaxe || held_item == I_iron_axe || held_item == I_iron_shovel) && r < 17179869) ||
((held_item == I_golden_pickaxe || held_item == I_golden_axe || held_item == I_golden_shovel) && r < 134217728) ||
((held_item == I_diamond_pickaxe || held_item == I_diamond_axe || held_item == I_diamond_shovel) && r < 2751420) ||
((held_item == I_netherite_pickaxe || held_item == I_netherite_axe || held_item == I_netherite_shovel) && r < 2114705) ||
(held_item == I_shears && r < 18046081)
) {
player->inventory_items[player->hotbar] = 0;
player->inventory_count[player->hotbar] = 0;
sc_entityEvent(player->client_fd, player->client_fd, 47);
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), 0, 0);
player->inventory_count[player->hotbar] += 255 / n;
if (r < (255 % n) * (UINT32_MAX / n)) {
player->inventory_count[player->hotbar] += 1;
}

// the first using of a tool cost at least 1 durability
if (player->inventory_count[player->hotbar] == 1){
player->inventory_count[player->hotbar] += 1;
}
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, player->hotbar), player->inventory_count[player->hotbar], held_item);
}

}
Expand Down
44 changes: 44 additions & 0 deletions src/tools.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,13 @@ uint32_t readUint32 (int client_fd) {
((uint32_t)recv_buffer[2] << 8) |
((uint32_t)recv_buffer[3]);
}
int32_t readInt32 (int client_fd) {
recv_count = recv_all(client_fd, recv_buffer, 4, false);
return ((int32_t)recv_buffer[0] << 24) |
((int32_t)recv_buffer[1] << 16) |
((int32_t)recv_buffer[2] << 8) |
((int32_t)recv_buffer[3]);
}
uint64_t readUint64 (int client_fd) {
recv_count = recv_all(client_fd, recv_buffer, 8, false);
return ((uint64_t)recv_buffer[0] << 56) |
Expand Down Expand Up @@ -268,6 +275,29 @@ void readStringN (int client_fd, uint32_t max_length) {
}
}

// Reads a Slot Data and return if there is any item
uint8_t readSlotData(int client_fd, uint16_t *item, uint8_t *count) {
if (readByte(client_fd)) {
*item = readVarInt(client_fd);
*count = (uint8_t)readVarInt(client_fd);

// ignore components
uint8_t component_count = readVarInt(client_fd);
for (uint8_t i = 0; i < component_count; i++) {
readVarInt(client_fd);
readInt32(client_fd);
}
component_count = readVarInt(client_fd);
for (uint8_t i = 0; i < component_count; i++) {
readVarInt(client_fd);
}

return true;
}

return false;
}

uint32_t fast_rand () {
rng_seed ^= rng_seed << 13;
rng_seed ^= rng_seed >> 17;
Expand All @@ -282,6 +312,20 @@ uint64_t splitmix64 (uint64_t state) {
return z ^ (z >> 31);
}

uint8_t is_tool(uint16_t item) {
for (uint8_t i = 0; i < TOOL_COUNT; i++) {
if (tools[i] == item) return 1;
}
return 0;
}

uint16_t get_tool_durability(int item) {
for (uint8_t i = 0; i < TOOL_COUNT; i++) {
if (tools[i] == item) return tool_durability[i];
}
return 0;
}

#ifndef ESP_PLATFORM
// Returns system time in microseconds.
// On ESP-IDF, this is available in "esp_timer.h", and returns time *since
Expand Down