Archiviert
13
0

Moved all player related injection methods into a separate package.

This should make the code a little bit clearer.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-10-04 21:56:39 +02:00
Ursprung eb12808483
Commit af3e278e06
13 geänderte Dateien mit 572 neuen und 241 gelöschten Zeilen

Datei anzeigen

@ -10,5 +10,6 @@
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jre6"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jre6"/>
<classpathentry kind="lib" path="D:/Games/Minecraft/Server Mods/1.3.2/SpoutPlugin.jar"/>
<classpathentry kind="output" path="class"/> <classpathentry kind="output" path="class"/>
</classpath> </classpath>

Datei anzeigen

@ -0,0 +1,27 @@
package com.comphenix.protocol.injector;
import net.minecraft.server.Packet;
import com.comphenix.protocol.events.PacketEvent;
public interface ListenerInvoker {
/**
* Invokes the given packet event for every registered listener.
* @param event - the packet event to invoke.
*/
public abstract void invokePacketRecieving(PacketEvent event);
/**
* Invokes the given packet event for every registered listener.
* @param event - the packet event to invoke.
*/
public abstract void invokePacketSending(PacketEvent event);
/**
* Retrieve the associated ID of a packet.
* @param packet - the packet.
* @return The packet ID.
*/
public abstract int getPacketID(Packet packet);
}

Datei anzeigen

@ -17,13 +17,10 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import java.io.DataInputStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level; import java.util.logging.Level;
@ -51,12 +48,13 @@ import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.async.AsyncFilterManager; 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.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;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
public final class PacketFilterManager implements ProtocolManager { public final class PacketFilterManager implements ProtocolManager, ListenerInvoker {
/** /**
* Sets the inject hook type. Different types allow for maximum compatibility. * Sets the inject hook type. Different types allow for maximum compatibility.
@ -87,21 +85,11 @@ public final class PacketFilterManager implements ProtocolManager {
private Set<PacketListener> packetListeners = private Set<PacketListener> packetListeners =
Collections.newSetFromMap(new ConcurrentHashMap<PacketListener, Boolean>()); Collections.newSetFromMap(new ConcurrentHashMap<PacketListener, Boolean>());
// Player injection
private Map<DataInputStream, Player> connectionLookup = new ConcurrentHashMap<DataInputStream, Player>();
private Map<Player, PlayerInjector> playerInjection = new HashMap<Player, PlayerInjector>();
// Player injection type
private PlayerInjectHooks playerHook = PlayerInjectHooks.NETWORK_SERVER_OBJECT;
// Packet injection // Packet injection
private PacketInjector packetInjector; private PacketInjector packetInjector;
// Server connection injection // Player injection
private InjectedServerConnection serverInjection; private PlayerInjectionHandler playerInjection;
// Enabled packet filters
private Set<Integer> sendingFilters = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
// The two listener containers // The two listener containers
private SortedPacketListenerList recievedListeners = new SortedPacketListenerList(); private SortedPacketListenerList recievedListeners = new SortedPacketListenerList();
@ -113,9 +101,6 @@ public final class PacketFilterManager implements ProtocolManager {
// The default class loader // The default class loader
private ClassLoader classLoader; private ClassLoader classLoader;
// The last successful player hook
private PlayerInjector lastSuccessfulHook;
// Error logger // Error logger
private Logger logger; private Logger logger;
@ -135,9 +120,9 @@ public final class PacketFilterManager implements ProtocolManager {
// Initialize values // Initialize values
this.classLoader = classLoader; this.classLoader = classLoader;
this.logger = logger; this.logger = logger;
this.packetInjector = new PacketInjector(classLoader, this, connectionLookup); this.playerInjection = new PlayerInjectionHandler(classLoader, logger, this, server);
this.packetInjector = new PacketInjector(classLoader, this, playerInjection);
this.asyncFilterManager = new AsyncFilterManager(logger, server.getScheduler(), this); this.asyncFilterManager = new AsyncFilterManager(logger, server.getScheduler(), this);
this.serverInjection = new InjectedServerConnection(logger, server);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
logger.log(Level.SEVERE, "Unable to initialize packet injector.", e); logger.log(Level.SEVERE, "Unable to initialize packet injector.", e);
} }
@ -153,7 +138,7 @@ public final class PacketFilterManager implements ProtocolManager {
* @return Injection method for reading server packets. * @return Injection method for reading server packets.
*/ */
public PlayerInjectHooks getPlayerHook() { public PlayerInjectHooks getPlayerHook() {
return playerHook; return playerInjection.getPlayerHook();
} }
/** /**
@ -161,18 +146,10 @@ public final class PacketFilterManager implements ProtocolManager {
* @param playerHook - the new injection method for reading server packets. * @param playerHook - the new injection method for reading server packets.
*/ */
public void setPlayerHook(PlayerInjectHooks playerHook) { public void setPlayerHook(PlayerInjectHooks playerHook) {
this.playerHook = playerHook; playerInjection.setPlayerHook(playerHook);
// Make sure the current listeners are compatible // Make sure the current listeners are compatible
if (lastSuccessfulHook != null) { playerInjection.checkListener(packetListeners);
for (PacketListener listener : packetListeners) {
try {
checkListener(listener);
} catch (IllegalStateException e) {
logger.log(Level.WARNING, "Unsupported listener.", e);
}
}
}
} }
public Logger getLogger() { public Logger getLogger() {
@ -204,14 +181,14 @@ public final class PacketFilterManager implements ProtocolManager {
verifyWhitelist(listener, sending); verifyWhitelist(listener, sending);
sendingListeners.addListener(listener, sending); sendingListeners.addListener(listener, sending);
enablePacketFilters(ConnectionSide.SERVER_SIDE, sending.getWhitelist()); enablePacketFilters(ConnectionSide.SERVER_SIDE, sending.getWhitelist());
// Make sure this is possible
playerInjection.checkListener(listener);
} }
if (hasReceiving) { if (hasReceiving) {
verifyWhitelist(listener, receiving); verifyWhitelist(listener, receiving);
recievedListeners.addListener(listener, receiving); recievedListeners.addListener(listener, receiving);
enablePacketFilters(ConnectionSide.CLIENT_SIDE, receiving.getWhitelist()); enablePacketFilters(ConnectionSide.CLIENT_SIDE, receiving.getWhitelist());
// We don't know if we've hooked any players yet
checkListener(listener);
} }
// Inform our injected hooks // Inform our injected hooks
@ -235,20 +212,6 @@ public final class PacketFilterManager implements ProtocolManager {
} }
} }
/**
* Determine if a listener is valid or not.
* @param listener - listener to check.
* @throws IllegalStateException If the given listener's whitelist cannot be fulfilled.
*/
public void checkListener(PacketListener listener) {
try {
if (lastSuccessfulHook != null)
lastSuccessfulHook.checkListener(listener);
} catch (Exception e) {
throw new IllegalStateException("Registering listener " + PacketAdapter.getPluginName(listener) + " failed", e);
}
}
@Override @Override
public void removePacketListener(PacketListener listener) { public void removePacketListener(PacketListener listener) {
if (listener == null) if (listener == null)
@ -292,18 +255,12 @@ public final class PacketFilterManager implements ProtocolManager {
asyncFilterManager.unregisterAsyncHandlers(plugin); asyncFilterManager.unregisterAsyncHandlers(plugin);
} }
/** @Override
* Invokes the given packet event for every registered listener.
* @param event - the packet event to invoke.
*/
public void invokePacketRecieving(PacketEvent event) { public void invokePacketRecieving(PacketEvent event) {
handlePacket(recievedListeners, event, false); handlePacket(recievedListeners, event, false);
} }
/** @Override
* Invokes the given packet event for every registered listener.
* @param event - the packet event to invoke.
*/
public void invokePacketSending(PacketEvent event) { public void invokePacketSending(PacketEvent event) {
handlePacket(sendingListeners, event, true); handlePacket(sendingListeners, event, true);
} }
@ -356,7 +313,7 @@ public final class PacketFilterManager implements ProtocolManager {
for (int packetID : packets) { for (int packetID : packets) {
if (side.isForServer()) if (side.isForServer())
sendingFilters.add(packetID); playerInjection.addPacketHandler(packetID);
if (side.isForClient() && packetInjector != null) if (side.isForClient() && packetInjector != null)
packetInjector.addPacketHandler(packetID); packetInjector.addPacketHandler(packetID);
} }
@ -373,7 +330,7 @@ public final class PacketFilterManager implements ProtocolManager {
for (int packetID : packets) { for (int packetID : packets) {
if (side.isForServer()) if (side.isForServer())
sendingFilters.remove(packetID); playerInjection.removePacketHandler(packetID);
if (side.isForClient() && packetInjector != null) if (side.isForClient() && packetInjector != null)
packetInjector.removePacketHandler(packetID); packetInjector.removePacketHandler(packetID);
} }
@ -391,7 +348,7 @@ public final class PacketFilterManager implements ProtocolManager {
if (packet == null) if (packet == null)
throw new IllegalArgumentException("packet cannot be NULL."); throw new IllegalArgumentException("packet cannot be NULL.");
getInjector(reciever).sendServerPacket(packet.getHandle(), filters); playerInjection.sendServerPacket(reciever, packet, filters);
} }
@Override @Override
@ -407,17 +364,21 @@ public final class PacketFilterManager implements ProtocolManager {
if (packet == null) if (packet == null)
throw new IllegalArgumentException("packet cannot be NULL."); throw new IllegalArgumentException("packet cannot be NULL.");
PlayerInjector injector = getInjector(sender);
Packet mcPacket = packet.getHandle(); Packet mcPacket = packet.getHandle();
// Make sure the packet isn't cancelled // Make sure the packet isn't cancelled
packetInjector.undoCancel(packet.getID(), mcPacket); packetInjector.undoCancel(packet.getID(), mcPacket);
if (filters) { if (filters) {
mcPacket = injector.handlePacketRecieved(mcPacket); PacketEvent event = packetInjector.packetRecieved(packet, sender);
if (!event.isCancelled())
mcPacket = event.getPacket().getHandle();
else
return;
} }
injector.processPacket(mcPacket); playerInjection.processPacket(sender, mcPacket);
} }
@Override @Override
@ -448,7 +409,7 @@ public final class PacketFilterManager implements ProtocolManager {
@Override @Override
public Set<Integer> getSendingFilters() { public Set<Integer> getSendingFilters() {
return ImmutableSet.copyOf(sendingFilters); return playerInjection.getSendingFilters();
} }
@Override @Override
@ -467,92 +428,7 @@ public final class PacketFilterManager implements ProtocolManager {
*/ */
public void initializePlayers(Player[] players) { public void initializePlayers(Player[] players) {
for (Player player : players) for (Player player : players)
injectPlayer(player); playerInjection.injectPlayer(player);
}
/**
* Used to construct a player hook.
* @param player - the player to hook.
* @param hook - the hook type.
* @return A new player hoook
* @throws IllegalAccessException Unable to do our reflection magic.
*/
protected PlayerInjector getHookInstance(Player player, PlayerInjectHooks hook) throws IllegalAccessException {
// Construct the correct player hook
switch (hook) {
case NETWORK_HANDLER_FIELDS:
return new NetworkFieldInjector(player, this, sendingFilters);
case NETWORK_MANAGER_OBJECT:
return new NetworkObjectInjector(player, this, sendingFilters);
case NETWORK_SERVER_OBJECT:
return new NetworkServerInjector(player, this, sendingFilters, serverInjection);
default:
throw new IllegalArgumentException("Cannot construct a player injector.");
}
}
/**
* Initialize a player hook, allowing us to read server packets.
* @param player - player to hook.
*/
protected void injectPlayer(Player player) {
PlayerInjector injector = null;
PlayerInjectHooks currentHook = playerHook;
boolean firstPlayer = lastSuccessfulHook == null;
// Don't inject if the class has closed
if (!hasClosed && player != null && !playerInjection.containsKey(player)) {
while (true) {
try {
injector = getHookInstance(player, currentHook);
injector.injectManager();
DataInputStream inputStream = injector.getInputStream(false);
if (!player.isOnline() || inputStream == null) {
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);
}
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;
}
}
}
// Update values
if (injector != null)
lastSuccessfulHook = injector;
if (currentHook != playerHook || firstPlayer)
setPlayerHook(currentHook);
}
} }
/** /**
@ -567,12 +443,12 @@ public final class PacketFilterManager implements ProtocolManager {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
injectPlayer(event.getPlayer()); playerInjection.injectPlayer(event.getPlayer());
} }
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
uninjectPlayer(event.getPlayer()); playerInjection.uninjectPlayer(event.getPlayer());
} }
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@ -591,6 +467,14 @@ public final class PacketFilterManager implements ProtocolManager {
} }
} }
@Override
public int getPacketID(Packet packet) {
if (packet == null)
throw new IllegalArgumentException("Packet cannot be NULL.");
return MinecraftRegistry.getPacketToID().get(packet.getClass());
}
// Yes, this is crazy. // Yes, this is crazy.
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private void registerOld(PluginManager manager, Plugin plugin) { private void registerOld(PluginManager manager, Plugin plugin) {
@ -632,9 +516,9 @@ public final class PacketFilterManager implements ProtocolManager {
// Check for the correct event // Check for the correct event
if (event instanceof PlayerJoinEvent) if (event instanceof PlayerJoinEvent)
injectPlayer(((PlayerJoinEvent) event).getPlayer()); playerInjection.injectPlayer(((PlayerJoinEvent) event).getPlayer());
else if (event instanceof PlayerQuitEvent) else if (event instanceof PlayerQuitEvent)
uninjectPlayer(((PlayerQuitEvent) event).getPlayer()); playerInjection.uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
} }
return null; return null;
} }
@ -677,36 +561,6 @@ public final class PacketFilterManager implements ProtocolManager {
} }
} }
private void uninjectPlayer(Player player) {
if (!hasClosed && player != null) {
PlayerInjector injector = playerInjection.get(player);
if (injector != null) {
DataInputStream input = injector.getInputStream(true);
injector.cleanupAll();
playerInjection.remove(player);
connectionLookup.remove(input);
}
}
}
private PlayerInjector getInjector(Player player) {
if (!playerInjection.containsKey(player)) {
// What? Try to inject again.
injectPlayer(player);
}
PlayerInjector injector = playerInjection.get(player);
// Check that the injector was sucessfully added
if (injector != null)
return injector;
else
throw new IllegalArgumentException("Player has no injected handler.");
}
/** /**
* Retrieves the current plugin class loader. * Retrieves the current plugin class loader.
* @return Class loader. * @return Class loader.
@ -722,28 +576,19 @@ public final class PacketFilterManager implements ProtocolManager {
public void close() { public void close() {
// Guard // Guard
if (hasClosed || playerInjection == null) if (hasClosed)
return; return;
// Remove everything
for (PlayerInjector injection : playerInjection.values()) {
if (injection != null) {
injection.cleanupAll();
}
}
// Remove packet handlers // Remove packet handlers
if (packetInjector != null) if (packetInjector != null)
packetInjector.cleanupAll(); packetInjector.cleanupAll();
// Remove server handler // Remove server handler
serverInjection.cleanupAll(); playerInjection.close();
hasClosed = true; hasClosed = true;
// Remove listeners // Remove listeners
packetListeners.clear(); packetListeners.clear();
playerInjection.clear();
connectionLookup.clear();
// Clean up async handlers. We have to do this last. // Clean up async handlers. We have to do this last.
asyncFilterManager.cleanupAll(); asyncFilterManager.cleanupAll();

Datei anzeigen

@ -33,6 +33,7 @@ import net.sf.cglib.proxy.Enhancer;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
@ -48,10 +49,10 @@ class PacketInjector {
private static Object intHashMap; private static Object intHashMap;
// The packet filter manager // The packet filter manager
private PacketFilterManager manager; private ListenerInvoker manager;
// Allows us to determine the sender // Allows us to determine the sender
private Map<DataInputStream, Player> playerLookup; private PlayerInjectionHandler playerInjection;
// Allows us to look up read packet injectors // Allows us to look up read packet injectors
private Map<Integer, ReadPacketModifier> readModifier; private Map<Integer, ReadPacketModifier> readModifier;
@ -59,12 +60,12 @@ class PacketInjector {
// Class loader // Class loader
private ClassLoader classLoader; private ClassLoader classLoader;
public PacketInjector(ClassLoader classLoader, PacketFilterManager manager, public PacketInjector(ClassLoader classLoader, ListenerInvoker manager,
Map<DataInputStream, Player> playerLookup) throws IllegalAccessException { PlayerInjectionHandler playerInjection) throws IllegalAccessException {
this.classLoader = classLoader; this.classLoader = classLoader;
this.manager = manager; this.manager = manager;
this.playerLookup = playerLookup; this.playerInjection = playerInjection;
this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>(); this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>();
initialize(); initialize();
} }
@ -194,7 +195,18 @@ class PacketInjector {
// Called from the ReadPacketModified monitor // Called from the ReadPacketModified monitor
PacketEvent packetRecieved(PacketContainer packet, DataInputStream input) { PacketEvent packetRecieved(PacketContainer packet, DataInputStream input) {
Player client = playerLookup.get(input); Player client = playerInjection.getPlayerByConnection(input);
return packetRecieved(packet, client);
}
/**
* Let the packet listeners process the given packet.
* @param packet - a packet to process.
* @param client - the client that sent the packet.
* @return The resulting packet event.
*/
public PacketEvent packetRecieved(PacketContainer packet, Player client) {
PacketEvent event = PacketEvent.fromClient((Object) manager, packet, client); PacketEvent event = PacketEvent.fromClient((Object) manager, packet, client);
manager.invokePacketRecieving(event); manager.invokePacketRecieving(event);

Datei anzeigen

@ -1,17 +1,17 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Set; import java.util.Set;
import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket;
import net.minecraft.server.Packet; import net.minecraft.server.Packet;
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.MethodProxy;
import com.comphenix.protocol.injector.NetworkFieldInjector.FakePacket;
/** /**
* The array list that notifies when packets are sent by the server. * The array list that notifies when packets are sent by the server.
* *

Datei anzeigen

@ -1,4 +1,4 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;

Datei anzeigen

@ -1,4 +1,4 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -7,12 +7,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.Packets; 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.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;
@ -46,12 +48,27 @@ class NetworkFieldInjector extends PlayerInjector {
private static Field syncField; private static Field syncField;
private Object syncObject; private Object syncObject;
public NetworkFieldInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException { // Determine if we're listening
super(player, manager, sendingFilters); private Set<Integer> sendingFilters;
// Used to construct proxy objects
private ClassLoader classLoader;
public NetworkFieldInjector(ClassLoader classLoader, Logger logger, Player player,
ListenerInvoker manager, Set<Integer> sendingFilters) throws IllegalAccessException {
super(logger, player, manager);
this.classLoader = classLoader;
this.sendingFilters = sendingFilters;
} }
@Override @Override
protected synchronized void initialize() throws IllegalAccessException { protected boolean hasListener(int packetID) {
return sendingFilters.contains(packetID);
}
@Override
public synchronized void initialize() throws IllegalAccessException {
super.initialize(); super.initialize();
// Get the sync field as well // Get the sync field as well
@ -112,7 +129,7 @@ class NetworkFieldInjector extends PlayerInjector {
synchronized(syncObject) { synchronized(syncObject) {
// The list we'll be inserting // The list we'll be inserting
List<Packet> hackedList = new InjectedArrayList(manager.getClassLoader(), this, ignoredPackets); List<Packet> hackedList = new InjectedArrayList(classLoader, this, ignoredPackets);
// Add every previously stored packet // Add every previously stored packet
for (Packet packet : minecraftList) { for (Packet packet : minecraftList) {
@ -154,4 +171,9 @@ class NetworkFieldInjector extends PlayerInjector {
} }
overridenLists.clear(); overridenLists.clear();
} }
@Override
public boolean canInject() {
return true;
}
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -8,12 +8,14 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.Packets; 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;
/** /**
* Injection method that overrides the NetworkHandler itself, and it's sendPacket-method. * Injection method that overrides the NetworkHandler itself, and it's sendPacket-method.
@ -21,8 +23,17 @@ import com.comphenix.protocol.events.PacketListener;
* @author Kristian * @author Kristian
*/ */
class NetworkObjectInjector extends PlayerInjector { class NetworkObjectInjector extends PlayerInjector {
public NetworkObjectInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException { // Determine if we're listening
super(player, manager, sendingFilters); private Set<Integer> sendingFilters;
public NetworkObjectInjector(Logger logger, Player player, ListenerInvoker invoker, Set<Integer> sendingFilters) throws IllegalAccessException {
super(logger, player, invoker);
this.sendingFilters = sendingFilters;
}
@Override
protected boolean hasListener(int packetID) {
return sendingFilters.contains(packetID);
} }
@Override @Override
@ -107,4 +118,9 @@ class NetworkObjectInjector extends PlayerInjector {
// Clean up // Clean up
networkManagerRef.revertValue(); networkManagerRef.revertValue();
} }
@Override
public boolean canInject() {
return true;
}
} }

Datei anzeigen

@ -1,8 +1,9 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger;
import net.minecraft.server.Packet; import net.minecraft.server.Packet;
import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Callback;
@ -16,6 +17,7 @@ import net.sf.cglib.proxy.NoOp;
import org.bukkit.entity.Player; 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.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;
@ -32,14 +34,30 @@ public class NetworkServerInjector extends PlayerInjector {
private static Method sendPacketMethod; private static Method sendPacketMethod;
private InjectedServerConnection serverInjection; private InjectedServerConnection serverInjection;
public NetworkServerInjector(Player player, PacketFilterManager manager, // Determine if we're listening
Set<Integer> sendingFilters, InjectedServerConnection serverInjection) throws IllegalAccessException { private Set<Integer> sendingFilters;
super(player, manager, sendingFilters);
// Used to create proxy objects
private ClassLoader classLoader;
public NetworkServerInjector(
ClassLoader classLoader, Logger logger, Player player,
ListenerInvoker invoker, Set<Integer> sendingFilters,
InjectedServerConnection serverInjection) throws IllegalAccessException {
super(logger, player, invoker);
this.classLoader = classLoader;
this.sendingFilters = sendingFilters;
this.serverInjection = serverInjection; this.serverInjection = serverInjection;
} }
@Override @Override
protected void initialize() throws IllegalAccessException { protected boolean hasListener(int packetID) {
return sendingFilters.contains(packetID);
}
@Override
public void initialize() throws IllegalAccessException {
super.initialize(); super.initialize();
// Get the send packet method! // Get the send packet method!
@ -104,7 +122,7 @@ public class NetworkServerInjector extends PlayerInjector {
}; };
Callback noOpCallback = NoOp.INSTANCE; Callback noOpCallback = NoOp.INSTANCE;
ex.setClassLoader(manager.getClassLoader()); ex.setClassLoader(classLoader);
ex.setSuperclass(serverClass); ex.setSuperclass(serverClass);
ex.setCallbacks(new Callback[] { sendPacketCallback, noOpCallback }); ex.setCallbacks(new Callback[] { sendPacketCallback, noOpCallback });
ex.setCallbackFilter(new CallbackFilter() { ex.setCallbackFilter(new CallbackFilter() {
@ -165,4 +183,9 @@ public class NetworkServerInjector extends PlayerInjector {
public void checkListener(PacketListener listener) { public void checkListener(PacketListener listener) {
// We support everything // We support everything
} }
@Override
public boolean canInject() {
return true;
}
} }

Datei anzeigen

@ -0,0 +1,60 @@
package com.comphenix.protocol.injector.player;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
import net.minecraft.server.Packet;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker;
public class NetworkSpoutHook extends PlayerInjector {
public NetworkSpoutHook(Logger logger, Player player, ListenerInvoker invoker) throws IllegalAccessException {
super(logger, player, invoker);
}
@Override
protected boolean hasListener(int packetID) {
return false;
}
@Override
public boolean canInject() {
return getSpout() != null;
}
private Plugin getSpout() {
// Spout must be loaded
try {
return Bukkit.getServer().getPluginManager().getPlugin("Spout");
} catch (Throwable e) {
return null;
}
}
@Override
public void injectManager() {
}
@Override
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
}
@Override
public void cleanupAll() {
// TODO Auto-generated method stub
}
@Override
public void checkListener(PacketListener listener) {
// We support everything Spout does
}
}

Datei anzeigen

@ -0,0 +1,306 @@
package com.comphenix.protocol.injector.player;
import java.io.DataInputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.server.Packet;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PlayerLoggedOutException;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.google.common.collect.ImmutableSet;
public class PlayerInjectionHandler {
// Server connection injection
private InjectedServerConnection serverInjection;
// The last successful player hook
private PlayerInjector lastSuccessfulHook;
// Player injection
private Map<DataInputStream, Player> connectionLookup = new ConcurrentHashMap<DataInputStream, Player>();
private Map<Player, PlayerInjector> playerInjection = new HashMap<Player, PlayerInjector>();
// Player injection type
private PlayerInjectHooks playerHook = PlayerInjectHooks.NETWORK_SERVER_OBJECT;
// Error logger
private Logger logger;
// Whether or not we're closing
private boolean hasClosed;
// Used to invoke events
private ListenerInvoker invoker;
// Enabled packet filters
private Set<Integer> sendingFilters = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
// The class loader we're using
private ClassLoader classLoader;
public PlayerInjectionHandler(ClassLoader classLoader, Logger logger, ListenerInvoker invoker, Server server) {
this.classLoader = classLoader;
this.logger = logger;
this.invoker = invoker;
this.serverInjection = new InjectedServerConnection(logger, server);
}
/**
* Retrieves how the server packets are read.
* @return Injection method for reading server packets.
*/
public PlayerInjectHooks getPlayerHook() {
return playerHook;
}
/**
* Add an underlying packet handler of the given ID.
* @param packetID - packet ID to register.
*/
public void addPacketHandler(int packetID) {
sendingFilters.add(packetID);
}
/**
* Remove an underlying packet handler of ths ID.
* @param packetID - packet ID to unregister.
*/
public void removePacketHandler(int packetID) {
sendingFilters.remove(packetID);
}
/**
* Sets how the server packets are read.
* @param playerHook - the new injection method for reading server packets.
*/
public void setPlayerHook(PlayerInjectHooks playerHook) {
this.playerHook = playerHook;
}
/**
* Used to construct a player hook.
* @param player - the player to hook.
* @param hook - the hook type.
* @return A new player hoook
* @throws IllegalAccessException Unable to do our reflection magic.
*/
private PlayerInjector getHookInstance(Player player, PlayerInjectHooks hook) throws IllegalAccessException {
// Construct the correct player hook
switch (hook) {
case NETWORK_HANDLER_FIELDS:
return new NetworkFieldInjector(classLoader, logger, player, invoker, sendingFilters);
case NETWORK_MANAGER_OBJECT:
return new NetworkObjectInjector(logger, player, invoker, sendingFilters);
case NETWORK_SERVER_OBJECT:
return new NetworkServerInjector(classLoader, logger, player, invoker, sendingFilters, serverInjection);
default:
throw new IllegalArgumentException("Cannot construct a player injector.");
}
}
public Player getPlayerByConnection(DataInputStream inputStream) {
return connectionLookup.get(inputStream);
}
/**
* Initialize a player hook, allowing us to read server packets.
* @param manager - the main packet filter manager.
* @param player - player to hook.
*/
public void injectPlayer(Player player) {
PlayerInjector injector = null;
PlayerInjectHooks currentHook = playerHook;
boolean firstPlayer = lastSuccessfulHook == null;
// Don't inject if the class has closed
if (!hasClosed && player != null && !playerInjection.containsKey(player)) {
while (true) {
try {
injector = getHookInstance(player, currentHook);
injector.initialize();
injector.injectManager();
DataInputStream inputStream = injector.getInputStream(false);
if (!player.isOnline() || inputStream == null) {
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);
}
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;
}
}
}
// Update values
if (injector != null)
lastSuccessfulHook = injector;
if (currentHook != playerHook || firstPlayer)
setPlayerHook(currentHook);
}
}
/**
* Unregisters the given player.
* @param player - player to unregister.
*/
public void uninjectPlayer(Player player) {
if (!hasClosed && player != null) {
PlayerInjector injector = playerInjection.get(player);
if (injector != null) {
DataInputStream input = injector.getInputStream(true);
injector.cleanupAll();
playerInjection.remove(player);
connectionLookup.remove(input);
}
}
}
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException {
getInjector(reciever).sendServerPacket(packet.getHandle(), filters);
}
private PlayerInjector getInjector(Player player) {
if (!playerInjection.containsKey(player)) {
// What? Try to inject again.
injectPlayer(player);
}
PlayerInjector injector = playerInjection.get(player);
// Check that the injector was sucessfully added
if (injector != null)
return injector;
else
throw new IllegalArgumentException("Player has no injected handler.");
}
/**
* Determine if the given listeners are valid.
* @param listeners - listeners to check.
*/
public void checkListener(Set<PacketListener> listeners) {
// Make sure the current listeners are compatible
if (lastSuccessfulHook != null) {
for (PacketListener listener : listeners) {
try {
checkListener(listener);
} catch (IllegalStateException e) {
logger.log(Level.WARNING, "Unsupported listener.", e);
}
}
}
}
/**
* Determine if a listener is valid or not.
* @param listener - listener to check.
* @throws IllegalStateException If the given listener's whitelist cannot be fulfilled.
*/
public void checkListener(PacketListener listener) {
try {
if (lastSuccessfulHook != null)
lastSuccessfulHook.checkListener(listener);
} catch (Exception e) {
throw new IllegalStateException("Registering listener " + PacketAdapter.getPluginName(listener) + " failed", e);
}
}
/**
* Process a packet as if it were sent by the given player.
* @param player - the sender.
* @param mcPacket - the packet to process.
* @throws IllegalAccessException If the reflection machinery failed.
* @throws InvocationTargetException If the underlying method caused an error.
*/
public void processPacket(Player player, Packet mcPacket) throws IllegalAccessException, InvocationTargetException {
PlayerInjector injector = getInjector(player);
injector.processPacket(mcPacket);
}
/**
* Retrieve the current list of registered sending listeners.
* @return List of the sending listeners's packet IDs.
*/
public Set<Integer> getSendingFilters() {
return ImmutableSet.copyOf(sendingFilters);
}
/**
* Retrieve the current logger.
* @return Error logger.
*/
public Logger getLogger() {
return logger;
}
public void close() {
// Guard
if (hasClosed || playerInjection == null)
return;
// Remove everything
for (PlayerInjector injection : playerInjection.values()) {
if (injection != null) {
injection.cleanupAll();
}
}
// Remove server handler
serverInjection.cleanupAll();
hasClosed = true;
playerInjection.clear();
connectionLookup.clear();
invoker = null;
}
}

Datei anzeigen

@ -15,14 +15,14 @@
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.lang.reflect.Field; 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.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityPlayer;
import net.minecraft.server.Packet; import net.minecraft.server.Packet;
@ -34,6 +34,7 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.events.PacketContainer; 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.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;
@ -69,17 +70,18 @@ abstract class PlayerInjector {
protected Object netHandler; protected Object netHandler;
// The packet manager and filters // The packet manager and filters
protected PacketFilterManager manager; protected ListenerInvoker invoker;
protected Set<Integer> sendingFilters;
// Previous data input // Previous data input
protected DataInputStream cachedInput; protected DataInputStream cachedInput;
public PlayerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException { // Handle errors
protected Logger logger;
public PlayerInjector(Logger logger, Player player, ListenerInvoker invoker) throws IllegalAccessException {
this.logger = logger;
this.player = player; this.player = player;
this.manager = manager; this.invoker = invoker;
this.sendingFilters = sendingFilters;
initialize();
} }
/** /**
@ -91,7 +93,11 @@ abstract class PlayerInjector {
return craft.getHandle(); return craft.getHandle();
} }
protected void initialize() throws IllegalAccessException { /**
* Initialize all fields for this player injector, if it hasn't already.
* @throws IllegalAccessException An error has occured.
*/
public void initialize() throws IllegalAccessException {
EntityPlayer notchEntity = getEntityPlayer(); EntityPlayer notchEntity = getEntityPlayer();
@ -156,12 +162,12 @@ abstract class PlayerInjector {
return reflection.getFieldByType(".*NetServerHandler"); return reflection.getFieldByType(".*NetServerHandler");
} catch (RuntimeException e) { } catch (RuntimeException e) {
manager.getLogger().log(Level.WARNING, "Server handler is a proxy type.", e); logger.log(Level.WARNING, "Server handler is a proxy type.", e);
} }
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
manager.getLogger().warning("Unable to load server handler from proxy type."); logger.warning("Unable to load server handler from proxy type.");
} }
// Nope, just go with it // Nope, just go with it
@ -250,6 +256,12 @@ abstract class PlayerInjector {
*/ */
public abstract void cleanupAll(); public abstract void cleanupAll();
/**
* 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();
/** /**
* Invoked before a new listener is registered. * Invoked before a new listener is registered.
* <p> * <p>
@ -263,16 +275,16 @@ abstract class PlayerInjector {
* @param packet - packet to recieve. * @param packet - packet to recieve.
* @return The given packet, or the packet replaced by the listeners. * @return The given packet, or the packet replaced by the listeners.
*/ */
Packet handlePacketRecieved(Packet packet) { public Packet handlePacketRecieved(Packet packet) {
// Get the packet ID too // Get the packet ID too
Integer id = MinecraftRegistry.getPacketToID().get(packet.getClass()); Integer id = invoker.getPacketID(packet);
// Make sure we're listening // Make sure we're listening
if (id != null && sendingFilters.contains(id)) { if (id != null && hasListener(id)) {
// A packet has been sent guys! // A packet has been sent guys!
PacketContainer container = new PacketContainer(id, packet); PacketContainer container = new PacketContainer(id, packet);
PacketEvent event = PacketEvent.fromServer(manager, container, player); PacketEvent event = PacketEvent.fromServer(invoker, container, player);
manager.invokePacketSending(event); invoker.invokePacketSending(event);
// Cancelling is pretty simple. Just ignore the packet. // Cancelling is pretty simple. Just ignore the packet.
if (event.isCancelled()) if (event.isCancelled())
@ -285,6 +297,13 @@ abstract class PlayerInjector {
return packet; return packet;
} }
/**
* Determine if the given injector is listening for this packet ID.
* @param packetID - packet ID to check.
* @return TRUE if it is, FALSE oterhwise.
*/
protected abstract boolean hasListener(int packetID);
/** /**
* Retrieve the current player's input stream. * Retrieve the current player's input stream.
* @param cache - whether or not to cache the result of this method. * @param cache - whether or not to cache the result of this method.

Datei anzeigen

@ -1,4 +1,4 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector.player;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;