mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-30 14:43:27 +01:00
Adding "support" for Spout by proxying it's NetServerHandler.
While it may seem better to use a Spout PacketListener, we can't prevent other spout listeners from stopping the listener chain. For instance, Orebfuscator does supports Spout, but does this by cancelling every chunk packet and sending them to be processed and sent by Orebfuscator only. This can never be made compatible with other plugins. So, we choose to add some overhead and inject our proxy onto Spout. Fortunately, Spout injects the proxy using a player listener on LOWEST, so we get to override Spout again with our HIGHEST. The proxy method should be generic enough to handle most proxy types.
This commit is contained in:
parent
af3e278e06
commit
18ef06ea21
@ -10,6 +10,5 @@
|
|||||||
</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>
|
||||||
|
@ -441,17 +441,17 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
try {
|
try {
|
||||||
manager.registerEvents(new Listener() {
|
manager.registerEvents(new Listener() {
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
playerInjection.injectPlayer(event.getPlayer());
|
playerInjection.injectPlayer(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
playerInjection.uninjectPlayer(event.getPlayer());
|
playerInjection.uninjectPlayer(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onPluginDisabled(PluginDisableEvent event) {
|
public void onPluginDisabled(PluginDisableEvent event) {
|
||||||
// Clean up in case the plugin forgets
|
// Clean up in case the plugin forgets
|
||||||
if (event.getPlugin() != plugin) {
|
if (event.getPlugin() != plugin) {
|
||||||
@ -487,7 +487,7 @@ 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, "Normal");
|
Object priorityNormal = Enum.valueOf(eventPriority, "Highest");
|
||||||
|
|
||||||
// Get event types
|
// Get event types
|
||||||
Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN");
|
Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN");
|
||||||
|
@ -136,8 +136,17 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Use the existing field values when we create our copy
|
// Use the existing field values when we create our copy
|
||||||
DefaultInstances serverInstances = DefaultInstances.fromArray(
|
DefaultInstances serverInstances = null;
|
||||||
|
|
||||||
|
if (hasProxyServerHandler()) {
|
||||||
|
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
||||||
|
serverInstances = DefaultInstances.fromArray(
|
||||||
|
ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass));
|
||||||
|
} else {
|
||||||
|
serverInstances = DefaultInstances.fromArray(
|
||||||
ExistingGenerator.fromObjectFields(serverHandler));
|
ExistingGenerator.fromObjectFields(serverHandler));
|
||||||
|
}
|
||||||
|
|
||||||
serverInstances.setNonNull(true);
|
serverInstances.setNonNull(true);
|
||||||
serverInstances.setMaximumRecursion(1);
|
serverInstances.setMaximumRecursion(1);
|
||||||
|
|
||||||
@ -155,6 +164,15 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
||||||
|
if (clazz.getName().startsWith("net.minecraft"))
|
||||||
|
return clazz;
|
||||||
|
else if (clazz.equals(Object.class))
|
||||||
|
return clazz;
|
||||||
|
else
|
||||||
|
return clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanupAll() {
|
public void cleanupAll() {
|
||||||
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,6 +23,11 @@ import com.comphenix.protocol.injector.PlayerLoggedOutException;
|
|||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for injecting into a player's sendPacket method.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
public class PlayerInjectionHandler {
|
public class PlayerInjectionHandler {
|
||||||
|
|
||||||
// Server connection injection
|
// Server connection injection
|
||||||
|
@ -50,6 +50,9 @@ abstract class PlayerInjector {
|
|||||||
protected static Field inputField;
|
protected static Field inputField;
|
||||||
protected static Field netHandlerField;
|
protected static Field netHandlerField;
|
||||||
|
|
||||||
|
// Whether or not we're using a proxy type
|
||||||
|
private static boolean hasProxyType;
|
||||||
|
|
||||||
// To add our injected array lists
|
// To add our injected array lists
|
||||||
protected static StructureModifier<Object> networkModifier;
|
protected static StructureModifier<Object> networkModifier;
|
||||||
|
|
||||||
@ -142,6 +145,14 @@ abstract class PlayerInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve whether or not the server handler is a proxy object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
protected boolean hasProxyServerHandler() {
|
||||||
|
return hasProxyType;
|
||||||
|
}
|
||||||
|
|
||||||
private Field getProxyField(EntityPlayer notchEntity, Field serverField) {
|
private Field getProxyField(EntityPlayer notchEntity, Field serverField) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -154,6 +165,8 @@ abstract class PlayerInjector {
|
|||||||
if (handler instanceof Factory)
|
if (handler instanceof Factory)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
hasProxyType = true;
|
||||||
|
|
||||||
// No? Is it a Proxy type?
|
// No? Is it a Proxy type?
|
||||||
try {
|
try {
|
||||||
FuzzyReflection reflection = FuzzyReflection.fromObject(handler, true);
|
FuzzyReflection reflection = FuzzyReflection.fromObject(handler, true);
|
||||||
@ -162,7 +175,7 @@ abstract class PlayerInjector {
|
|||||||
return reflection.getFieldByType(".*NetServerHandler");
|
return reflection.getFieldByType(".*NetServerHandler");
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
logger.log(Level.WARNING, "Server handler is a proxy type.", e);
|
logger.log(Level.WARNING, "Detected server handler proxy type by another plugin. Conflict may occur!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,14 @@ public class ObjectCloner {
|
|||||||
// System.out.println(String.format("Writing value %s to %s",
|
// System.out.println(String.format("Writing value %s to %s",
|
||||||
// value, modifier.getFields().get(i).getName()));
|
// value, modifier.getFields().get(i).getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy private fields underneath
|
||||||
|
Class<?> superclass = commonType.getSuperclass();
|
||||||
|
|
||||||
|
if (!superclass.equals(Object.class)) {
|
||||||
|
copyTo(source, destination, superclass);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (FieldAccessException e) {
|
} catch (FieldAccessException e) {
|
||||||
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
|
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
|
||||||
}
|
}
|
||||||
|
@ -235,16 +235,16 @@ public class DefaultInstances {
|
|||||||
params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1);
|
params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1);
|
||||||
|
|
||||||
// Did we break the non-null contract?
|
// Did we break the non-null contract?
|
||||||
if (params[i] == null && nonNull)
|
if (params[i] == null && nonNull) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return createInstance(type, minimum, types, params);
|
return createInstance(type, minimum, types, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Nope, we couldn't create this type
|
// Nope, we couldn't create this type
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No suitable default value could be found
|
// No suitable default value could be found
|
||||||
|
@ -33,10 +33,34 @@ public class ExistingGenerator implements InstanceProvider {
|
|||||||
* @return The instance generator.
|
* @return The instance generator.
|
||||||
*/
|
*/
|
||||||
public static ExistingGenerator fromObjectFields(Object object) {
|
public static ExistingGenerator fromObjectFields(Object object) {
|
||||||
|
if (object == null)
|
||||||
|
throw new IllegalArgumentException("Object cannot be NULL.");
|
||||||
|
|
||||||
|
return fromObjectFields(object, object.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically create an instance provider from a objects public and private fields.
|
||||||
|
* <p>
|
||||||
|
* If two or more fields share the same type, the last declared non-null field will take
|
||||||
|
* precedent.
|
||||||
|
* @param object - object to create an instance generator from.
|
||||||
|
* @param type - the type to cast the object.
|
||||||
|
* @return The instance generator.
|
||||||
|
*/
|
||||||
|
public static ExistingGenerator fromObjectFields(Object object, Class<?> type) {
|
||||||
ExistingGenerator generator = new ExistingGenerator();
|
ExistingGenerator generator = new ExistingGenerator();
|
||||||
|
|
||||||
|
// Possible errors
|
||||||
|
if (object == null)
|
||||||
|
throw new IllegalArgumentException("Object cannot be NULL.");
|
||||||
|
if (type == null)
|
||||||
|
throw new IllegalArgumentException("Type cannot be NULL.");
|
||||||
|
if (!type.isAssignableFrom(object.getClass()))
|
||||||
|
throw new IllegalArgumentException("Type must be a superclass or be the same type.");
|
||||||
|
|
||||||
// Read instances from every field.
|
// Read instances from every field.
|
||||||
for (Field field : FuzzyReflection.fromObject(object, true).getFields()) {
|
for (Field field : FuzzyReflection.fromClass(type, true).getFields()) {
|
||||||
try {
|
try {
|
||||||
Object value = FieldUtils.readField(field, object, true);
|
Object value = FieldUtils.readField(field, object, true);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user