Мир перестаёт стучить при ходьбе
Статтеры были не на сервере, а в клиенте, и стоили дорого. Измерено: перевод чанка в игровой формат шел через setBlockState, а он каждый раз обновляет карту высот и карту света. Чанк стоил 10-156 мс на главном потоке, их было 208, и переход через границу чанка упирался в 325 мс за один тик. Сделано: - Секции чанка пишутся прямо в формате игры. Палитра и упакованные индексы строятся игровым же классом, так что формат совпадает по определению, а заливка по блокам и карты высот и света не нужны. Чанк подешевел с 25 мс до 1-2 мс, это в 15-25 раз. - Обработка входящих пакетов ограничена тремя миллисекундами на тик. Колонка чанков, пришедшая за один раз, теперь размазывается по тикам: не влезшее ждет следующего, это 0.2 секунды, и глазом не видно. - Сгенерированный чанк больше не считается грязным. Террейн есть чистая функция от зерна и координат, он и так восстановится за пару миллисекунд, а писать его стоило 64 килобайта на чанк. Ходьба по миру больше не гоняет двадцать мегабайт по диску. На диск пишется только то, во что игрок построился. Проверено: 169 чанков при заходе, медленных (больше 4 мс) три, остальные быстрее; на диске ноль файлов, потому что игрок ничего не строил.
This commit is contained in:
@@ -81,7 +81,11 @@ public final class Chunk {
|
||||
|
||||
void markGenerated() {
|
||||
this.generated = true;
|
||||
this.dirty = true;
|
||||
// a generated chunk is not dirty. The terrain is a pure function of the
|
||||
// seed and the position, so it can be generated again in a moment, and
|
||||
// writing it out costs sixty four kilobytes a chunk for nothing. Only
|
||||
// a chunk somebody built in is worth the disk.
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
|
||||
@@ -572,23 +572,35 @@ public final class WorldTest {
|
||||
ChunkStorage storage = new ChunkStorage(dir);
|
||||
World world = new World(11L, storage);
|
||||
ChunkPos pos = new ChunkPos(5, 5);
|
||||
ChunkPos built = new ChunkPos(6, 6);
|
||||
world.chunkAt(pos);
|
||||
eq("one chunk in memory", Integer.valueOf(1), Integer.valueOf(world.loadedChunks()));
|
||||
world.chunkAt(built);
|
||||
// one chunk is only walked over, the other is built in: the grass at
|
||||
// the surface is replaced with stone
|
||||
int surface = world.generator().heightAt(6 * Chunk.WIDTH, 6 * Chunk.WIDTH);
|
||||
world.setBlock(6 * Chunk.WIDTH, surface, 6 * Chunk.WIDTH, Blocks.STONE);
|
||||
eq("two chunks in memory", Integer.valueOf(2), Integer.valueOf(world.loadedChunks()));
|
||||
|
||||
for (int i = 0; i < (int) World.EVICT_AFTER_TICKS + 10; i++) {
|
||||
world.tick();
|
||||
}
|
||||
int dropped = world.evictIdle();
|
||||
eq("it was dropped", Integer.valueOf(1), Integer.valueOf(dropped));
|
||||
eq("they were dropped", Integer.valueOf(2), Integer.valueOf(dropped));
|
||||
eq("nothing left in memory", Integer.valueOf(0), Integer.valueOf(world.loadedChunks()));
|
||||
eq("one chunk evicted", Long.valueOf(1L), Long.valueOf(world.evictedCount()));
|
||||
yes("and it is on disk", storage.exists(pos));
|
||||
eq("two chunks evicted", Long.valueOf(2L), Long.valueOf(world.evictedCount()));
|
||||
|
||||
// and it comes back with the same terrain
|
||||
Chunk back = world.chunkAt(pos);
|
||||
// a chunk somebody built in is worth the disk, and comes back
|
||||
yes("the built one is on disk", storage.exists(built));
|
||||
// a chunk that was only walked over is not: the terrain is generated
|
||||
// again in a moment, and writing it out would cost sixty four
|
||||
// kilobytes a chunk for nothing
|
||||
yes("the untouched one is not", !storage.exists(pos));
|
||||
|
||||
Chunk back = world.chunkAt(built);
|
||||
yes("it came back", back.isGenerated());
|
||||
eq("with the same surface",
|
||||
Integer.valueOf(world.generator().heightAt(5 * Chunk.WIDTH, 5 * Chunk.WIDTH) + 1),
|
||||
eq("with the build in it", Byte.valueOf(Blocks.STONE),
|
||||
Byte.valueOf(back.block(0, surface, 0)));
|
||||
eq("and the surface is where it was", Integer.valueOf(surface + 1),
|
||||
Integer.valueOf(back.surfaceHeight(0, 0)));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user