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.
This commit is contained in:
James Puleo 2021-02-27 14:53:53 -05:00
parent 5be44b597a
commit 5369b6bc44
No known key found for this signature in database
GPG Key ID: 3E16C7EFA34FB15D
3 changed files with 47 additions and 32 deletions

View File

@ -1,22 +1,10 @@
package com.loohp.limbo.Events; package com.loohp.limbo.Events;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player; import com.loohp.limbo.Player.Player;
public class PlayerJoinEvent extends PlayerEvent { public class PlayerJoinEvent extends PlayerEvent {
private Location spawnLocation; public PlayerJoinEvent(Player player) {
public PlayerJoinEvent(Player player, Location spawnLoc) {
super(player); super(player);
spawnLocation = spawnLoc;
}
public Location getSpawnLocation() {
return spawnLocation;
}
public void setSpawnLocation(Location spawnLocation) {
this.spawnLocation = spawnLocation;
} }
} }

View File

@ -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;
}
}

View File

@ -23,6 +23,7 @@ import com.loohp.limbo.Events.PlayerLoginEvent;
import com.loohp.limbo.Events.PlayerMoveEvent; import com.loohp.limbo.Events.PlayerMoveEvent;
import com.loohp.limbo.Events.PlayerQuitEvent; import com.loohp.limbo.Events.PlayerQuitEvent;
import com.loohp.limbo.Events.StatusPingEvent; import com.loohp.limbo.Events.StatusPingEvent;
import com.loohp.limbo.Events.PlayerSpawnLocationEvent;
import com.loohp.limbo.Events.PlayerSelectedSlotChangeEvent; import com.loohp.limbo.Events.PlayerSelectedSlotChangeEvent;
import com.loohp.limbo.File.ServerProperties; import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location; 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!")}); disconnectDuringLogin(new BaseComponent[] {new TextComponent(ChatColor.RED + "Please connect from the proxy!")});
} }
} }
while (client_socket.isConnected()) { while (client_socket.isConnected()) {
int size = DataTypeIO.readVarInt(input); int size = DataTypeIO.readVarInt(input);
int packetId = DataTypeIO.readVarInt(input); int packetId = DataTypeIO.readVarInt(input);
Class<? extends Packet> packetType = Packet.getLoginIn().get(packetId); Class<? extends Packet> packetType = Packet.getLoginIn().get(packetId);
if (packetType == null) { if (packetType == null) {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
} else if (packetType.equals(PacketLoginInLoginStart.class)) { } else if (packetType.equals(PacketLoginInLoginStart.class)) {
PacketLoginInLoginStart start = new PacketLoginInLoginStart(input); PacketLoginInLoginStart start = new PacketLoginInLoginStart(input);
String username = start.getUsername(); String username = start.getUsername();
UUID uuid = isBungeecord ? bungeeUUID : UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); UUID uuid = isBungeecord ? bungeeUUID : UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username); PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username);
sendPacket(success); sendPacket(success);
state = ClientState.PLAY; state = ClientState.PLAY;
player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager()); 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)); 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); Limbo.getInstance().addPlayer(player);
break; break;
} else { } else {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
} }
} }
PlayerLoginEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerLoginEvent(this, false)); PlayerLoginEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerLoginEvent(this, false));
if (event.isCancelled()) { if (event.isCancelled()) {
disconnectDuringLogin(event.getCancelReason()); disconnectDuringLogin(event.getCancelReason());
} }
break; break;
} }
if (state == ClientState.PLAY) { if (state == ClientState.PLAY) {
TimeUnit.MILLISECONDS.sleep(500); TimeUnit.MILLISECONDS.sleep(500);
ServerProperties properties = Limbo.getInstance().getServerProperties(); ServerProperties properties = Limbo.getInstance().getServerProperties();
Location worldSpawn = properties.getWorldSpawn(); Location worldSpawn = player.getLocation();
PlayerJoinEvent joinEvent = Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player, worldSpawn));
worldSpawn = joinEvent.getSpawnLocation();
World world = worldSpawn.getWorld();
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); sendPacket(join);
Limbo.getInstance().getUnsafe().setPlayerGameModeSilently(player, properties.getDefaultGamemode()); Limbo.getInstance().getUnsafe().setPlayerGameModeSilently(player, properties.getDefaultGamemode());
player.playerInteractManager.update(); player.playerInteractManager.update();
SkinResponse skinresponce = isBungeecord && bungeeSkin != null ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName()); SkinResponse skinresponce = isBungeecord && bungeeSkin != null ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null; 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())); 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); sendPacket(info);
Set<PlayerAbilityFlags> flags = new HashSet<>(); Set<PlayerAbilityFlags> flags = new HashSet<>();
if (properties.isAllowFlight()) { if (properties.isAllowFlight()) {
flags.add(PlayerAbilityFlags.FLY); flags.add(PlayerAbilityFlags.FLY);
@ -333,7 +339,7 @@ public class ClientConnection extends Thread {
sendPacket(spawnPos); sendPacket(spawnPos);
PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(worldSpawn.getX(), worldSpawn.getY(), worldSpawn.getZ(), worldSpawn.getYaw(), worldSpawn.getPitch(), 1); 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); sendPacket(positionLook);
player.getDataWatcher().update(); player.getDataWatcher().update();