From afc1f48d5e41f9730348005ae33808f53416b439 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:09:47 -0400 Subject: [PATCH] Use custom class for caching chunk data Right now, our chunk cache stores the heightmap and biome data that the server sends, which we never use. This commit saves that data in a custom GeyserColumn class that only stores chunk data. In the future, it may also store NBT data. --- .../network/session/cache/ChunkCache.java | 23 ++++++-- .../translators/world/chunk/GeyserColumn.java | 57 +++++++++++++++++++ .../geysermc/connector/utils/ChunkUtils.java | 1 + 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/GeyserColumn.java diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java index 393a1f188..4f93b0f53 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java @@ -32,14 +32,17 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.chunk.GeyserColumn; import org.geysermc.connector.utils.MathUtils; public class ChunkCache { private final boolean cache; - private final Long2ObjectMap chunks; + private final Long2ObjectMap chunks; @Setter private int minY; + @Setter + private int heightY; public ChunkCache(GeyserSession session) { this.cache = !session.getConnector().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing @@ -51,10 +54,12 @@ public class ChunkCache { return; } - chunks.put(MathUtils.chunkPositionToLong(chunk.getX(), chunk.getZ()), chunk); + long chunkPosition = MathUtils.chunkPositionToLong(chunk.getX(), chunk.getZ()); + GeyserColumn geyserColumn = GeyserColumn.from(this, chunk); + chunks.put(chunkPosition, geyserColumn); } - public Column getChunk(int chunkX, int chunkZ) { + public GeyserColumn getChunk(int chunkX, int chunkZ) { long chunkPosition = MathUtils.chunkPositionToLong(chunkX, chunkZ); return chunks.getOrDefault(chunkPosition, null); } @@ -64,7 +69,7 @@ public class ChunkCache { return; } - Column column = this.getChunk(x >> 4, z >> 4); + GeyserColumn column = this.getChunk(x >> 4, z >> 4); if (column == null) { return; } @@ -77,8 +82,10 @@ public class ChunkCache { Chunk chunk = column.getChunks()[(y >> 4) - getChunkMinY()]; if (chunk == null) { if (block != BlockTranslator.JAVA_AIR_ID) { - chunk = new Chunk(); // A previously empty chunk, which is no longer empty as a block has been added to it + chunk = new Chunk(); + // Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug + chunk.getPalette().stateToId(BlockTranslator.JAVA_AIR_ID); column.getChunks()[(y >> 4) - getChunkMinY()] = chunk; } else { // Nothing to update @@ -94,7 +101,7 @@ public class ChunkCache { return BlockTranslator.JAVA_AIR_ID; } - Column column = this.getChunk(x >> 4, z >> 4); + GeyserColumn column = this.getChunk(x >> 4, z >> 4); if (column == null) { return BlockTranslator.JAVA_AIR_ID; } @@ -124,4 +131,8 @@ public class ChunkCache { public int getChunkMinY() { return minY >> 4; } + + public int getChunkHeightY() { + return heightY >> 4; + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/GeyserColumn.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/GeyserColumn.java new file mode 100644 index 000000000..3da5787a5 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/GeyserColumn.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.world.chunk; + +import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; +import com.github.steveice10.mc.protocol.data.game.chunk.Column; +import lombok.Getter; +import org.geysermc.connector.network.session.cache.ChunkCache; + +/** + * Acts as a lightweight version of {@link Column} that doesn't store + * biomes or heightmaps. + */ +public class GeyserColumn { + @Getter + private final Chunk[] chunks; + + private GeyserColumn(Chunk[] chunks) { + this.chunks = chunks; + } + + public static GeyserColumn from(ChunkCache chunkCache, Column column) { + int chunkHeightY = chunkCache.getChunkHeightY(); + Chunk[] chunks; + if (chunkHeightY < column.getChunks().length) { + chunks = new Chunk[chunkHeightY]; + // TODO addresses https://github.com/Steveice10/MCProtocolLib/pull/598#issuecomment-862782392 + System.arraycopy(column.getChunks(), 0, chunks, 0, chunks.length); + } else { + chunks = column.getChunks(); + } + return new GeyserColumn(chunks); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 85b7f8600..343f5c53e 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -419,6 +419,7 @@ public class ChunkUtils { } session.getChunkCache().setMinY(minY); + session.getChunkCache().setHeightY(maxY); } @Data