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 0c2183b3..0165f854 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 @@ -37,12 +37,11 @@ import com.github.steveice10.packetlib.event.session.PacketReceivedEvent; import com.github.steveice10.packetlib.event.session.SessionAdapter; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import com.nukkitx.math.GenericMath; +import com.nukkitx.math.TrigMath; import com.nukkitx.math.vector.Vector2f; -import com.nukkitx.math.vector.Vector2i; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.nbt.stream.NBTInputStream; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.GamePublishSetting; @@ -55,7 +54,6 @@ import org.geysermc.api.RemoteServer; import org.geysermc.api.session.AuthData; import org.geysermc.api.window.FormWindow; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.console.GeyserLogger; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.cache.*; @@ -64,9 +62,9 @@ import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.Toolbox; -import java.io.InputStream; import java.net.InetSocketAddress; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements Player { @@ -88,9 +86,6 @@ public class GeyserSession implements Player { private DataCache javaPacketCache; - @Setter - private Vector2i lastChunkPosition = null; - @Setter private int renderDistance; private boolean loggedIn; @@ -103,8 +98,7 @@ public class GeyserSession implements Player { @Setter private GameMode gameMode = GameMode.SURVIVAL; - @Setter - private boolean switchingDimension = false; + private final AtomicInteger pendingDimSwitches = new AtomicInteger(0); private boolean manyDimPackets = false; private ServerRespawnPacket lastDimPacket = null; @@ -132,6 +126,10 @@ public class GeyserSession implements Player { public void connect(RemoteServer remoteServer) { startGame(); this.remoteServer = remoteServer; + if (!(connector.getConfig().getRemote().getAuthType().hashCode() == "online".hashCode())) { + connector.getLogger().info("Attempting to login using offline mode... authentication is disabled."); + authenticate(authenticationData.getName()); + } ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); @@ -270,6 +268,16 @@ public class GeyserSession implements Player { windowCache.showWindow(window, id); } + public void setRenderDistance(int renderDistance) { + renderDistance = GenericMath.ceil(++renderDistance * TrigMath.SQRT_OF_TWO); //square to circle + if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x) + this.renderDistance = renderDistance; + + ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); + chunkRadiusUpdatedPacket.setRadius(renderDistance); + upstream.sendPacket(chunkRadiusUpdatedPacket); + } + @Override public InetSocketAddress getSocketAddress() { return this.upstream.getAddress(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index 2abeebb8..c18859c1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -146,6 +146,9 @@ public class TranslatorsInit { Registry.registerJava(ServerMultiBlockChangePacket.class, new JavaMultiBlockChangeTranslator()); Registry.registerJava(ServerUnloadChunkPacket.class, new JavaUnloadChunkTranslator()); + Registry.registerJava(ServerUpdateViewPositionPacket.class, new JavaUpdateViewPositionTranslator()); + Registry.registerJava(ServerUpdateViewDistancePacket.class, new JavaUpdateViewDistanceTranslator()); + Registry.registerJava(ServerOpenWindowPacket.class, new OpenWindowPacketTranslator()); Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java index e5bec698..af23acd0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java @@ -115,12 +115,13 @@ public class BedrockActionTranslator extends PacketTranslator 0) return; if (!session.getUpstream().isInitialized()) { MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInitializedTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInitializedTranslator.java index e30ef2d7..201049db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInitializedTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInitializedTranslator.java @@ -38,11 +38,6 @@ public class BedrockPlayerInitializedTranslator extends PacketTranslator { @@ -59,15 +60,11 @@ public class JavaJoinGameTranslator extends PacketTranslator 32) session.setRenderDistance(32); // <3 u ViaVersion but I don't like crashing clients x) - - ChunkRadiusUpdatedPacket chunkRadiusPacket = new ChunkRadiusUpdatedPacket(); - chunkRadiusPacket.setRadius(session.getRenderDistance()); - session.getUpstream().sendPacket(chunkRadiusPacket); + session.setRenderDistance(packet.getViewDistance()); if (DimensionUtils.javaToBedrock(packet.getDimension()) != entity.getDimension()) { - DimensionUtils.switchDimension(session, packet.getDimension(), false); + ChunkUtils.sendEmptyChunks(session, entity.getPosition().toInt(), 3, true); + DimensionUtils.switchDimension(session, packet.getDimension()); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java index 8a6432e5..285f9d85 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java @@ -51,14 +51,15 @@ public class JavaRespawnTranslator extends PacketTranslator session.setGameMode(packet.getGamemode()); if (entity.getDimension() != DimensionUtils.javaToBedrock(packet.getDimension())) { - DimensionUtils.switchDimension(session, packet.getDimension(), false); + DimensionUtils.switchDimension(session, packet.getDimension()); } else { - // Handled in JavaPlayerPositionRotationTranslator - session.setSpawned(false); if (session.isManyDimPackets()) { //reloading world int fakeDim = entity.getDimension() == 0 ? -1 : 0; - DimensionUtils.switchDimension(session, fakeDim, true); - DimensionUtils.switchDimension(session, packet.getDimension(), false); + DimensionUtils.switchDimension(session, fakeDim); + DimensionUtils.switchDimension(session, packet.getDimension()); + } else { + // Handled in JavaPlayerPositionRotationTranslator + session.setSpawned(false); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java index d5b84313..a5d20333 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java @@ -51,7 +51,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator { - Vector2i chunkPos = session.getLastChunkPosition(); - Vector3f position = session.getPlayerEntity().getPosition(); - Vector2i newChunkPos = Vector2i.from(position.getFloorX() >> 4, position.getFloorZ() >> 4); - - if (chunkPos == null || !chunkPos.equals(newChunkPos)) { - NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket(); - chunkPublisherUpdatePacket.setPosition(position.toInt()); - chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4); - session.getUpstream().sendPacket(chunkPublisherUpdatePacket); - - session.setLastChunkPosition(newChunkPos); - } - try { - ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn()); - ByteBuf byteBuf = Unpooled.buffer(32); - ChunkSection[] sections = chunkData.sections; + if (packet.getColumn().getBiomeData() != null) { //Full chunk + ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn()); + ByteBuf byteBuf = Unpooled.buffer(32); + ChunkSection[] sections = chunkData.sections; - int sectionCount = sections.length - 1; - while (sectionCount >= 0 && sections[sectionCount].isEmpty()) { - sectionCount--; + int sectionCount = sections.length - 1; + while (sectionCount >= 0 && sections[sectionCount].isEmpty()) { + sectionCount--; + } + sectionCount++; + + for (int i = 0; i < sectionCount; i++) { + ChunkSection section = chunkData.sections[i]; + section.writeToNetwork(byteBuf); + } + + byte[] bedrockBiome = BiomeTranslator.toBedrockBiome(packet.getColumn().getBiomeData()); + + byteBuf.writeBytes(bedrockBiome); // Biomes - 256 bytes + byteBuf.writeByte(0); // Border blocks - Edu edition only + VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now + + byte[] payload = new byte[byteBuf.writerIndex()]; + byteBuf.readBytes(payload); + + LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); + levelChunkPacket.setSubChunksLength(sectionCount); + levelChunkPacket.setCachingEnabled(false); + levelChunkPacket.setChunkX(packet.getColumn().getX()); + levelChunkPacket.setChunkZ(packet.getColumn().getZ()); + levelChunkPacket.setData(payload); + session.getUpstream().sendPacket(levelChunkPacket); + } else { + final int xOffset = packet.getColumn().getX() << 4; + final int zOffset = packet.getColumn().getZ() << 4; + Chunk[] chunks = packet.getColumn().getChunks(); + for (int i = 0; i < chunks.length; i++) { + Chunk chunk = chunks[i]; + if (chunk == null) continue; + final int yOffset = i * 16; + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState blockState = chunk.get(x, y, z); + Vector3i pos = Vector3i.from( + x + xOffset, + y + yOffset, + z + zOffset); + ChunkUtils.updateBlock(session, blockState, pos); + } + } + } + } } - sectionCount++; - - for (int i = 0; i < sectionCount; i++) { - ChunkSection section = chunkData.sections[i]; - section.writeToNetwork(byteBuf); - } - - byte[] bedrockBiome = BiomeTranslator.toBedrockBiome(packet.getColumn().getBiomeData()); - - byteBuf.writeBytes(bedrockBiome); // Biomes - 256 bytes - byteBuf.writeByte(0); // Border blocks - Edu edition only - VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now - - byte[] payload = new byte[byteBuf.writerIndex()]; - byteBuf.readBytes(payload); - - LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); - levelChunkPacket.setSubChunksLength(sectionCount); - levelChunkPacket.setCachingEnabled(false); - levelChunkPacket.setChunkX(packet.getColumn().getX()); - levelChunkPacket.setChunkZ(packet.getColumn().getZ()); - levelChunkPacket.setData(payload); - session.getUpstream().sendPacket(levelChunkPacket); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java new file mode 100644 index 00000000..1b339b1c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2020 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.java.world; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateViewDistancePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; + +public class JavaUpdateViewDistanceTranslator extends PacketTranslator { + + @Override + public void translate(ServerUpdateViewDistancePacket packet, GeyserSession session) { + session.setRenderDistance(packet.getViewDistance()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java new file mode 100644 index 00000000..ebe9062f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2020 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.java.world; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateViewPositionPacket; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; + +public class JavaUpdateViewPositionTranslator extends PacketTranslator { + + @Override + public void translate(ServerUpdateViewPositionPacket packet, GeyserSession session) { + NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket(); + chunkPublisherUpdatePacket.setPosition(Vector3i.from(packet.getChunkX() << 4, 0, packet.getChunkZ() << 4)); + chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4); + session.getUpstream().sendPacket(chunkPublisherUpdatePacket); + } +} 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 6c55c5ea..1a6296c0 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -31,7 +31,6 @@ 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.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; -import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.TranslatorsInit; @@ -76,19 +75,23 @@ public class ChunkUtils { } public static void updateBlock(GeyserSession session, BlockState blockState, Position position) { - int blockId = BlockTranslator.getBedrockBlockId(blockState); Vector3i pos = Vector3i.from(position.getX(), position.getY(), position.getZ()); + updateBlock(session, blockState, pos); + } + + public static void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { + int blockId = BlockTranslator.getBedrockBlockId(blockState); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(pos); + updateBlockPacket.setBlockPosition(position); updateBlockPacket.setRuntimeId(blockId); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); session.getUpstream().sendPacket(updateBlockPacket); UpdateBlockPacket waterPacket = new UpdateBlockPacket(); waterPacket.setDataLayer(1); - waterPacket.setBlockPosition(pos); + waterPacket.setBlockPosition(position); if (BlockTranslator.isWaterlogged(blockState)) { waterPacket.setRuntimeId(BEDROCK_WATER_ID); } else { @@ -100,11 +103,6 @@ public class ChunkUtils { public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) { int chunkX = position.getX() >> 4; int chunkZ = position.getZ() >> 4; - NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket(); - chunkPublisherUpdatePacket.setPosition(position); - chunkPublisherUpdatePacket.setRadius(radius + 1 << 4); - session.getUpstream().sendPacket(chunkPublisherUpdatePacket); - session.setLastChunkPosition(null); for (int x = -radius; x <= radius; x++) { for (int z = -radius; z <= radius; z++) { LevelChunkPacket data = new LevelChunkPacket(); @@ -119,7 +117,7 @@ public class ChunkUtils { Vector3i pos = Vector3i.from(chunkX + x << 4, 80, chunkZ + z << 4); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setBlockPosition(pos); - blockPacket.setDataLayer(1); + blockPacket.setDataLayer(0); blockPacket.setRuntimeId(1); session.getUpstream().sendPacket(blockPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index 81f52823..c7ecaafb 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -31,14 +31,18 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; public class DimensionUtils { - public static void switchDimension(GeyserSession session, int javaDimension, boolean fake) { + public static void switchDimension(GeyserSession session, int javaDimension) { int bedrockDimension = javaToBedrock(javaDimension); Entity player = session.getPlayerEntity(); if (bedrockDimension == player.getDimension()) return; - Vector3i pos = Vector3i.from(0, Short.MAX_VALUE, 0); session.getEntityCache().removeAllEntities(); + if (session.getPendingDimSwitches().getAndIncrement() > 0) { + ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); + } + + Vector3i pos = Vector3i.from(0, Short.MAX_VALUE, 0); ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket(); changeDimensionPacket.setDimension(bedrockDimension); @@ -46,19 +50,14 @@ public class DimensionUtils { changeDimensionPacket.setPosition(pos.toFloat()); session.getUpstream().sendPacket(changeDimensionPacket); player.setDimension(bedrockDimension); + player.setPosition(pos.toFloat()); + session.setSpawned(false); //let java server handle portal travel sound StopSoundPacket stopSoundPacket = new StopSoundPacket(); stopSoundPacket.setStoppingAllSound(true); stopSoundPacket.setSoundName(""); session.getUpstream().sendPacket(stopSoundPacket); - - if (fake) { - ChunkUtils.sendEmptyChunks(session, pos, 2, true); - } - - session.setSpawned(false); - session.setSwitchingDimension(true); } public static int javaToBedrock(int javaDimension) { diff --git a/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java b/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java index 840e2f5d..cafb7ab0 100644 --- a/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java +++ b/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java @@ -27,12 +27,14 @@ package org.geysermc.connector.world.chunk; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @Getter @Setter @AllArgsConstructor +@EqualsAndHashCode public class ChunkPosition { private int x; @@ -43,16 +45,9 @@ public class ChunkPosition { } public Position getChunkBlock(int x, int y, int z) { - int chunkX = x % 16; - int chunkY = y % 16; - int chunkZ = z % 16; - - if (chunkX < 0) - chunkX = -chunkX; - if (chunkY < 0) - chunkY = -chunkY; - if (chunkZ < 0) - chunkZ = -chunkZ; + int chunkX = x & 15; + int chunkY = y & 15; + int chunkZ = z & 15; return new Position(chunkX, chunkY, chunkZ); }