Шаг A: предметы и инвентарь
Фундамент предметов по данным плана (срез 11.2025) и серверный инвентарь. В протоколе (общий словарь для клиента и сервера): - ToolClass, ResourceClass - что чем ломается и что где лежит. - ItemType - определение предмета: класс инструмента, урон по четырем частям тела, прочность, Gather Rates по каждому классу ресурса (сколько снимает удар, разброс, сколько уходит прочности инструмента), bench - требуемый уровень верстака, knownByDefault - открыт ли рецепт с начала игры, admin - только ли админы сервера. - ItemRegistry - таблица предметов. Числа из плана, каждое в одном месте, чтобы игра и план не разъехались. - Recipe - ингредиенты, количество, базовое время крафта. - ItemStack - тип, количество, остаток прочности и свои данные на стеке (как теги у плагина в Paper): стек - это то, что путешествует. Пакеты: Inventory (весь инвентарь при входе) и SlotChange (один слот). На сервере: Inventory - 30 слотов, хотбар 6, сервер владеет инвентарем и сообщает клиенту, а не спрашивает. Стартовый набор - камень в первом слоте и в руке. Тесты: предметы закреплены числами из плана (камень бьёт в голову на 20, снимает 10 дерева и 5 руды; кирка не рубит дерево; меч не ломает вообще), инвентарь переживает провод, сумка наполняется и опустошается, полная сумма говорит об этом. Замечание: прогрессия крафта в Rust упирается в лутбоксы - скрап падает только из них, а чертёж требует найденного предмета. Это отдельный вопрос (п. 5.2 плана), он не блокирует предметы и инвентарь.
This commit is contained in:
@@ -102,6 +102,52 @@ public final class Packets {
|
||||
*/
|
||||
public static final int LAUNCHER_AUTH = 0x1A;
|
||||
|
||||
/**
|
||||
* The whole inventory, sent when the player arrives.
|
||||
*
|
||||
* The server is the only one who decides what is in the slots, so the
|
||||
* client is told rather than asked.
|
||||
*/
|
||||
public static final int INVENTORY = 0x1C;
|
||||
|
||||
/** One slot of the inventory, when it changes. */
|
||||
public static final int INVENTORY_SLOT = 0x1D;
|
||||
|
||||
/**
|
||||
* One slot of the inventory and what is in it now.
|
||||
*
|
||||
* The slot number is here because the client has to know which one to
|
||||
* redraw, and the contents because it has no way of guessing them.
|
||||
*/
|
||||
public static final class SlotChange implements Packet {
|
||||
|
||||
public final int slot;
|
||||
public final int item;
|
||||
public final int count;
|
||||
public final int condition;
|
||||
|
||||
public SlotChange(int slot, int item, int count, int condition) {
|
||||
this.slot = slot;
|
||||
this.item = item;
|
||||
this.count = count;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public Buf write() {
|
||||
Buf buf = new Buf(24);
|
||||
buf.writeVarInt(this.slot);
|
||||
buf.writeVarInt(this.item);
|
||||
buf.writeVarInt(this.count);
|
||||
buf.writeVarInt(this.condition);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static SlotChange read(Buf in) {
|
||||
return new SlotChange(in.readVarInt(), in.readVarInt(), in.readVarInt(),
|
||||
in.readVarInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The player's game mode, changed while the player is in the world.
|
||||
*
|
||||
@@ -796,6 +842,80 @@ public final class Packets {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* One slot of an inventory.
|
||||
*
|
||||
* The empty slot is a stack of nothing, so there is no special case: an
|
||||
* empty slot is one with the id of nothing and a count of zero.
|
||||
*/
|
||||
public static final class Slot {
|
||||
|
||||
public final int item;
|
||||
public final int count;
|
||||
public final int condition;
|
||||
|
||||
public Slot(int item, int count, int condition) {
|
||||
this.item = item;
|
||||
this.count = count;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public static Slot of(ItemStack stack) {
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
return new Slot(ItemRegistry.NOTHING, 0, -1);
|
||||
}
|
||||
return new Slot(stack.item, stack.count, stack.condition);
|
||||
}
|
||||
|
||||
public void write(Buf buf) {
|
||||
buf.writeVarInt(this.item);
|
||||
buf.writeVarInt(this.count);
|
||||
buf.writeVarInt(this.condition);
|
||||
}
|
||||
|
||||
public static Slot read(Buf in) {
|
||||
return new Slot(in.readVarInt(), in.readVarInt(), in.readVarInt());
|
||||
}
|
||||
}
|
||||
|
||||
/** The whole inventory of a player. */
|
||||
public static final class Inventory implements Packet {
|
||||
|
||||
public final Slot[] slots;
|
||||
|
||||
/** The slot the player is holding. */
|
||||
public final int held;
|
||||
|
||||
public Inventory(Slot[] slots, int held) {
|
||||
this.slots = slots;
|
||||
this.held = held;
|
||||
}
|
||||
|
||||
public Buf write() {
|
||||
Buf buf = new Buf(16 + this.slots.length * 12);
|
||||
buf.writeVarInt(this.held);
|
||||
buf.writeVarInt(this.slots.length);
|
||||
for (int i = 0; i < this.slots.length; i++) {
|
||||
Slot slot = this.slots[i] == null ? Slot.of(null) : this.slots[i];
|
||||
slot.write(buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static Inventory read(Buf in) {
|
||||
int held = in.readVarInt();
|
||||
int count = in.readVarInt();
|
||||
if (count < 0 || count > 1024) {
|
||||
throw new ProtocolException("an inventory of " + count + " slots is not real");
|
||||
}
|
||||
Slot[] slots = new Slot[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
slots[i] = Slot.read(in);
|
||||
}
|
||||
return new Inventory(slots, held);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The launcher's session, as the game server sees it.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user