diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index 3ff170f41..2b2ad0544 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -68,8 +68,8 @@ public class Entity { protected boolean valid; - protected Set passengers = new HashSet(); - protected Map attributes = new HashMap(); + protected Set passengers = new HashSet<>(); + protected Map attributes = new HashMap<>(); public Entity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { this.entityId = entityId; @@ -128,9 +128,6 @@ public class Entity { } public void moveAbsolute(Vector3f position, Vector3f rotation) { - if (position.getX() == 0 && position.getY() == 0 && position.getZ() == 0 && rotation.getX() == 0 && rotation.getY() == 0) - return; - this.position = position; this.rotation = rotation; this.movePending = true; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java new file mode 100644 index 000000000..6b1b1c117 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java @@ -0,0 +1,55 @@ +package org.geysermc.connector.entity; + +import com.flowpowered.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.geysermc.connector.console.GeyserLogger; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.PaintingType; + +@Getter @Setter +@Accessors(chain = true) +public class PaintingEntity extends Entity { + private static final double OFFSET = -0.46875; + private PaintingType paintingName; + private int direction; + + public PaintingEntity(long entityId, long geyserId, Vector3f position) { + super(entityId, geyserId, EntityType.PAINTING, position, Vector3f.ZERO, Vector3f.ZERO); + } + + @Override + public void spawnEntity(GeyserSession session) { + AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); + addPaintingPacket.setUniqueEntityId(geyserId); + addPaintingPacket.setRuntimeEntityId(geyserId); + addPaintingPacket.setName(paintingName.getBedrockName()); + addPaintingPacket.setPosition(fixOffset(true)); + addPaintingPacket.setDirection(direction); + session.getUpstream().sendPacket(addPaintingPacket); + + valid = true; + + GeyserLogger.DEFAULT.debug("Spawned painting on " + position); + } + + public Vector3f fixOffset(boolean toBedrock) { + if (toBedrock) { + Vector3f position = super.position; + position = position.add(0.5, 0.5, 0.5); + double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; + double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0; + + switch (direction) { + case 0: return position.add(widthOffset, heightOffset, OFFSET); + case 1: return position.add(-OFFSET, heightOffset, widthOffset); + case 2: return position.add(-widthOffset, heightOffset, -OFFSET); + case 3: return position.add(OFFSET, heightOffset, -widthOffset); + } + } + return position; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 06b6e7c22..ff3a2ed4d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -49,8 +49,8 @@ public class PlayerEntity extends Entity { private ItemData leggings; private ItemData boots; - public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); + public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation); uuid = gameProfile.getId(); username = gameProfile.getName(); @@ -58,8 +58,7 @@ public class PlayerEntity extends Entity { // TODO: Break this into an EquippableEntity class public void updateEquipment(GeyserSession session) { - if (hand != null && helmet != null && chestplate != null && leggings != null ) - return; + if (!valid) return; MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket(); armorEquipmentPacket.setRuntimeEntityId(geyserId); diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index cd06e78eb..929ed9d5b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -112,14 +112,15 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(MovePlayerPacket packet) { connector.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName()); - if (!session.isLoggedIn()) { + if (!session.isLoggedIn() && !session.isLoggingIn()) { // TODO it is safer to key authentication on something that won't change (UUID, not username) if (!couldLoginUserByName(session.getAuthenticationData().getName())) { LoginEncryptionUtils.showLoginWindow(session); } // else we were able to log the user in - return true; + } else if (session.isLoggingIn()) { + session.sendMessage("Please wait until you are logged in..."); } return translateAndDefault(packet); 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 38d466d15..0ad983b53 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 @@ -64,13 +64,10 @@ import java.util.UUID; @Getter public class GeyserSession implements Player { - private final GeyserConnector connector; private final BedrockServerSession upstream; private RemoteServer remoteServer; - private Client downstream; - private AuthData authenticationData; private PlayerEntity playerEntity; @@ -86,12 +83,14 @@ public class GeyserSession implements Player { @Setter private Vector2i lastChunkPosition = null; + @Setter + private int renderDistance; private boolean loggedIn; + private boolean loggingIn; @Setter private boolean spawned; - private boolean closed; public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { @@ -104,10 +103,10 @@ public class GeyserSession implements Player { this.scoreboardCache = new ScoreboardCache(this); this.windowCache = new WindowCache(this); - this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "Unknown"), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)); + this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), -1, 1, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)); this.inventory = new PlayerInventory(); - this.javaPacketCache = new DataCache(); + this.javaPacketCache = new DataCache<>(); this.spawned = false; this.loggedIn = false; @@ -137,43 +136,49 @@ public class GeyserSession implements Player { return; } - try { - MinecraftProtocol protocol; - if (password != null && !password.isEmpty()) { - protocol = new MinecraftProtocol(username, password); - } else { - protocol = new MinecraftProtocol(username); + loggedIn = true; + // new thread so clients don't timeout + new Thread(() -> { + try { + MinecraftProtocol protocol; + if (password != null && !password.isEmpty()) { + protocol = new MinecraftProtocol(username, password); + } else { + protocol = new MinecraftProtocol(username); + } + + downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); + downstream.getSession().addListener(new SessionAdapter() { + + @Override + public void connected(ConnectedEvent event) { + loggingIn = false; + loggedIn = true; + connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); + playerEntity.setUuid(protocol.getProfile().getId()); + playerEntity.setUsername(protocol.getProfile().getName()); + } + + @Override + public void disconnected(DisconnectedEvent event) { + loggingIn = false; + loggedIn = false; + connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason()); + upstream.disconnect(event.getReason()); + } + + @Override + public void packetReceived(PacketReceivedEvent event) { + if (!closed) + Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); + } + }); + + downstream.getSession().connect(); + } catch (RequestException ex) { + ex.printStackTrace(); } - - downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); - downstream.getSession().addListener(new SessionAdapter() { - - @Override - public void connected(ConnectedEvent event) { - loggedIn = true; - connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); - playerEntity.setUuid(protocol.getProfile().getId()); - playerEntity.setUsername(protocol.getProfile().getName()); - } - - @Override - public void disconnected(DisconnectedEvent event) { - loggedIn = false; - connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason()); - upstream.disconnect(event.getReason()); - } - - @Override - public void packetReceived(PacketReceivedEvent event) { - if (!closed) - Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); - } - }); - - downstream.getSession().connect(); - } catch (RequestException ex) { - ex.printStackTrace(); - } + }).start(); } public void disconnect(String reason) { diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index 881230031..a619533d3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -64,7 +64,13 @@ public class EntityCache { public void removeEntity(Entity entity) { if (entity == null) return; - entityIdTranslations.remove(entity.getEntityId()); + Long geyserId = entityIdTranslations.remove(entity.getEntityId()); + if (geyserId != null) { + entities.remove(geyserId); + if (entity instanceof PlayerEntity) { + playerEntities.remove(((PlayerEntity) entity).getUuid()); + } + } entity.despawnEntity(session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java index 7ae5a4ee0..3f300a6d0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java @@ -35,11 +35,10 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 8) - return; - - if (packet.getContainerId() != ContainerId.INVENTORY) + if (!session.isSpawned() || packet.getHotbarSlot() > 8 || + packet.getContainerId() != ContainerId.INVENTORY) { return; + } session.getInventory().setHeldItemSlot(packet.getHotbarSlot()); 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 f1dfc2105..d74bb8337 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 @@ -41,11 +41,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { @@ -49,29 +39,12 @@ public class JavaJoinGameTranslator extends PacketTranslator> 4; - int chunkZ = pos.getFloorZ() >> 4; - for (int x = -1; x < 1; x++) { - for (int z = -1; z < 1; z++) { - LevelChunkPacket data = new LevelChunkPacket(); - data.setChunkX(chunkX + x); - data.setChunkZ(chunkZ + z); - data.setSubChunksLength(0); - - data.setData(TranslatorsInit.EMPTY_LEVEL_CHUNK_DATA); - session.getUpstream().sendPacketImmediately(data); - - } - } - PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); session.getUpstream().sendPacketImmediately(playStatus); - Entity entity = session.getPlayerEntity(); - if (entity == null) - return; + PlayerEntity entity = session.getPlayerEntity(); + if (entity == null) return; session.getPlayerEntity().setEntityId(packet.getEntityId()); @@ -84,6 +57,14 @@ public class JavaJoinGameTranslator extends PacketTranslator 32) session.setRenderDistance(32); // <3 u ViaVersion but I don't like crashing clients x) + + ChunkRadiusUpdatedPacket packet1 = new ChunkRadiusUpdatedPacket(); + packet1.setRadius(session.getRenderDistance()); + session.getUpstream().sendPacket(packet1); + + session.setSpawned(true); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java index eb7262d67..a484a0be0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java @@ -40,8 +40,7 @@ public class JavaEntityTeleportTranslator extends PacketTranslator { @@ -38,12 +39,16 @@ public class JavaSpawnPaintingTranslator extends PacketTranslator { // #slowdownbrother, just don't execute it directly + PaintingEntity entity = new PaintingEntity( + packet.getEntityId(), + session.getEntityCache().getNextEntityId().incrementAndGet(), + position + ) + .setPaintingName(PaintingType.getByPaintingType(packet.getPaintingType())) + .setDirection(packet.getDirection().ordinal()); - if (entity == null) - return; - - session.getEntityCache().spawnEntity(entity); + session.getEntityCache().spawnEntity(entity); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java index 75e960fda..bab7ceebd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java @@ -9,7 +9,6 @@ import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.geysermc.api.Geyser; -import org.geysermc.connector.console.GeyserLogger; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.utils.ChunkUtils; @@ -28,7 +27,7 @@ public class JavaChunkDataTranslator extends PacketTranslator