diff --git a/README.md b/README.md index c51d73b28..d370d8e58 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Links: - [x] Entity support - [ ] Chunks (Experimental) - [x] Block translation (may be missing mappings) - - [ ] Block updates + - [x] Block updates - [ ] Block entities - [ ] Extra data - [ ] Biome colors diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 0872c0772..1c3930c46 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -75,10 +75,11 @@ public class GeyserSession implements Player { private PlayerEntity playerEntity; private PlayerInventory inventory; + private ChunkCache chunkCache; private EntityCache entityCache; private InventoryCache inventoryCache; - private WindowCache windowCache; private ScoreboardCache scoreboardCache; + private WindowCache windowCache; private DataCache javaPacketCache; @@ -96,10 +97,11 @@ public class GeyserSession implements Player { this.connector = connector; this.upstream = bedrockServerSession; + this.chunkCache = new ChunkCache(this); this.entityCache = new EntityCache(this); this.inventoryCache = new InventoryCache(this); - this.windowCache = new WindowCache(this); this.scoreboardCache = new ScoreboardCache(this); + this.windowCache = new WindowCache(this); this.playerEntity = new PlayerEntity(UUID.randomUUID(), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)); this.inventory = new PlayerInventory(); 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 new file mode 100644 index 000000000..e8396e06e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019 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.session.cache; + +import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; +import com.github.steveice10.mc.protocol.data.game.chunk.Column; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; +import lombok.Getter; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.item.BedrockItem; +import org.geysermc.connector.world.chunk.ChunkPosition; + +import java.util.HashMap; +import java.util.Map; + +public class ChunkCache { + + private GeyserSession session; + + @Getter + private Map chunks; + + public ChunkCache(GeyserSession session) { + this.session = session; + this.chunks = new HashMap<>(); + } + + public void addToCache(Column chunk) { + ChunkPosition position = new ChunkPosition(chunk.getX(), chunk.getZ()); + chunks.put(position, chunk); + } + + public void updateBlock(Position position, BlockState block) { + ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4); + if (!chunks.containsKey(chunkPosition)) + return; + + Column column = chunks.get(chunkPosition); + Chunk chunk = column.getChunks()[position.getY() >> 4]; + Position blockPosition = chunkPosition.getChunkBlock(position.getX(), position.getY(), position.getZ()); + if (chunk != null) { + chunk.getBlocks().set(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), block); + } + } + + public BedrockItem getBlockAt(Position position) { + ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4); + if (!chunks.containsKey(chunkPosition)) + return BedrockItem.AIR; + + Column column = chunks.get(chunkPosition); + Chunk chunk = column.getChunks()[position.getY() >> 4]; + Position blockPosition = chunkPosition.getChunkBlock(position.getX(), position.getY(), position.getZ()); + if (chunk != null) { + BlockState blockState = chunk.getBlocks().get(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); + return TranslatorsInit.getItemTranslator().getBedrockBlock(blockState); + } + + return BedrockItem.AIR; + } + + public void removeChunk(ChunkPosition position) { + if (chunks.containsKey(position)) { + chunks.remove(position); + } + + sendEmptyChunk(position, true); + } + + public void sendEmptyChunk(ChunkPosition position) { + sendEmptyChunk(position, false); + } + + public void sendEmptyChunk(ChunkPosition position, boolean force) { + if (!force && chunks.containsKey(position)) + return; + + LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); + levelChunkPacket.setChunkX(position.getX()); + levelChunkPacket.setChunkZ(position.getZ()); + levelChunkPacket.setCachingEnabled(false); + levelChunkPacket.setSubChunksLength(0); + levelChunkPacket.setData(TranslatorsInit.EMPTY_LEVEL_CHUNK_DATA); + session.getUpstream().sendPacket(levelChunkPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java index 1f8b8f772..8c031f932 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java @@ -25,12 +25,14 @@ package org.geysermc.connector.network.translators.bedrock; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.item.BedrockItem; public class BedrockMovePlayerTranslator extends PacketTranslator { @@ -40,12 +42,21 @@ public class BedrockMovePlayerTranslator extends PacketTranslator