From 27da638a917565dca61ecb31d033f3176ab283d3 Mon Sep 17 00:00:00 2001 From: Kristian Stangeland Date: Thu, 28 Mar 2013 22:27:58 -0400 Subject: [PATCH] Update the player instance on login (LOWEST), not HIGHEST. Should ensure that packet listeners recieve the most up-to-date player instance, regardless of whether or not the main thread is blocked in the player listener. No more temporary players. --- .../injector/PacketFilterManager.java | 1 + .../player/PlayerInjectionHandler.java | 6 + .../injector/player/PlayerInjector.java | 5 +- .../player/ProxyPlayerInjectionHandler.java | 13 +++ .../injector/server/BukkitSocketInjector.java | 103 ++++++++++++++++++ .../injector/server/SocketInjector.java | 6 + .../injector/spigot/DummyPlayerHandler.java | 5 + 7 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/BukkitSocketInjector.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index 28b79198..44aa1e46 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -696,6 +696,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok try { // Let's clean up the other injection first. playerInjection.uninjectPlayer(event.getPlayer().getAddress()); + playerInjection.updatePlayer(event.getPlayer()); } catch (Exception e) { reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject net handler for player.", e, event); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java index b26769fa..85669c69 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java @@ -129,6 +129,12 @@ public interface PlayerInjectionHandler { public abstract void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException; + /** + * Ensure that packet readers are informed of this player reference. + * @param player - the player to update. + */ + public abstract void updatePlayer(Player player); + /** * Determine if the given listeners are valid. * @param version - the current Minecraft version, or NULL if unknown. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java index a2fa3362..caff1e2c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java @@ -642,10 +642,7 @@ abstract class PlayerInjector implements SocketInjector { // Do nothing } - /** - * Set the real Bukkit player that we will use. - * @param updatedPlayer - the real Bukkit player. - */ + @Override public void setUpdatedPlayer(Player updatedPlayer) { this.updatedPlayer = updatedPlayer; } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java index 6816610b..2329d6b1 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java @@ -42,6 +42,7 @@ import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.PlayerLoggedOutException; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; +import com.comphenix.protocol.injector.server.BukkitSocketInjector; import com.comphenix.protocol.injector.server.InputStreamLookupBuilder; import com.comphenix.protocol.injector.server.SocketInjector; import com.comphenix.protocol.utility.MinecraftReflection; @@ -416,6 +417,18 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler { } } + @Override + public void updatePlayer(Player player) { + SocketInjector injector = inputStreamLookup.peekSocketInjector(player.getAddress()); + + if (injector != null) { + injector.setUpdatedPlayer(player); + } else { + inputStreamLookup.setSocketInjector(player.getAddress(), + new BukkitSocketInjector(player)); + } + } + /** * Unregisters the given player. * @param player - player to unregister. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/BukkitSocketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/BukkitSocketInjector.java new file mode 100644 index 00000000..8e72db01 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/BukkitSocketInjector.java @@ -0,0 +1,103 @@ +package com.comphenix.protocol.injector.server; + +import java.lang.reflect.InvocationTargetException; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.bukkit.entity.Player; + +public class BukkitSocketInjector implements SocketInjector { + /** + * Represents a single send packet command. + * @author Kristian + */ + static class SendPacketCommand { + private final Object packet; + private final boolean filtered; + + public SendPacketCommand(Object packet, boolean filtered) { + this.packet = packet; + this.filtered = filtered; + } + + public Object getPacket() { + return packet; + } + + public boolean isFiltered() { + return filtered; + } + } + + private Player player; + + // Queue of server packets + private List syncronizedQueue = Collections.synchronizedList(new ArrayList()); + + /** + * Represents a temporary socket injector. + * @param temporaryPlayer - + */ + public BukkitSocketInjector(Player player) { + if (player == null) + throw new IllegalArgumentException("Player cannot be NULL."); + this.player = player; + } + + @Override + public Socket getSocket() throws IllegalAccessException { + throw new UnsupportedOperationException("Cannot get socket from Bukkit player."); + } + + @Override + public SocketAddress getAddress() throws IllegalAccessException { + return player.getAddress(); + } + + @Override + public void disconnect(String message) throws InvocationTargetException { + player.kickPlayer(message); + } + + @Override + public void sendServerPacket(Object packet, boolean filtered) + throws InvocationTargetException { + SendPacketCommand command = new SendPacketCommand(packet, filtered); + + // Queue until we can find something better + syncronizedQueue.add(command); + } + + @Override + public Player getPlayer() { + return player; + } + + @Override + public Player getUpdatedPlayer() { + return player; + } + + @Override + public void transferState(SocketInjector delegate) { + // Transmit all queued packets to a different injector. + try { + synchronized(syncronizedQueue) { + for (SendPacketCommand command : syncronizedQueue) { + delegate.sendServerPacket(command.getPacket(), command.isFiltered()); + } + syncronizedQueue.clear(); + } + } catch (InvocationTargetException e) { + throw new RuntimeException("Unable to transmit packets to " + delegate + " from old injector.", e); + } + } + + @Override + public void setUpdatedPlayer(Player updatedPlayer) { + this.player = updatedPlayer; + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java index 6407d320..e484c2e5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java @@ -58,4 +58,10 @@ public interface SocketInjector { * @param delegate - the new injector. */ public abstract void transferState(SocketInjector delegate); + + /** + * Set the real Bukkit player that we will use. + * @param updatedPlayer - the real Bukkit player. + */ + public abstract void setUpdatedPlayer(Player updatedPlayer); } \ No newline at end of file diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java index 08b1a8d2..8df7f70c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java @@ -119,4 +119,9 @@ class DummyPlayerHandler implements PlayerInjectionHandler { public void postWorldLoaded() { // Do nothing } + + @Override + public void updatePlayer(Player player) { + // Do nothing + } }