Модель предметов по базе ремейка: узлы, деревья, знание

Протокол:
- ItemData читает таблицу items/items.csv (218 предметов ремейка) и отдает
  числа: урон, дальность, темп, прочность, сколько ресурса за удар.
- ItemType: поля rid, researchScrap, techTreeBench, techTreeScrap,
  techTreeParent, admin. Урон по частям тела делится как в ремейке: голова
  вдвое, руки и ноги четыре пятых. Число в исходнике главнее таблицы.
- ItemRegistry: 218 предметов с рецептами, ценой исследования и веткой
  дерева. Новые вещи: salvage-тесак, бронедвери, гаражи, взрывчатка,
  компоненты, еда, мусор, верстаки и печи.
- NodeType: узлы с запасом (дерево 500/750/1000, камень 750, металл 500,
  сера 200) и меткой: крестик на дереве до двух, горячая точка на руде до
  трех.
- TechTree: ветки верстаков с предками, 125/250/500 скрапа.
- Новые пакеты: Dig, BreakProgress, CraftStart, CraftUpdate, ResearchStart,
  ResearchUpdate, TechTreeUnlock, KnownRecipes, TechTreeState, ContainerOpen,
  ContainerTake, LearnBlueprint.

Сервер:
- Knowledge: что игрок знает - рецепты и открытые узлы деревьев.
- Crafter: проверка рецепта, уровня верстака и ингредиентов; время крафта
  по формуле плана.
- ResearchTable: предмет плюс скрап, десять секунд, предмет превращается в
  чертёж; чертёж изучается и открывает рецепт.
- ResourceNode: запас, метка, последний удар отдает остаток.
- JunkPile: две-четыре бочки (серая - скрап и мусор, синяя - компонент,
  красная - нефть и топливо) и ящик с едой; пустая мусорка исчезает через
  60-180 секунд.
- RoadNetwork: сетка дорог и кольцо, точки спавна мусорки; генератор кладет
  асфальт и ровняет дорогу по ширине.
- Проверка досягаемости вынесена из changeBlock, игрок получил benchLevel.
- Сессия отвечает на новые пакеты, при входе шлет известные рецепты и
  открытые узлы.

Тесты: протокол 24 + 10, сервер 74 (было 57). Форк собирается чисто.
This commit is contained in:
sasheg dev
2026-10-21 19:54:22 +03:00
parent 27047e8071
commit cda7198c76
25 changed files with 3409 additions and 108 deletions
@@ -113,6 +113,42 @@ public final class Packets {
/** One slot of the inventory, when it changes. */
public static final int INVENTORY_SLOT = 0x1D;
/** The client starts or stops digging. */
public static final int DIG = 0x1E;
/** How far the digging has come, for the cracks. */
public static final int BREAK_PROGRESS = 0x1F;
/** The client asks to make something. */
public static final int CRAFT_START = 0x20;
/** What the server says about a craft. */
public static final int CRAFT_UPDATE = 0x21;
/** The client asks to research an item at the research table. */
public static final int RESEARCH_START = 0x22;
/** What the server says about a research. */
public static final int RESEARCH_UPDATE = 0x23;
/** The client asks to open a node of the tree of a workbench. */
public static final int TECH_TREE_UNLOCK = 0x24;
/** The recipes the player knows. */
public static final int KNOWN_RECIPES = 0x25;
/** The nodes of the trees the player has opened. */
public static final int TECH_TREE_STATE = 0x26;
/** A container the player may look into. */
public static final int CONTAINER_OPEN = 0x27;
/** The client takes something out of a container. */
public static final int CONTAINER_TAKE = 0x28;
/** The client learns a blueprint. */
public static final int LEARN_BLUEPRINT = 0x29;
/**
* One slot of the inventory and what is in it now.
*
@@ -948,6 +984,394 @@ public final class Packets {
}
}
/**
* The client starts or stops digging.
*
* The client does not decide anything: it says where it is looking and
* whether the button is down. The server works out what happens there,
* how long it takes and who is allowed to do it.
*/
public static final class Dig implements Packet {
/** The button went down. */
public static final int START = 0;
/** The button came up. */
public static final int STOP = 1;
public final int action;
public final int x;
public final int y;
public final int z;
public final int face;
public Dig(int action, int x, int y, int z, int face) {
this.action = action;
this.x = x;
this.y = y;
this.z = z;
this.face = face;
}
public boolean start() {
return this.action == START;
}
public Buf write() {
Buf buf = new Buf(24);
buf.writeVarInt(this.action);
buf.writeVarInt(this.x);
buf.writeVarInt(this.y);
buf.writeVarInt(this.z);
buf.writeVarInt(this.face);
return buf;
}
public static Dig read(Buf in) {
return new Dig(in.readVarInt(), in.readVarInt(), in.readVarInt(),
in.readVarInt(), in.readVarInt());
}
}
/**
* How far the digging has come, so that everybody sees the cracks.
*
* The stage goes from zero to nine. A stage of minus one means that
* nothing is being dug at that place.
*/
public static final class BreakProgress implements Packet {
/** The stage of the cracks, from zero to nine. */
public static final int STAGES = 10;
public final int x;
public final int y;
public final int z;
public final int stage;
public BreakProgress(int x, int y, int z, int stage) {
this.x = x;
this.y = y;
this.z = z;
this.stage = stage;
}
public Buf write() {
Buf buf = new Buf(24);
buf.writeVarInt(this.x);
buf.writeVarInt(this.y);
buf.writeVarInt(this.z);
buf.writeVarInt(this.stage);
return buf;
}
public static BreakProgress read(Buf in) {
return new BreakProgress(in.readVarInt(), in.readVarInt(), in.readVarInt(),
in.readVarInt());
}
}
/**
* The client asks to make something.
*
* The server looks the recipe up, checks the workbench and the knowledge
* of the player, and answers with a {@link CraftUpdate}.
*/
public static final class CraftStart implements Packet {
public final int item;
public final int count;
public CraftStart(int item, int count) {
this.item = item;
this.count = count;
}
public Buf write() {
Buf buf = new Buf(8);
buf.writeVarInt(this.item);
buf.writeVarInt(this.count);
return buf;
}
public static CraftStart read(Buf in) {
return new CraftStart(in.readVarInt(), in.readVarInt());
}
}
/**
* What the server says about a craft.
*
* The seconds left go down while the work goes on. When it reaches zero
* the item is in the inventory. A reason that is not empty means that
* nothing was made, and says why.
*/
public static final class CraftUpdate implements Packet {
public final int item;
public final int count;
public final int secondsLeft;
public final String reason;
public CraftUpdate(int item, int count, int secondsLeft, String reason) {
this.item = item;
this.count = count;
this.secondsLeft = secondsLeft;
this.reason = reason == null ? "" : reason;
}
public boolean ok() {
return this.reason.isEmpty();
}
public Buf write() {
Buf buf = new Buf(64);
buf.writeVarInt(this.item);
buf.writeVarInt(this.count);
buf.writeVarInt(this.secondsLeft);
buf.writeString(this.reason);
return buf;
}
public static CraftUpdate read(Buf in) {
return new CraftUpdate(in.readVarInt(), in.readVarInt(), in.readVarInt(),
in.readString(MAX_TEXT));
}
}
/**
* The client asks to research an item at the research table.
*
* The server checks that the player has the item and the scrap, takes
* both and answers with a {@link ResearchUpdate}.
*/
public static final class ResearchStart implements Packet {
public final int item;
public ResearchStart(int item) {
this.item = item;
}
public Buf write() {
Buf buf = new Buf(8);
buf.writeVarInt(this.item);
return buf;
}
public static ResearchStart read(Buf in) {
return new ResearchStart(in.readVarInt());
}
}
/** What the server says about a research. */
public static final class ResearchUpdate implements Packet {
public final int item;
public final int secondsLeft;
public final String reason;
public ResearchUpdate(int item, int secondsLeft, String reason) {
this.item = item;
this.secondsLeft = secondsLeft;
this.reason = reason == null ? "" : reason;
}
public boolean ok() {
return this.reason.isEmpty();
}
public Buf write() {
Buf buf = new Buf(64);
buf.writeVarInt(this.item);
buf.writeVarInt(this.secondsLeft);
buf.writeString(this.reason);
return buf;
}
public static ResearchUpdate read(Buf in) {
return new ResearchUpdate(in.readVarInt(), in.readVarInt(), in.readString(MAX_TEXT));
}
}
/**
* The client asks to open a node of the tree of a workbench.
*
* The server checks that the branch is open and that there is enough
* scrap, and takes the scrap.
*/
public static final class TechTreeUnlock implements Packet {
public final int item;
public TechTreeUnlock(int item) {
this.item = item;
}
public Buf write() {
Buf buf = new Buf(8);
buf.writeVarInt(this.item);
return buf;
}
public static TechTreeUnlock read(Buf in) {
return new TechTreeUnlock(in.readVarInt());
}
}
/** The recipes the player knows. */
public static final class KnownRecipes implements Packet {
public final int[] items;
public KnownRecipes(int[] items) {
this.items = items;
}
public Buf write() {
Buf buf = new Buf(8 + this.items.length * 4);
buf.writeVarInt(this.items.length);
for (int i = 0; i < this.items.length; i++) {
buf.writeVarInt(this.items[i]);
}
return buf;
}
public static KnownRecipes read(Buf in) {
int count = in.readVarInt();
if (count < 0 || count > 4096) {
throw new ProtocolException("that many recipes is not real");
}
int[] items = new int[count];
for (int i = 0; i < count; i++) {
items[i] = in.readVarInt();
}
return new KnownRecipes(items);
}
}
/** The nodes of the trees the player has opened. */
public static final class TechTreeState implements Packet {
public final int[] items;
public TechTreeState(int[] items) {
this.items = items;
}
public Buf write() {
Buf buf = new Buf(8 + this.items.length * 4);
buf.writeVarInt(this.items.length);
for (int i = 0; i < this.items.length; i++) {
buf.writeVarInt(this.items[i]);
}
return buf;
}
public static TechTreeState read(Buf in) {
int count = in.readVarInt();
if (count < 0 || count > 4096) {
throw new ProtocolException("that many nodes is not real");
}
int[] items = new int[count];
for (int i = 0; i < count; i++) {
items[i] = in.readVarInt();
}
return new TechTreeState(items);
}
}
/**
* A container the player may look into: a crate of food on a junk pile,
* a chest, a barrel.
*/
public static final class ContainerOpen implements Packet {
public final int id;
public final String title;
public final Slot[] slots;
public ContainerOpen(int id, String title, Slot[] slots) {
this.id = id;
this.title = title == null ? "" : title;
this.slots = slots;
}
public Buf write() {
Buf buf = new Buf(64 + this.slots.length * 12);
buf.writeVarInt(this.id);
buf.writeString(this.title);
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 ContainerOpen read(Buf in) {
int id = in.readVarInt();
String title = in.readString(MAX_TEXT);
int count = in.readVarInt();
if (count < 0 || count > 1024) {
throw new ProtocolException("a container 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 ContainerOpen(id, title, slots);
}
}
/** The client takes something out of a container. */
public static final class ContainerTake implements Packet {
public final int id;
public final int slot;
public ContainerTake(int id, int slot) {
this.id = id;
this.slot = slot;
}
public Buf write() {
Buf buf = new Buf(8);
buf.writeVarInt(this.id);
buf.writeVarInt(this.slot);
return buf;
}
public static ContainerTake read(Buf in) {
return new ContainerTake(in.readVarInt(), in.readVarInt());
}
}
/**
* The client asks to learn a blueprint.
*
* A blueprint is the item with a mark on it. Learning it uses it up and
* opens the recipe for good.
*/
public static final class LearnBlueprint implements Packet {
public final int item;
public LearnBlueprint(int item) {
this.item = item;
}
public Buf write() {
Buf buf = new Buf(8);
buf.writeVarInt(this.item);
return buf;
}
public static LearnBlueprint read(Buf in) {
return new LearnBlueprint(in.readVarInt());
}
}
/**
* Every packet id this build knows, and what it decodes into.
*
@@ -974,6 +1398,20 @@ public final class Packets {
map.put(Integer.valueOf(ENTITY_REMOVE), "EntityRemove");
map.put(Integer.valueOf(LAUNCHER_AUTH), "LauncherAuth");
map.put(Integer.valueOf(SET_GAME_MODE), "GameMode");
map.put(Integer.valueOf(INVENTORY), "Inventory");
map.put(Integer.valueOf(INVENTORY_SLOT), "SlotChange");
map.put(Integer.valueOf(DIG), "Dig");
map.put(Integer.valueOf(BREAK_PROGRESS), "BreakProgress");
map.put(Integer.valueOf(CRAFT_START), "CraftStart");
map.put(Integer.valueOf(CRAFT_UPDATE), "CraftUpdate");
map.put(Integer.valueOf(RESEARCH_START), "ResearchStart");
map.put(Integer.valueOf(RESEARCH_UPDATE), "ResearchUpdate");
map.put(Integer.valueOf(TECH_TREE_UNLOCK), "TechTreeUnlock");
map.put(Integer.valueOf(KNOWN_RECIPES), "KnownRecipes");
map.put(Integer.valueOf(TECH_TREE_STATE), "TechTreeState");
map.put(Integer.valueOf(CONTAINER_OPEN), "ContainerOpen");
map.put(Integer.valueOf(CONTAINER_TAKE), "ContainerTake");
map.put(Integer.valueOf(LEARN_BLUEPRINT), "LearnBlueprint");
map.put(Integer.valueOf(DISCONNECT), "Disconnect");
return map;
}