Prevent the PlayerQuitEvent from being fired twice. FIXES Ticket-2.

This commit is contained in:
Kristian S. Stangeland 2012-10-23 00:37:35 +02:00
parent 0aac8ebf0a
commit 96ad954cf7
9 changed files with 105 additions and 8 deletions

View File

@ -4,7 +4,7 @@
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<name>ProtocolLib</name>
<version>1.4.2</version>
<version>1.4.3-SNAPSHOT</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>http://dev.bukkit.org/server-mods/protocollib/</url>
<developers>

View File

@ -606,6 +606,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
playerInjection.handleDisconnect(event.getPlayer());
playerInjection.uninjectPlayer(event.getPlayer());
}
@ -689,10 +690,14 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
Object event = args[0];
// Check for the correct event
if (event instanceof PlayerJoinEvent)
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer());
else if (event instanceof PlayerQuitEvent)
playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
if (event instanceof PlayerJoinEvent) {
Player player = ((PlayerJoinEvent) event).getPlayer();
playerInjection.injectPlayer(player);
} else if (event instanceof PlayerQuitEvent) {
Player player = ((PlayerQuitEvent) event).getPlayer();
playerInjection.handleDisconnect(player);
playerInjection.uninjectPlayer(player);
}
}
return null;
}

View File

@ -241,7 +241,7 @@ class InjectedServerConnection {
// Clean up?
if (removing instanceof NetLoginHandler) {
netLoginInjector.cleanup(removing);
}
}
}
};
}

View File

@ -191,6 +191,11 @@ class NetworkFieldInjector extends PlayerInjector {
overridenLists.clear();
}
@Override
public void handleDisconnect() {
// No need to do anything
}
@Override
public boolean canInject(GamePhase phase) {
// All phases should work

View File

@ -159,6 +159,11 @@ class NetworkObjectInjector extends PlayerInjector {
}
}
@Override
public void handleDisconnect() {
// No need to do anything
}
@Override
public boolean canInject(GamePhase phase) {
// Works for all phases

View File

@ -17,8 +17,10 @@
package com.comphenix.protocol.injector.player;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.server.Packet;
@ -50,6 +52,7 @@ import com.comphenix.protocol.reflect.instances.ExistingGenerator;
*/
public class NetworkServerInjector extends PlayerInjector {
private static Field disconnectField;
private static Method sendPacketMethod;
private InjectedServerConnection serverInjection;
@ -59,6 +62,9 @@ public class NetworkServerInjector extends PlayerInjector {
// Used to create proxy objects
private ClassLoader classLoader;
// Whether or not the player has disconnected
private boolean hasDisconnected;
public NetworkServerInjector(
ClassLoader classLoader, Logger logger, Player player,
ListenerInvoker invoker, IntegerSet sendingFilters,
@ -250,11 +256,42 @@ public class NetworkServerInjector extends PlayerInjector {
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Prevent the PlayerQuitEvent from being sent twice
if (hasDisconnected) {
setDisconnect(serverHandlerRef.getValue(), true);
}
}
serverInjection.revertServerHandler(serverHandler);
}
@Override
public void handleDisconnect() {
hasDisconnected = true;
}
/**
* Set the disconnected field in a NetServerHandler.
* @param handler - the NetServerHandler.
* @param value - the new value.
*/
private void setDisconnect(Object handler, boolean value) {
// Set it
try {
// Load the field
if (disconnectField == null) {
disconnectField = FuzzyReflection.fromObject(handler).getFieldByName("disconnected.*");
}
FieldUtils.writeField(disconnectField, handler, value);
} catch (IllegalArgumentException e) {
logger.log(Level.WARNING, "Unable to find disconnect field. Is ProtocolLib up to date?");
} catch (IllegalAccessException e) {
logger.log(Level.WARNING, "Unable to update disconnected field. Player quit event may be sent twice.");
}
}
@Override
public void checkListener(PacketListener listener) {
// We support everything

View File

@ -358,6 +358,18 @@ public class PlayerInjectionHandler {
}
}
/**
* Invoke special routines for handling disconnect before a player is uninjected.
* @param player - player to process.
*/
public void handleDisconnect(Player player) {
PlayerInjector injector = getInjector(player);
if (injector != null) {
injector.handleDisconnect();
}
}
/**
* Unregisters the given player.
* @param player - player to unregister.

View File

@ -451,6 +451,11 @@ abstract class PlayerInjector {
cleanHook();
clean = true;
}
/**
* Clean up after the player has disconnected.
*/
public abstract void handleDisconnect();
/**
* Override to add custom cleanup behavior.

View File

@ -68,7 +68,7 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
}
/**
* Invoksed when an element is being removed.
* Invoked when an element is being removed.
* @param removing - the element being removed.
*/
protected void onRemoved(TKey removing) {
@ -264,6 +264,15 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
addMapping(target, replacement, false);
}
/**
* Retrieve the old value, if it exists.
* @param target - the key.
* @return The value that was replaced, or NULL.
*/
public TKey getMapping(TKey target) {
return replaceMap.get(target);
}
/**
* Add a replace rule.
* <p>
@ -284,8 +293,9 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
/**
* Revert the given mapping.
* @param target - the instance we replaced.
* @return The old mapped value, or NULL if nothing was replaced.
*/
public synchronized void removeMapping(TKey target) {
public synchronized TKey removeMapping(TKey target) {
// Make sure the mapping exist
if (replaceMap.containsKey(target)) {
TKey replacement = replaceMap.get(target);
@ -293,7 +303,25 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
// Revert existing elements
replaceAll(replacement, target);
return replacement;
}
return null;
}
/**
* Swap the new replaced value with its old value.
* @param target - the instance we replaced.
* @param The old mapped value, or NULL if nothing was swapped.
*/
public synchronized TKey swapMapping(TKey target) {
// Make sure the mapping exist
TKey replacement = removeMapping(target);
// Add the reverse
if (replacement != null) {
replaceMap.put(replacement, target);
}
return replacement;
}
/**