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>
<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>

Datei anzeigen

@ -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) {

Datei anzeigen

@ -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;
}
}

Datei anzeigen

@ -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;
}
}

Datei anzeigen

@ -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;
}
}

Datei anzeigen

@ -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,69 +149,94 @@ 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.initialize();
injector.injectManager();
injector = getHookInstance(player, tempHook);
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) {
throw new PlayerLoggedOutException();
DataInputStream inputStream = injector.getInputStream(false);
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) {
throw e;
} catch (Exception e) {
// 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
try {
if (injector != null)
injector.cleanupAll();
} catch (Exception e2) {
logger.log(Level.WARNING, "Cleaing up after player hook failed.", e);
}
// Choose the previous player hook type
tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1];
logger.log(Level.INFO, "Switching to " + tempHook.toString() + " instead.");
if (currentHook.ordinal() > 0) {
// Check for UTTER FAILURE
if (tempHook == PlayerInjectHooks.NONE) {
cleanupHook(injector);
injector = null;
hookFailed = true;
}
// 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;
}
// 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);
}
}

Datei anzeigen

@ -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.