Prevent the PlayerQuitEvent from being fired twice. FIXES Ticket-2.
Dieser Commit ist enthalten in:
Ursprung
0aac8ebf0a
Commit
96ad954cf7
@ -4,7 +4,7 @@
|
|||||||
<groupId>com.comphenix.protocol</groupId>
|
<groupId>com.comphenix.protocol</groupId>
|
||||||
<artifactId>ProtocolLib</artifactId>
|
<artifactId>ProtocolLib</artifactId>
|
||||||
<name>ProtocolLib</name>
|
<name>ProtocolLib</name>
|
||||||
<version>1.4.2</version>
|
<version>1.4.3-SNAPSHOT</version>
|
||||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||||
<url>http://dev.bukkit.org/server-mods/protocollib/</url>
|
<url>http://dev.bukkit.org/server-mods/protocollib/</url>
|
||||||
<developers>
|
<developers>
|
||||||
|
@ -606,6 +606,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
playerInjection.handleDisconnect(event.getPlayer());
|
||||||
playerInjection.uninjectPlayer(event.getPlayer());
|
playerInjection.uninjectPlayer(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,10 +690,14 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
Object event = args[0];
|
Object event = args[0];
|
||||||
|
|
||||||
// Check for the correct event
|
// Check for the correct event
|
||||||
if (event instanceof PlayerJoinEvent)
|
if (event instanceof PlayerJoinEvent) {
|
||||||
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer());
|
Player player = ((PlayerJoinEvent) event).getPlayer();
|
||||||
else if (event instanceof PlayerQuitEvent)
|
playerInjection.injectPlayer(player);
|
||||||
playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
|
} else if (event instanceof PlayerQuitEvent) {
|
||||||
|
Player player = ((PlayerQuitEvent) event).getPlayer();
|
||||||
|
playerInjection.handleDisconnect(player);
|
||||||
|
playerInjection.uninjectPlayer(player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +191,11 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
overridenLists.clear();
|
overridenLists.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleDisconnect() {
|
||||||
|
// No need to do anything
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canInject(GamePhase phase) {
|
public boolean canInject(GamePhase phase) {
|
||||||
// All phases should work
|
// All phases should work
|
||||||
|
@ -159,6 +159,11 @@ class NetworkObjectInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleDisconnect() {
|
||||||
|
// No need to do anything
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canInject(GamePhase phase) {
|
public boolean canInject(GamePhase phase) {
|
||||||
// Works for all phases
|
// Works for all phases
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
package com.comphenix.protocol.injector.player;
|
package com.comphenix.protocol.injector.player;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
import net.minecraft.server.Packet;
|
||||||
@ -50,6 +52,7 @@ import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
|||||||
*/
|
*/
|
||||||
public class NetworkServerInjector extends PlayerInjector {
|
public class NetworkServerInjector extends PlayerInjector {
|
||||||
|
|
||||||
|
private static Field disconnectField;
|
||||||
private static Method sendPacketMethod;
|
private static Method sendPacketMethod;
|
||||||
private InjectedServerConnection serverInjection;
|
private InjectedServerConnection serverInjection;
|
||||||
|
|
||||||
@ -59,6 +62,9 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
// Used to create proxy objects
|
// Used to create proxy objects
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
// Whether or not the player has disconnected
|
||||||
|
private boolean hasDisconnected;
|
||||||
|
|
||||||
public NetworkServerInjector(
|
public NetworkServerInjector(
|
||||||
ClassLoader classLoader, Logger logger, Player player,
|
ClassLoader classLoader, Logger logger, Player player,
|
||||||
ListenerInvoker invoker, IntegerSet sendingFilters,
|
ListenerInvoker invoker, IntegerSet sendingFilters,
|
||||||
@ -250,11 +256,42 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent the PlayerQuitEvent from being sent twice
|
||||||
|
if (hasDisconnected) {
|
||||||
|
setDisconnect(serverHandlerRef.getValue(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInjection.revertServerHandler(serverHandler);
|
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
|
@Override
|
||||||
public void checkListener(PacketListener listener) {
|
public void checkListener(PacketListener listener) {
|
||||||
// We support everything
|
// We support everything
|
||||||
|
@ -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.
|
* Unregisters the given player.
|
||||||
* @param player - player to unregister.
|
* @param player - player to unregister.
|
||||||
|
@ -452,6 +452,11 @@ abstract class PlayerInjector {
|
|||||||
clean = true;
|
clean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up after the player has disconnected.
|
||||||
|
*/
|
||||||
|
public abstract void handleDisconnect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override to add custom cleanup behavior.
|
* Override to add custom cleanup behavior.
|
||||||
*/
|
*/
|
||||||
|
@ -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.
|
* @param removing - the element being removed.
|
||||||
*/
|
*/
|
||||||
protected void onRemoved(TKey removing) {
|
protected void onRemoved(TKey removing) {
|
||||||
@ -264,6 +264,15 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
|
|||||||
addMapping(target, replacement, false);
|
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.
|
* Add a replace rule.
|
||||||
* <p>
|
* <p>
|
||||||
@ -284,8 +293,9 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
|
|||||||
/**
|
/**
|
||||||
* Revert the given mapping.
|
* Revert the given mapping.
|
||||||
* @param target - the instance we replaced.
|
* @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
|
// Make sure the mapping exist
|
||||||
if (replaceMap.containsKey(target)) {
|
if (replaceMap.containsKey(target)) {
|
||||||
TKey replacement = replaceMap.get(target);
|
TKey replacement = replaceMap.get(target);
|
||||||
@ -293,7 +303,25 @@ class ReplacedArrayList<TKey> extends ArrayList<TKey> {
|
|||||||
|
|
||||||
// Revert existing elements
|
// Revert existing elements
|
||||||
replaceAll(replacement, target);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren