Дальний вид мира: сетка высот и цвета

- Новый пакет LOD_REGION: сервер отдаёт участок дальнего вида — сетку высот
  и цветов, по одной пробе каждые 4 блока.
- LodGenerator на сервере считает участки от начала мира, держит их в
  памяти и пишет на диск рядом с миром, чтобы считать один раз.
- Клиент строит из участка сетку и рисует своим шейдером (#version 330) до
  обычных чанков: чанки ближе и подробнее, поэтому закрывают дальний вид.
- Дальний вид приходит по мере того, как игрок ходит по миру: сервер шлёт
  участки вокруг него раз в тик.

Проверки в сервере 96, в протоколе 24, в клиенте 128.
This commit is contained in:
sasheg dev
2026-10-22 10:28:51 +03:00
parent 30cffa19da
commit b5fb57bb4f
11 changed files with 845 additions and 0 deletions
@@ -158,6 +158,9 @@ public final class Packets {
/** The client asks the server to read its box file again. */
public static final int HITBOXES_RELOAD = 0x2C;
/** A piece of the far view: the ground of one region, in a grid. */
public static final int LOD_REGION = 0x34;
/** The client hits something. */
public static final int ATTACK = 0x2D;
@@ -1834,6 +1837,66 @@ public final class Packets {
}
}
/**
* A piece of the far view.
*
* The far view is the ground of the world seen from far away: a grid of
* heights and colours, one sample every few blocks. The client turns it
* into a mesh and draws it beyond the chunks that are loaded.
*/
public static final class LodRegion implements Packet {
/** The block the region starts at. */
public final int originX;
public final int originZ;
/** How many blocks there are between two samples. */
public final int step;
/** How many samples there are on a side. */
public final int size;
/** The height of every sample, in blocks. */
public final byte[] heights;
/** The colour of every sample: three bytes each, red green blue. */
public final byte[] colors;
public LodRegion(int originX, int originZ, int step, int size, byte[] heights,
byte[] colors) {
this.originX = originX;
this.originZ = originZ;
this.step = step;
this.size = size;
this.heights = heights;
this.colors = colors;
}
public Buf write() {
Buf buf = new Buf(32 + this.heights.length + this.colors.length);
buf.writeVarInt(this.originX);
buf.writeVarInt(this.originZ);
buf.writeVarInt(this.step);
buf.writeVarInt(this.size);
buf.writeBytes(this.heights);
buf.writeBytes(this.colors);
return buf;
}
public static LodRegion read(Buf in) {
int originX = in.readVarInt();
int originZ = in.readVarInt();
int step = in.readVarInt();
int size = in.readVarInt();
if (size < 0 || size > 1024) {
throw new ProtocolException("that many samples is not real");
}
byte[] heights = in.readBytes(size * size);
byte[] colors = in.readBytes(size * size * 3);
return new LodRegion(originX, originZ, step, size, heights, colors);
}
}
/**
* Every packet id this build knows, and what it decodes into.
*
@@ -1877,6 +1940,7 @@ public final class Packets {
map.put(Integer.valueOf(HITBOXES), "Hitboxes");
map.put(Integer.valueOf(HITBOX_INSTANCES), "HitboxInstances");
map.put(Integer.valueOf(HITBOXES_RELOAD), "HitboxesReload");
map.put(Integer.valueOf(LOD_REGION), "LodRegion");
map.put(Integer.valueOf(ATTACK), "Attack");
map.put(Integer.valueOf(CHAT), "Chat");
map.put(Integer.valueOf(CHAT_SEND), "ChatSend");