forked from GeyserMC/Geyser
Non-full-chunk support (#574)
This commit adds non-full chunk support if chunk caching is enabled.
This commit is contained in:
parent
4c58568eb4
commit
5b76a85895
10 changed files with 320 additions and 17 deletions
|
@ -42,7 +42,7 @@ public class ChunkCache {
|
|||
private final boolean cache;
|
||||
|
||||
@Getter
|
||||
private Map<ChunkPosition, Column> chunks = new HashMap<>();
|
||||
private final Map<ChunkPosition, Column> chunks = new HashMap<>();
|
||||
|
||||
public ChunkCache(GeyserSession session) {
|
||||
if (session.getConnector().getWorldManager().getClass() == GeyserBootstrap.DEFAULT_CHUNK_MANAGER.getClass()) {
|
||||
|
@ -57,6 +57,15 @@ public class ChunkCache {
|
|||
return;
|
||||
}
|
||||
ChunkPosition position = new ChunkPosition(chunk.getX(), chunk.getZ());
|
||||
if (chunk.getBiomeData() == null && chunks.containsKey(position)) {
|
||||
Column newColumn = chunk;
|
||||
chunk = chunks.get(position);
|
||||
for (int i = 0; i < newColumn.getChunks().length; i++) {
|
||||
if (newColumn.getChunks()[i] != null) {
|
||||
chunk.getChunks()[i] = newColumn.getChunks()[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
chunks.put(position, chunk);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,18 +45,33 @@ import org.geysermc.connector.utils.ChunkUtils;
|
|||
@Translator(packet = ServerChunkDataPacket.class)
|
||||
public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPacket> {
|
||||
|
||||
/**
|
||||
* Determines if we should process non-full chunks
|
||||
*/
|
||||
private final boolean isCacheChunks;
|
||||
|
||||
public JavaChunkDataTranslator() {
|
||||
isCacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(ServerChunkDataPacket packet, GeyserSession session) {
|
||||
if (session.isSpawned()) {
|
||||
ChunkUtils.updateChunkPosition(session, session.getPlayerEntity().getPosition().toInt());
|
||||
}
|
||||
|
||||
if (packet.getColumn().getBiomeData() == null) //Non-full chunk
|
||||
if (packet.getColumn().getBiomeData() == null && !isCacheChunks) {
|
||||
// Non-full chunk without chunk caching
|
||||
session.getConnector().getLogger().debug("Not sending non-full chunk because chunk caching is off.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-full chunks don't have all the chunk data, and Bedrock won't accept that
|
||||
final boolean isNonFullChunk = (packet.getColumn().getBiomeData() == null);
|
||||
|
||||
GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> {
|
||||
try {
|
||||
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn());
|
||||
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, packet.getColumn(), isNonFullChunk);
|
||||
ByteBuf byteBuf = Unpooled.buffer(32);
|
||||
ChunkSection[] sections = chunkData.sections;
|
||||
|
||||
|
@ -71,7 +86,12 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
section.writeToNetwork(byteBuf);
|
||||
}
|
||||
|
||||
byte[] bedrockBiome = BiomeTranslator.toBedrockBiome(packet.getColumn().getBiomeData());
|
||||
byte[] bedrockBiome;
|
||||
if (packet.getColumn().getBiomeData() == null) {
|
||||
bedrockBiome = BiomeTranslator.toBedrockBiome(session.getConnector().getWorldManager().getBiomeDataAt(session, packet.getColumn().getX(), packet.getColumn().getZ()));
|
||||
} else {
|
||||
bedrockBiome = BiomeTranslator.toBedrockBiome(packet.getColumn().getBiomeData());
|
||||
}
|
||||
|
||||
byteBuf.writeBytes(bedrockBiome); // Biomes - 256 bytes
|
||||
byteBuf.writeByte(0); // Border blocks - Edu edition only
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
|
|||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.chunk.ChunkPosition;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
|
||||
public class GeyserWorldManager extends WorldManager {
|
||||
|
@ -43,6 +44,13 @@ public class GeyserWorldManager extends WorldManager {
|
|||
return session.getChunkCache().getBlockAt(new Position(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getBiomeDataAt(GeyserSession session, int x, int z) {
|
||||
if (!session.getConnector().getConfig().isCacheChunks())
|
||||
return new int[1024];
|
||||
return session.getChunkCache().getChunks().get(new ChunkPosition(x, z)).getBiomeData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameRule(GeyserSession session, String name, Object value) {
|
||||
session.sendDownstreamPacket(new ClientChatPacket("/gamerule " + name + " " + value));
|
||||
|
|
|
@ -74,6 +74,16 @@ public abstract class WorldManager {
|
|||
*/
|
||||
public abstract int getBlockAt(GeyserSession session, int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Gets the biome data for the specified chunk.
|
||||
*
|
||||
* @param session the session of the player
|
||||
* @param x the chunk's X coordinate
|
||||
* @param z the chunk's Z coordinate
|
||||
* @return the biome data for the specified region with a length of 1024.
|
||||
*/
|
||||
public abstract int[] getBiomeDataAt(GeyserSession session, int x, int z);
|
||||
|
||||
/**
|
||||
* Updates a gamerule value on the Java server
|
||||
*
|
||||
|
|
|
@ -81,7 +81,7 @@ public class ChunkUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static ChunkData translateToBedrock(Column column) {
|
||||
public static ChunkData translateToBedrock(GeyserSession session, Column column, boolean isNonFullChunk) {
|
||||
ChunkData chunkData = new ChunkData();
|
||||
Chunk[] chunks = column.getChunks();
|
||||
chunkData.sections = new ChunkSection[chunks.length];
|
||||
|
@ -97,14 +97,26 @@ public class ChunkUtils {
|
|||
chunkData.sections[chunkY] = new ChunkSection();
|
||||
Chunk chunk = chunks[chunkY];
|
||||
|
||||
if (chunk == null || chunk.isEmpty())
|
||||
// Chunk is null and caching chunks is off or this isn't a non-full chunk
|
||||
if (chunk == null && (!session.getConnector().getConfig().isCacheChunks() || !isNonFullChunk))
|
||||
continue;
|
||||
|
||||
// If chunk is empty then no need to process
|
||||
if (chunk != null && chunk.isEmpty())
|
||||
continue;
|
||||
|
||||
ChunkSection section = chunkData.sections[chunkY];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int blockState = chunk.get(x, y, z);
|
||||
int blockState;
|
||||
// If a non-full chunk, then grab the block that should be here to create a 'full' chunk
|
||||
if (chunk == null) {
|
||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
||||
blockState = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ());
|
||||
} else {
|
||||
blockState = chunk.get(x, y, z);
|
||||
}
|
||||
int id = BlockTranslator.getBedrockBlockId(blockState);
|
||||
|
||||
// Check to see if the name is in BlockTranslator.getBlockEntityString, and therefore must be handled differently
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue