First test of the pre-login injector.
Dieser Commit ist enthalten in:
Ursprung
39805c5502
Commit
9b4b161602
@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>1.3.3</version>
|
||||
<version>1.3.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||
|
||||
|
@ -38,6 +38,7 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
@ -49,6 +50,7 @@ import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.async.AsyncMarker;
|
||||
import com.comphenix.protocol.events.*;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.GamePhase;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.google.common.base.Objects;
|
||||
@ -61,6 +63,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
* @author Kristian
|
||||
*/
|
||||
public enum PlayerInjectHooks {
|
||||
/**
|
||||
* The injection hook that does nothing. Set when every other inject hook fails.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Override the network handler object itself. Only works in 1.3.
|
||||
* <p>
|
||||
@ -463,7 +470,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
*/
|
||||
public void initializePlayers(Player[] players) {
|
||||
for (Player player : players)
|
||||
playerInjection.injectPlayer(player);
|
||||
playerInjection.injectPlayer(player, GamePhase.PLAYING);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -475,9 +482,14 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
|
||||
try {
|
||||
manager.registerEvents(new Listener() {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
playerInjection.injectPlayer(event.getPlayer(), GamePhase.LOGIN);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
playerInjection.injectPlayer(event.getPlayer());
|
||||
playerInjection.injectPlayer(event.getPlayer(), GamePhase.PLAYING);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
@ -521,9 +533,10 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
Class eventPriority = loader.loadClass("org.bukkit.event.Event$Priority");
|
||||
|
||||
// Get the priority
|
||||
Object priorityNormal = Enum.valueOf(eventPriority, "Monitor");
|
||||
Object priorityMonitor = Enum.valueOf(eventPriority, "Monitor");
|
||||
|
||||
// Get event types
|
||||
Object playerLoginType = Enum.valueOf(eventTypes, "PLAYER_LOGIN");
|
||||
Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN");
|
||||
Object playerQuitType = Enum.valueOf(eventTypes, "PLAYER_QUIT");
|
||||
Object pluginDisabledType = Enum.valueOf(eventTypes, "PLUGIN_DISABLE");
|
||||
@ -549,8 +562,10 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
Object event = args[0];
|
||||
|
||||
// Check for the correct event
|
||||
if (event instanceof PlayerLoginEvent)
|
||||
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer(), GamePhase.LOGIN);
|
||||
if (event instanceof PlayerJoinEvent)
|
||||
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer());
|
||||
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer(), GamePhase.PLAYING);
|
||||
else if (event instanceof PlayerQuitEvent)
|
||||
playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
|
||||
}
|
||||
@ -579,9 +594,10 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
Object playerProxy = playerEx.create();
|
||||
Object serverProxy = serverEx.create();
|
||||
|
||||
registerEvent.invoke(manager, playerJoinType, playerProxy, priorityNormal, plugin);
|
||||
registerEvent.invoke(manager, playerQuitType, playerProxy, priorityNormal, plugin);
|
||||
registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityNormal, plugin);
|
||||
registerEvent.invoke(manager, playerLoginType, playerProxy, priorityMonitor, plugin);
|
||||
registerEvent.invoke(manager, playerJoinType, playerProxy, priorityMonitor, plugin);
|
||||
registerEvent.invoke(manager, playerQuitType, playerProxy, priorityMonitor, plugin);
|
||||
registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityMonitor, plugin);
|
||||
|
||||
// A lot can go wrong
|
||||
} catch (ClassNotFoundException e1) {
|
||||
|
@ -32,6 +32,8 @@ import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.GamePhase;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@ -190,7 +192,13 @@ class NetworkFieldInjector extends PlayerInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
public boolean canInject(GamePhase phase) {
|
||||
// All phases should work
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerInjectHooks getHookType() {
|
||||
return PlayerInjectHooks.NETWORK_HANDLER_FIELDS;
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.GamePhase;
|
||||
|
||||
/**
|
||||
* Injection method that overrides the NetworkHandler itself, and it's sendPacket-method.
|
||||
@ -137,7 +139,13 @@ class NetworkObjectInjector extends PlayerInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
public boolean canInject(GamePhase phase) {
|
||||
// Works for all phases
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerInjectHooks getHookType() {
|
||||
return PlayerInjectHooks.NETWORK_MANAGER_OBJECT;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.GamePhase;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.ObjectCloner;
|
||||
@ -260,7 +262,13 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
return true;
|
||||
public boolean canInject(GamePhase phase) {
|
||||
// Doesn't work when logging in
|
||||
return phase == GamePhase.PLAYING || phase == GamePhase.CLOSING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerInjectHooks getHookType() {
|
||||
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,16 @@ import com.google.common.collect.ImmutableSet;
|
||||
*/
|
||||
public class PlayerInjectionHandler {
|
||||
|
||||
/**
|
||||
* The current player phase.
|
||||
* @author Kristian
|
||||
*/
|
||||
public enum GamePhase {
|
||||
LOGIN,
|
||||
PLAYING,
|
||||
CLOSING,
|
||||
}
|
||||
|
||||
// Server connection injection
|
||||
private InjectedServerConnection serverInjection;
|
||||
|
||||
@ -139,21 +149,37 @@ public class PlayerInjectionHandler {
|
||||
return connectionLookup.get(inputStream);
|
||||
}
|
||||
|
||||
private PlayerInjectHooks getInjectorType(PlayerInjector injector) {
|
||||
return injector != null ? injector.getHookType() : PlayerInjectHooks.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a player hook, allowing us to read server packets.
|
||||
* @param player - player to hook.
|
||||
*/
|
||||
public void injectPlayer(Player player) {
|
||||
public void injectPlayer(Player player, GamePhase phase) {
|
||||
|
||||
PlayerInjector injector = null;
|
||||
PlayerInjectHooks currentHook = playerHook;
|
||||
boolean firstPlayer = lastSuccessfulHook == null;
|
||||
PlayerInjector injector = playerInjection.get(player);
|
||||
PlayerInjectHooks tempHook = playerHook;
|
||||
PlayerInjectHooks permanentHook = tempHook;
|
||||
|
||||
// See if we need to inject something else
|
||||
boolean invalidInjector = injector != null ? !injector.canInject(phase) : false;
|
||||
|
||||
// Don't inject if the class has closed
|
||||
if (!hasClosed && player != null && !playerInjection.containsKey(player)) {
|
||||
while (true) {
|
||||
if (!hasClosed && player != null && (tempHook != getInjectorType(injector) || invalidInjector)) {
|
||||
while (tempHook != PlayerInjectHooks.NONE) {
|
||||
// Whether or not the current hook method failed completely
|
||||
boolean hookFailed = false;
|
||||
|
||||
// Remove the previous hook, if any
|
||||
cleanupHook(injector);
|
||||
|
||||
try {
|
||||
injector = getHookInstance(player, currentHook);
|
||||
injector = getHookInstance(player, tempHook);
|
||||
|
||||
// Make sure this injection method supports the current game phase
|
||||
if (injector.canInject(phase)) {
|
||||
injector.initialize();
|
||||
injector.injectManager();
|
||||
|
||||
@ -163,45 +189,54 @@ public class PlayerInjectionHandler {
|
||||
throw new PlayerLoggedOutException();
|
||||
}
|
||||
|
||||
playerInjection.put(player, injector);
|
||||
connectionLookup.put(inputStream, player);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} catch (PlayerLoggedOutException e) {
|
||||
throw e;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
// Mark this injection attempt as a failure
|
||||
logger.log(Level.SEVERE, "Player hook " + currentHook.toString() + " failed.", e);
|
||||
|
||||
// Clean up as much as possible
|
||||
try {
|
||||
if (injector != null)
|
||||
injector.cleanupAll();
|
||||
} catch (Exception e2) {
|
||||
logger.log(Level.WARNING, "Cleaing up after player hook failed.", e);
|
||||
logger.log(Level.SEVERE, "Player hook " + tempHook.toString() + " failed.", e);
|
||||
hookFailed = true;
|
||||
}
|
||||
|
||||
if (currentHook.ordinal() > 0) {
|
||||
|
||||
// Choose the previous player hook type
|
||||
currentHook = PlayerInjectHooks.values()[currentHook.ordinal() - 1];
|
||||
logger.log(Level.INFO, "Switching to " + currentHook.toString() + " instead.");
|
||||
} else {
|
||||
// UTTER FAILURE
|
||||
playerInjection.put(player, null);
|
||||
return;
|
||||
tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1];
|
||||
logger.log(Level.INFO, "Switching to " + tempHook.toString() + " instead.");
|
||||
|
||||
// Check for UTTER FAILURE
|
||||
if (tempHook == PlayerInjectHooks.NONE) {
|
||||
cleanupHook(injector);
|
||||
injector = null;
|
||||
hookFailed = true;
|
||||
}
|
||||
|
||||
// Should we set the default hook method too?
|
||||
if (hookFailed) {
|
||||
permanentHook = tempHook;
|
||||
}
|
||||
}
|
||||
|
||||
// Update values
|
||||
if (injector != null)
|
||||
lastSuccessfulHook = injector;
|
||||
if (currentHook != playerHook || firstPlayer)
|
||||
setPlayerHook(currentHook);
|
||||
if (permanentHook != playerHook)
|
||||
setPlayerHook(tempHook);
|
||||
|
||||
// Save last injector
|
||||
playerInjection.put(player, injector);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupHook(PlayerInjector injector) {
|
||||
// Clean up as much as possible
|
||||
try {
|
||||
if (injector != null)
|
||||
injector.cleanupAll();
|
||||
} catch (Exception e2) {
|
||||
logger.log(Level.WARNING, "Cleaing up after player hook failed.", e2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,8 @@ import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.GamePhase;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@ -269,7 +271,13 @@ abstract class PlayerInjector {
|
||||
* Determine if this inject method can even be attempted.
|
||||
* @return TRUE if can be attempted, though possibly with failure, FALSE otherwise.
|
||||
*/
|
||||
public abstract boolean canInject();
|
||||
public abstract boolean canInject(GamePhase state);
|
||||
|
||||
/**
|
||||
* Retrieve the hook type this class represents.
|
||||
* @return Hook type this class represents.
|
||||
*/
|
||||
public abstract PlayerInjectHooks getHookType();
|
||||
|
||||
/**
|
||||
* Invoked before a new listener is registered.
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren