From 5369b6bc445d3ed546a3512cbec9ee05fe4de02f Mon Sep 17 00:00:00 2001 From: James Puleo Date: Sat, 27 Feb 2021 14:53:53 -0500 Subject: [PATCH] Rework spawn world selection into it's own event. The player is created a bit before we call the PlayerJoinEvent, and by that time the player has already ticked and been sent some chunks for their current world, which the PlayerJoinEvent wouldn't have had a chance to modify. This introduces a PlayerSpawnLocationEvent, which allows a spawn location to be chosen for a player right as they are created, before PlayerJoinEvent is called. This solution is pretty bad. If you have any better way to implement this correctly then certainly tell. --- .../loohp/limbo/Events/PlayerJoinEvent.java | 14 +----- .../Events/PlayerSpawnLocationEvent.java | 21 +++++++++ .../loohp/limbo/Server/ClientConnection.java | 44 +++++++++++-------- 3 files changed, 47 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/loohp/limbo/Events/PlayerSpawnLocationEvent.java diff --git a/src/main/java/com/loohp/limbo/Events/PlayerJoinEvent.java b/src/main/java/com/loohp/limbo/Events/PlayerJoinEvent.java index 9a4d45a..b653f26 100644 --- a/src/main/java/com/loohp/limbo/Events/PlayerJoinEvent.java +++ b/src/main/java/com/loohp/limbo/Events/PlayerJoinEvent.java @@ -1,22 +1,10 @@ package com.loohp.limbo.Events; -import com.loohp.limbo.Location.Location; import com.loohp.limbo.Player.Player; public class PlayerJoinEvent extends PlayerEvent { - private Location spawnLocation; - - public PlayerJoinEvent(Player player, Location spawnLoc) { + public PlayerJoinEvent(Player player) { super(player); - spawnLocation = spawnLoc; - } - - public Location getSpawnLocation() { - return spawnLocation; - } - - public void setSpawnLocation(Location spawnLocation) { - this.spawnLocation = spawnLocation; } } diff --git a/src/main/java/com/loohp/limbo/Events/PlayerSpawnLocationEvent.java b/src/main/java/com/loohp/limbo/Events/PlayerSpawnLocationEvent.java new file mode 100644 index 0000000..ca4c9ce --- /dev/null +++ b/src/main/java/com/loohp/limbo/Events/PlayerSpawnLocationEvent.java @@ -0,0 +1,21 @@ +package com.loohp.limbo.Events; + +import com.loohp.limbo.Location.Location; +import com.loohp.limbo.Player.Player; + +public class PlayerSpawnLocationEvent extends PlayerEvent { + private Location location; + + public PlayerSpawnLocationEvent(Player player, Location loc) { + super(player); + location = loc; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } +} diff --git a/src/main/java/com/loohp/limbo/Server/ClientConnection.java b/src/main/java/com/loohp/limbo/Server/ClientConnection.java index b2c3a0f..d1d40f4 100644 --- a/src/main/java/com/loohp/limbo/Server/ClientConnection.java +++ b/src/main/java/com/loohp/limbo/Server/ClientConnection.java @@ -23,6 +23,7 @@ import com.loohp.limbo.Events.PlayerLoginEvent; import com.loohp.limbo.Events.PlayerMoveEvent; import com.loohp.limbo.Events.PlayerQuitEvent; import com.loohp.limbo.Events.StatusPingEvent; +import com.loohp.limbo.Events.PlayerSpawnLocationEvent; import com.loohp.limbo.Events.PlayerSelectedSlotChangeEvent; import com.loohp.limbo.File.ServerProperties; import com.loohp.limbo.Location.Location; @@ -253,64 +254,69 @@ public class ClientConnection extends Thread { disconnectDuringLogin(new BaseComponent[] {new TextComponent(ChatColor.RED + "Please connect from the proxy!")}); } } - + while (client_socket.isConnected()) { int size = DataTypeIO.readVarInt(input); int packetId = DataTypeIO.readVarInt(input); Class packetType = Packet.getLoginIn().get(packetId); - + if (packetType == null) { input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); } else if (packetType.equals(PacketLoginInLoginStart.class)) { PacketLoginInLoginStart start = new PacketLoginInLoginStart(input); String username = start.getUsername(); UUID uuid = isBungeecord ? bungeeUUID : UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); - + PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username); sendPacket(success); - + state = ClientState.PLAY; player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager()); player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40)); + Location spawnLocation = Limbo.getInstance().getEventsManager().callEvent(new PlayerSpawnLocationEvent(player, Limbo.getInstance().getServerProperties().getWorldSpawn())).getLocation(); + player.setX(spawnLocation.getX()); + player.setY(spawnLocation.getY()); + player.setZ(spawnLocation.getZ()); + player.setPitch(spawnLocation.getPitch()); + player.setYaw(spawnLocation.getYaw()); + player.setWorld(spawnLocation.getWorld()); Limbo.getInstance().addPlayer(player); - + break; } else { input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); } } - + PlayerLoginEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerLoginEvent(this, false)); if (event.isCancelled()) { disconnectDuringLogin(event.getCancelReason()); } - + break; } - + if (state == ClientState.PLAY) { - + TimeUnit.MILLISECONDS.sleep(500); ServerProperties properties = Limbo.getInstance().getServerProperties(); - Location worldSpawn = properties.getWorldSpawn(); - - PlayerJoinEvent joinEvent = Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player, worldSpawn)); - worldSpawn = joinEvent.getSpawnLocation(); - World world = worldSpawn.getWorld(); + Location worldSpawn = player.getLocation(); - PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, properties.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), Limbo.getInstance().getDimensionRegistry().getCodec(), world, 0, (byte) properties.getMaxPlayers(), 8, properties.isReducedDebugInfo(), true, false, true); + Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player)); + + PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, properties.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), Limbo.getInstance().getDimensionRegistry().getCodec(), worldSpawn.getWorld(), 0, (byte) properties.getMaxPlayers(), 8, properties.isReducedDebugInfo(), true, false, true); sendPacket(join); Limbo.getInstance().getUnsafe().setPlayerGameModeSilently(player, properties.getDefaultGamemode()); - + player.playerInteractManager.update(); - + SkinResponse skinresponce = isBungeecord && bungeeSkin != null ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName()); PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null; PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUniqueId(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), properties.getDefaultGamemode(), 0, false, Optional.empty())); sendPacket(info); - + Set flags = new HashSet<>(); if (properties.isAllowFlight()) { flags.add(PlayerAbilityFlags.FLY); @@ -333,7 +339,7 @@ public class ClientConnection extends Thread { sendPacket(spawnPos); PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(worldSpawn.getX(), worldSpawn.getY(), worldSpawn.getZ(), worldSpawn.getYaw(), worldSpawn.getPitch(), 1); - Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, new Location(world, worldSpawn.getX(), worldSpawn.getY(), worldSpawn.getZ(), worldSpawn.getYaw(), worldSpawn.getPitch())); + Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, worldSpawn); sendPacket(positionLook); player.getDataWatcher().update();