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>
|
<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>
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren