Archiviert
13
0

First test of the pre-login injector.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-10-15 00:31:55 +02:00
Ursprung 39805c5502
Commit 9b4b161602
7 geänderte Dateien mit 2012 neuen und 1929 gelöschten Zeilen

Datei anzeigen

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.comphenix.protocol</groupId> <groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId> <artifactId>ProtocolLib</artifactId>
<version>1.3.3</version> <version>1.3.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>Provides read/write access to the Minecraft protocol.</description> <description>Provides read/write access to the Minecraft protocol.</description>

Datei anzeigen

@ -38,6 +38,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin; 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.async.AsyncMarker;
import com.comphenix.protocol.events.*; import com.comphenix.protocol.events.*;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler; 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.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -61,6 +63,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
* @author Kristian * @author Kristian
*/ */
public enum PlayerInjectHooks { 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. * Override the network handler object itself. Only works in 1.3.
* <p> * <p>
@ -463,7 +470,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
*/ */
public void initializePlayers(Player[] players) { public void initializePlayers(Player[] players) {
for (Player 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 { try {
manager.registerEvents(new Listener() { 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) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
playerInjection.injectPlayer(event.getPlayer()); playerInjection.injectPlayer(event.getPlayer(), GamePhase.PLAYING);
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @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"); Class eventPriority = loader.loadClass("org.bukkit.event.Event$Priority");
// Get the priority // Get the priority
Object priorityNormal = Enum.valueOf(eventPriority, "Monitor"); Object priorityMonitor = Enum.valueOf(eventPriority, "Monitor");
// Get event types // Get event types
Object playerLoginType = Enum.valueOf(eventTypes, "PLAYER_LOGIN");
Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN"); Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN");
Object playerQuitType = Enum.valueOf(eventTypes, "PLAYER_QUIT"); Object playerQuitType = Enum.valueOf(eventTypes, "PLAYER_QUIT");
Object pluginDisabledType = Enum.valueOf(eventTypes, "PLUGIN_DISABLE"); Object pluginDisabledType = Enum.valueOf(eventTypes, "PLUGIN_DISABLE");
@ -549,8 +562,10 @@ 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 PlayerLoginEvent)
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer(), GamePhase.LOGIN);
if (event instanceof PlayerJoinEvent) if (event instanceof PlayerJoinEvent)
playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer()); playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer(), GamePhase.PLAYING);
else if (event instanceof PlayerQuitEvent) else if (event instanceof PlayerQuitEvent)
playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer()); playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
} }
@ -579,9 +594,10 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
Object playerProxy = playerEx.create(); Object playerProxy = playerEx.create();
Object serverProxy = serverEx.create(); Object serverProxy = serverEx.create();
registerEvent.invoke(manager, playerJoinType, playerProxy, priorityNormal, plugin); registerEvent.invoke(manager, playerLoginType, playerProxy, priorityMonitor, plugin);
registerEvent.invoke(manager, playerQuitType, playerProxy, priorityNormal, plugin); registerEvent.invoke(manager, playerJoinType, playerProxy, priorityMonitor, plugin);
registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityNormal, plugin); registerEvent.invoke(manager, playerQuitType, playerProxy, priorityMonitor, plugin);
registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityMonitor, plugin);
// A lot can go wrong // A lot can go wrong
} catch (ClassNotFoundException e1) { } catch (ClassNotFoundException e1) {

Datei anzeigen

@ -32,6 +32,8 @@ import com.comphenix.protocol.Packets;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker; 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.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
@ -190,7 +192,13 @@ class NetworkFieldInjector extends PlayerInjector {
} }
@Override @Override
public boolean canInject() { public boolean canInject(GamePhase phase) {
// All phases should work
return true; return true;
} }
@Override
public PlayerInjectHooks getHookType() {
return PlayerInjectHooks.NETWORK_HANDLER_FIELDS;
}
} }

Datei anzeigen

@ -33,6 +33,8 @@ import com.comphenix.protocol.Packets;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker; 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. * Injection method that overrides the NetworkHandler itself, and it's sendPacket-method.
@ -137,7 +139,13 @@ class NetworkObjectInjector extends PlayerInjector {
} }
@Override @Override
public boolean canInject() { public boolean canInject(GamePhase phase) {
// Works for all phases
return true; return true;
} }
@Override
public PlayerInjectHooks getHookType() {
return PlayerInjectHooks.NETWORK_MANAGER_OBJECT;
}
} }

Datei anzeigen

@ -35,6 +35,8 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker; 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.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.ObjectCloner; import com.comphenix.protocol.reflect.ObjectCloner;
@ -260,7 +262,13 @@ public class NetworkServerInjector extends PlayerInjector {
} }
@Override @Override
public boolean canInject() { public boolean canInject(GamePhase phase) {
return true; // Doesn't work when logging in
return phase == GamePhase.PLAYING || phase == GamePhase.CLOSING;
}
@Override
public PlayerInjectHooks getHookType() {
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
} }
} }

Datei anzeigen

@ -47,6 +47,16 @@ import com.google.common.collect.ImmutableSet;
*/ */
public class PlayerInjectionHandler { public class PlayerInjectionHandler {
/**
* The current player phase.
* @author Kristian
*/
public enum GamePhase {
LOGIN,
PLAYING,
CLOSING,
}
// Server connection injection // Server connection injection
private InjectedServerConnection serverInjection; private InjectedServerConnection serverInjection;
@ -139,69 +149,94 @@ public class PlayerInjectionHandler {
return connectionLookup.get(inputStream); 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. * Initialize a player hook, allowing us to read server packets.
* @param player - player to hook. * @param player - player to hook.
*/ */
public void injectPlayer(Player player) { public void injectPlayer(Player player, GamePhase phase) {
PlayerInjector injector = null; PlayerInjector injector = playerInjection.get(player);
PlayerInjectHooks currentHook = playerHook; PlayerInjectHooks tempHook = playerHook;
boolean firstPlayer = lastSuccessfulHook == null; 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 // Don't inject if the class has closed
if (!hasClosed && player != null && !playerInjection.containsKey(player)) { if (!hasClosed && player != null && (tempHook != getInjectorType(injector) || invalidInjector)) {
while (true) { 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 { try {
injector = getHookInstance(player, currentHook); injector = getHookInstance(player, tempHook);
injector.initialize();
injector.injectManager();
DataInputStream inputStream = injector.getInputStream(false); // Make sure this injection method supports the current game phase
if (injector.canInject(phase)) {
injector.initialize();
injector.injectManager();
if (!player.isOnline() || inputStream == null) { DataInputStream inputStream = injector.getInputStream(false);
throw new PlayerLoggedOutException();
if (!player.isOnline() || inputStream == null) {
throw new PlayerLoggedOutException();
}
connectionLookup.put(inputStream, player);
break;
} }
playerInjection.put(player, injector);
connectionLookup.put(inputStream, player);
break;
} catch (PlayerLoggedOutException e) { } catch (PlayerLoggedOutException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
// Mark this injection attempt as a failure // Mark this injection attempt as a failure
logger.log(Level.SEVERE, "Player hook " + currentHook.toString() + " failed.", e); logger.log(Level.SEVERE, "Player hook " + tempHook.toString() + " failed.", e);
hookFailed = true;
}
// Clean up as much as possible // Choose the previous player hook type
try { tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1];
if (injector != null) logger.log(Level.INFO, "Switching to " + tempHook.toString() + " instead.");
injector.cleanupAll();
} catch (Exception e2) {
logger.log(Level.WARNING, "Cleaing up after player hook failed.", e);
}
if (currentHook.ordinal() > 0) { // Check for UTTER FAILURE
if (tempHook == PlayerInjectHooks.NONE) {
cleanupHook(injector);
injector = null;
hookFailed = true;
}
// Choose the previous player hook type // Should we set the default hook method too?
currentHook = PlayerInjectHooks.values()[currentHook.ordinal() - 1]; if (hookFailed) {
logger.log(Level.INFO, "Switching to " + currentHook.toString() + " instead."); permanentHook = tempHook;
} else {
// UTTER FAILURE
playerInjection.put(player, null);
return;
}
} }
} }
// Update values // Update values
if (injector != null) if (injector != null)
lastSuccessfulHook = injector; lastSuccessfulHook = injector;
if (currentHook != playerHook || firstPlayer) if (permanentHook != playerHook)
setPlayerHook(currentHook); 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);
} }
} }

Datei anzeigen

@ -35,6 +35,8 @@ import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker; 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.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
@ -269,7 +271,13 @@ abstract class PlayerInjector {
* Determine if this inject method can even be attempted. * Determine if this inject method can even be attempted.
* @return TRUE if can be attempted, though possibly with failure, FALSE otherwise. * @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. * Invoked before a new listener is registered.