Minimize the number of unnecessary references.
Dieser Commit ist enthalten in:
Ursprung
e7954a0f79
Commit
8f2935e241
@ -285,43 +285,11 @@ public class PacketContainer implements Serializable {
|
|||||||
* internal Minecraft ItemStack.
|
* internal Minecraft ItemStack.
|
||||||
* @return A modifier for ItemStack array fields.
|
* @return A modifier for ItemStack array fields.
|
||||||
*/
|
*/
|
||||||
public StructureModifier<ItemStack[]> getItemArrayModifier() {
|
public StructureModifier<ItemStack[]> getItemArrayModifier() {
|
||||||
|
|
||||||
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
|
|
||||||
|
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<ItemStack[]>withType(
|
return structureModifier.<ItemStack[]>withType(
|
||||||
MinecraftReflection.getItemStackArrayClass(),
|
MinecraftReflection.getItemStackArrayClass(),
|
||||||
BukkitConverters.getIgnoreNull(new EquivalentConverter<ItemStack[]>() {
|
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
|
||||||
|
|
||||||
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
|
|
||||||
Class<?> nmsStack = MinecraftReflection.getItemStackClass();
|
|
||||||
Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
|
|
||||||
|
|
||||||
// Unwrap every item
|
|
||||||
for (int i = 0; i < result.length; i++) {
|
|
||||||
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack[] getSpecific(Object generic) {
|
|
||||||
Object[] input = (Object[]) generic;
|
|
||||||
ItemStack[] result = new ItemStack[input.length];
|
|
||||||
|
|
||||||
// Add the wrapper
|
|
||||||
for (int i = 0; i < result.length; i++) {
|
|
||||||
result[i] = stackConverter.getSpecific(input[i]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<ItemStack[]> getSpecificType() {
|
|
||||||
return ItemStack[].class;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -556,4 +524,40 @@ public class PacketContainer implements Serializable {
|
|||||||
|
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an equivalent converter for ItemStack arrays.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
private static class ItemStackArrayConverter implements EquivalentConverter<ItemStack[]> {
|
||||||
|
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
|
||||||
|
|
||||||
|
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
|
||||||
|
Class<?> nmsStack = MinecraftReflection.getItemStackClass();
|
||||||
|
Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
|
||||||
|
|
||||||
|
// Unwrap every item
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack[] getSpecific(Object generic) {
|
||||||
|
Object[] input = (Object[]) generic;
|
||||||
|
ItemStack[] result = new ItemStack[input.length];
|
||||||
|
|
||||||
|
// Add the wrapper
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = stackConverter.getSpecific(input[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ItemStack[]> getSpecificType() {
|
||||||
|
return ItemStack[].class;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,352 +1,358 @@
|
|||||||
/*
|
/*
|
||||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
* Copyright (C) 2012 Kristian S. Stangeland
|
* Copyright (C) 2012 Kristian S. Stangeland
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||||
* the License, or (at your option) any later version.
|
* the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* See the GNU General Public License for more details.
|
* See the GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this program;
|
* You should have received a copy of the GNU General Public License along with this program;
|
||||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
* 02111-1307 USA
|
* 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.comphenix.protocol.injector.player;
|
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;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import net.sf.cglib.proxy.*;
|
import net.sf.cglib.proxy.*;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
import com.comphenix.protocol.error.Report;
|
import com.comphenix.protocol.error.Report;
|
||||||
import com.comphenix.protocol.error.ReportType;
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
import com.comphenix.protocol.injector.GamePhase;
|
import com.comphenix.protocol.injector.GamePhase;
|
||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
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.ObjectWriter;
|
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
||||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a player hook into the NetServerHandler class.
|
* Represents a player hook into the NetServerHandler class.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class NetworkServerInjector extends PlayerInjector {
|
class NetworkServerInjector extends PlayerInjector {
|
||||||
// Disconnected field
|
// Disconnected field
|
||||||
public static final ReportType REPORT_ASSUMING_DISCONNECT_FIELD = new ReportType("Unable to find 'disconnected' field. Assuming %s.");
|
public static final ReportType REPORT_ASSUMING_DISCONNECT_FIELD = new ReportType("Unable to find 'disconnected' field. Assuming %s.");
|
||||||
public static final ReportType REPORT_DISCONNECT_FIELD_MISSING = new ReportType("Cannot find disconnected field. Is ProtocolLib up to date?");
|
public static final ReportType REPORT_DISCONNECT_FIELD_MISSING = new ReportType("Cannot find disconnected field. Is ProtocolLib up to date?");
|
||||||
public static final ReportType REPORT_DISCONNECT_FIELD_FAILURE = new ReportType("Unable to update disconnected field. Player quit event may be sent twice.");
|
public static final ReportType REPORT_DISCONNECT_FIELD_FAILURE = new ReportType("Unable to update disconnected field. Player quit event may be sent twice.");
|
||||||
|
|
||||||
private volatile static CallbackFilter callbackFilter;
|
private volatile static CallbackFilter callbackFilter;
|
||||||
private volatile static boolean foundSendPacket;
|
private volatile static boolean foundSendPacket;
|
||||||
|
|
||||||
private volatile static Field disconnectField;
|
private volatile static Field disconnectField;
|
||||||
private InjectedServerConnection serverInjection;
|
private InjectedServerConnection serverInjection;
|
||||||
|
|
||||||
// Determine if we're listening
|
// Determine if we're listening
|
||||||
private IntegerSet sendingFilters;
|
private IntegerSet sendingFilters;
|
||||||
|
|
||||||
// Used to create proxy objects
|
// Used to create proxy objects
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
// Whether or not the player has disconnected
|
// Whether or not the player has disconnected
|
||||||
private boolean hasDisconnected;
|
private boolean hasDisconnected;
|
||||||
|
|
||||||
// Used to copy fields
|
// Used to copy fields
|
||||||
private final ObjectWriter writer = new ObjectWriter();
|
private final ObjectWriter writer = new ObjectWriter();
|
||||||
|
|
||||||
public NetworkServerInjector(
|
public NetworkServerInjector(
|
||||||
ClassLoader classLoader, ErrorReporter reporter, Player player,
|
ClassLoader classLoader, ErrorReporter reporter, Player player,
|
||||||
ListenerInvoker invoker, IntegerSet sendingFilters,
|
ListenerInvoker invoker, IntegerSet sendingFilters,
|
||||||
InjectedServerConnection serverInjection) throws IllegalAccessException {
|
InjectedServerConnection serverInjection) throws IllegalAccessException {
|
||||||
|
|
||||||
super(reporter, player, invoker);
|
super(reporter, player, invoker);
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.sendingFilters = sendingFilters;
|
this.sendingFilters = sendingFilters;
|
||||||
this.serverInjection = serverInjection;
|
this.serverInjection = serverInjection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasListener(int packetID) {
|
protected boolean hasListener(int packetID) {
|
||||||
return sendingFilters.contains(packetID);
|
return sendingFilters.contains(packetID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||||
Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
||||||
|
|
||||||
if (serverDelegate != null) {
|
if (serverDelegate != null) {
|
||||||
try {
|
try {
|
||||||
// Note that invocation target exception is a wrapper for a checked exception
|
// Note that invocation target exception is a wrapper for a checked exception
|
||||||
MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet);
|
MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IllegalStateException("Unable to access send packet method.", e);
|
throw new IllegalStateException("Unable to access send packet method.", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unable to load server handler. Cannot send packet.");
|
throw new IllegalStateException("Unable to load server handler. Cannot send packet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectManager() {
|
public void injectManager() {
|
||||||
|
|
||||||
if (serverHandlerRef == null)
|
if (serverHandlerRef == null)
|
||||||
throw new IllegalStateException("Cannot find server handler.");
|
throw new IllegalStateException("Cannot find server handler.");
|
||||||
// Don't inject twice
|
// Don't inject twice
|
||||||
if (serverHandlerRef.getValue() instanceof Factory)
|
if (serverHandlerRef.getValue() instanceof Factory)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!tryInjectManager()) {
|
if (!tryInjectManager()) {
|
||||||
Class<?> serverHandlerClass = MinecraftReflection.getNetServerHandlerClass();
|
Class<?> serverHandlerClass = MinecraftReflection.getNetServerHandlerClass();
|
||||||
|
|
||||||
// Try to override the proxied object
|
// Try to override the proxied object
|
||||||
if (proxyServerField != null) {
|
if (proxyServerField != null) {
|
||||||
serverHandlerRef = new VolatileField(proxyServerField, serverHandler, true);
|
serverHandlerRef = new VolatileField(proxyServerField, serverHandler, true);
|
||||||
serverHandler = serverHandlerRef.getValue();
|
serverHandler = serverHandlerRef.getValue();
|
||||||
|
|
||||||
if (serverHandler == null)
|
if (serverHandler == null)
|
||||||
throw new RuntimeException("Cannot hook player: Inner proxy object is NULL.");
|
throw new RuntimeException("Cannot hook player: Inner proxy object is NULL.");
|
||||||
else
|
else
|
||||||
serverHandlerClass = serverHandler.getClass();
|
serverHandlerClass = serverHandler.getClass();
|
||||||
|
|
||||||
// Try again
|
// Try again
|
||||||
if (tryInjectManager()) {
|
if (tryInjectManager()) {
|
||||||
// It worked - probably
|
// It worked - probably
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Cannot hook player: Unable to find a valid constructor for the "
|
"Cannot hook player: Unable to find a valid constructor for the "
|
||||||
+ serverHandlerClass.getName() + " object.");
|
+ serverHandlerClass.getName() + " object.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryInjectManager() {
|
private boolean tryInjectManager() {
|
||||||
Class<?> serverClass = serverHandler.getClass();
|
Class<?> serverClass = serverHandler.getClass();
|
||||||
|
|
||||||
Enhancer ex = new Enhancer();
|
Enhancer ex = new Enhancer();
|
||||||
Callback sendPacketCallback = new MethodInterceptor() {
|
Callback sendPacketCallback = new MethodInterceptor() {
|
||||||
@Override
|
@Override
|
||||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||||
Object packet = args[0];
|
Object packet = args[0];
|
||||||
|
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
packet = handlePacketSending(packet);
|
packet = handlePacketSending(packet);
|
||||||
|
|
||||||
// A NULL packet indicate cancelling
|
// A NULL packet indicate cancelling
|
||||||
if (packet != null)
|
if (packet != null)
|
||||||
args[0] = packet;
|
args[0] = packet;
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the method directly
|
// Call the method directly
|
||||||
return proxy.invokeSuper(obj, args);
|
return proxy.invokeSuper(obj, args);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Callback noOpCallback = NoOp.INSTANCE;
|
Callback noOpCallback = NoOp.INSTANCE;
|
||||||
|
|
||||||
// Share callback filter - that way, we avoid generating a new class for
|
// Share callback filter - that way, we avoid generating a new class for
|
||||||
// every logged in player.
|
// every logged in player.
|
||||||
if (callbackFilter == null) {
|
if (callbackFilter == null) {
|
||||||
final Method sendPacket = MinecraftMethods.getSendPacketMethod();
|
callbackFilter = new SendMethodFilter();
|
||||||
|
}
|
||||||
callbackFilter = new CallbackFilter() {
|
|
||||||
@Override
|
ex.setClassLoader(classLoader);
|
||||||
public int accept(Method method) {
|
ex.setSuperclass(serverClass);
|
||||||
if (isCallableEqual(sendPacket, method)) {
|
ex.setCallbacks(new Callback[] { sendPacketCallback, noOpCallback });
|
||||||
foundSendPacket = true;
|
ex.setCallbackFilter(callbackFilter);
|
||||||
return 0;
|
|
||||||
} else {
|
// Find the Minecraft NetServerHandler superclass
|
||||||
return 1;
|
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
||||||
}
|
ExistingGenerator generator = ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass);
|
||||||
}
|
DefaultInstances serverInstances = null;
|
||||||
};
|
|
||||||
}
|
// Maybe the proxy instance can help?
|
||||||
|
Object proxyInstance = getProxyServerHandler();
|
||||||
ex.setClassLoader(classLoader);
|
|
||||||
ex.setSuperclass(serverClass);
|
// Use the existing server proxy when we create one
|
||||||
ex.setCallbacks(new Callback[] { sendPacketCallback, noOpCallback });
|
if (proxyInstance != null && proxyInstance != serverHandler) {
|
||||||
ex.setCallbackFilter(callbackFilter);
|
serverInstances = DefaultInstances.fromArray(generator,
|
||||||
|
ExistingGenerator.fromObjectArray(new Object[] { proxyInstance }));
|
||||||
// Find the Minecraft NetServerHandler superclass
|
} else {
|
||||||
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
serverInstances = DefaultInstances.fromArray(generator);
|
||||||
ExistingGenerator generator = ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass);
|
}
|
||||||
DefaultInstances serverInstances = null;
|
|
||||||
|
serverInstances.setNonNull(true);
|
||||||
// Maybe the proxy instance can help?
|
serverInstances.setMaximumRecursion(1);
|
||||||
Object proxyInstance = getProxyServerHandler();
|
|
||||||
|
Object proxyObject = serverInstances.forEnhancer(ex).getDefault(serverClass);
|
||||||
// Use the existing server proxy when we create one
|
|
||||||
if (proxyInstance != null && proxyInstance != serverHandler) {
|
// Inject it now
|
||||||
serverInstances = DefaultInstances.fromArray(generator,
|
if (proxyObject != null) {
|
||||||
ExistingGenerator.fromObjectArray(new Object[] { proxyInstance }));
|
// Did we override a sendPacket method?
|
||||||
} else {
|
if (!foundSendPacket) {
|
||||||
serverInstances = DefaultInstances.fromArray(generator);
|
throw new IllegalArgumentException("Unable to find a sendPacket method in " + serverClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstances.setNonNull(true);
|
serverInjection.replaceServerHandler(serverHandler, proxyObject);
|
||||||
serverInstances.setMaximumRecursion(1);
|
serverHandlerRef.setValue(proxyObject);
|
||||||
|
return true;
|
||||||
Object proxyObject = serverInstances.forEnhancer(ex).getDefault(serverClass);
|
} else {
|
||||||
|
return false;
|
||||||
// Inject it now
|
}
|
||||||
if (proxyObject != null) {
|
}
|
||||||
// Did we override a sendPacket method?
|
|
||||||
if (!foundSendPacket) {
|
private Object getProxyServerHandler() {
|
||||||
throw new IllegalArgumentException("Unable to find a sendPacket method in " + serverClass);
|
if (proxyServerField != null && !proxyServerField.equals(serverHandlerRef.getField())) {
|
||||||
}
|
try {
|
||||||
|
return FieldUtils.readField(proxyServerField, serverHandler, true);
|
||||||
serverInjection.replaceServerHandler(serverHandler, proxyObject);
|
} catch (Throwable e) {
|
||||||
serverHandlerRef.setValue(proxyObject);
|
// Oh well
|
||||||
return true;
|
}
|
||||||
} else {
|
}
|
||||||
return false;
|
|
||||||
}
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
||||||
* Determine if the two methods are equal in terms of call semantics.
|
if (MinecraftReflection.isMinecraftClass(clazz))
|
||||||
* <p>
|
return clazz;
|
||||||
* Two methods are equal if they have the same name, parameter types and return type.
|
else if (clazz.equals(Object.class))
|
||||||
* @param first - first method.
|
return clazz;
|
||||||
* @param second - second method.
|
else
|
||||||
* @return TRUE if they are, FALSE otherwise.
|
return getFirstMinecraftSuperClass(clazz.getSuperclass());
|
||||||
*/
|
}
|
||||||
private boolean isCallableEqual(Method first, Method second) {
|
|
||||||
return first.getName().equals(second.getName()) &&
|
@Override
|
||||||
first.getReturnType().equals(second.getReturnType()) &&
|
protected void cleanHook() {
|
||||||
Arrays.equals(first.getParameterTypes(), second.getParameterTypes());
|
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
||||||
}
|
writer.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
|
||||||
|
serverHandlerRef.revertValue();
|
||||||
private Object getProxyServerHandler() {
|
|
||||||
if (proxyServerField != null && !proxyServerField.equals(serverHandlerRef.getField())) {
|
try {
|
||||||
try {
|
if (getNetHandler() != null) {
|
||||||
return FieldUtils.readField(proxyServerField, serverHandler, true);
|
// Restore packet listener
|
||||||
} catch (Throwable e) {
|
try {
|
||||||
// Oh well
|
FieldUtils.writeField(netHandlerField, networkManager, serverHandlerRef.getOldValue(), true);
|
||||||
}
|
} catch (IllegalAccessException e) {
|
||||||
}
|
// Oh well
|
||||||
|
e.printStackTrace();
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
e.printStackTrace();
|
||||||
if (MinecraftReflection.isMinecraftClass(clazz))
|
}
|
||||||
return clazz;
|
|
||||||
else if (clazz.equals(Object.class))
|
// Prevent the PlayerQuitEvent from being sent twice
|
||||||
return clazz;
|
if (hasDisconnected) {
|
||||||
else
|
setDisconnect(serverHandlerRef.getValue(), true);
|
||||||
return getFirstMinecraftSuperClass(clazz.getSuperclass());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
serverInjection.revertServerHandler(serverHandler);
|
||||||
protected void cleanHook() {
|
}
|
||||||
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
|
||||||
writer.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
|
@Override
|
||||||
serverHandlerRef.revertValue();
|
public void handleDisconnect() {
|
||||||
|
hasDisconnected = true;
|
||||||
try {
|
}
|
||||||
if (getNetHandler() != null) {
|
|
||||||
// Restore packet listener
|
/**
|
||||||
try {
|
* Set the disconnected field in a NetServerHandler.
|
||||||
FieldUtils.writeField(netHandlerField, networkManager, serverHandlerRef.getOldValue(), true);
|
* @param handler - the NetServerHandler.
|
||||||
} catch (IllegalAccessException e) {
|
* @param value - the new value.
|
||||||
// Oh well
|
*/
|
||||||
e.printStackTrace();
|
private void setDisconnect(Object handler, boolean value) {
|
||||||
}
|
// Set it
|
||||||
}
|
try {
|
||||||
} catch (IllegalAccessException e) {
|
// Load the field
|
||||||
e.printStackTrace();
|
if (disconnectField == null) {
|
||||||
}
|
disconnectField = FuzzyReflection.fromObject(handler).getFieldByName("disconnected.*");
|
||||||
|
}
|
||||||
// Prevent the PlayerQuitEvent from being sent twice
|
FieldUtils.writeField(disconnectField, handler, value);
|
||||||
if (hasDisconnected) {
|
|
||||||
setDisconnect(serverHandlerRef.getValue(), true);
|
} catch (IllegalArgumentException e) {
|
||||||
}
|
// Assume it's the first ...
|
||||||
}
|
if (disconnectField == null) {
|
||||||
|
disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class);
|
||||||
serverInjection.revertServerHandler(serverHandler);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUMING_DISCONNECT_FIELD).messageParam(disconnectField));
|
||||||
}
|
|
||||||
|
// Try again
|
||||||
@Override
|
if (disconnectField != null) {
|
||||||
public void handleDisconnect() {
|
setDisconnect(handler, value);
|
||||||
hasDisconnected = true;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Set the disconnected field in a NetServerHandler.
|
// This is really bad
|
||||||
* @param handler - the NetServerHandler.
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_MISSING).error(e));
|
||||||
* @param value - the new value.
|
|
||||||
*/
|
} catch (IllegalAccessException e) {
|
||||||
private void setDisconnect(Object handler, boolean value) {
|
reporter.reportWarning(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_FAILURE).error(e));
|
||||||
// Set it
|
}
|
||||||
try {
|
}
|
||||||
// Load the field
|
|
||||||
if (disconnectField == null) {
|
@Override
|
||||||
disconnectField = FuzzyReflection.fromObject(handler).getFieldByName("disconnected.*");
|
public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) {
|
||||||
}
|
// We support everything
|
||||||
FieldUtils.writeField(disconnectField, handler, value);
|
return null;
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// Assume it's the first ...
|
@Override
|
||||||
if (disconnectField == null) {
|
public boolean canInject(GamePhase phase) {
|
||||||
disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class);
|
// Doesn't work when logging in
|
||||||
reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUMING_DISCONNECT_FIELD).messageParam(disconnectField));
|
return phase == GamePhase.PLAYING;
|
||||||
|
}
|
||||||
// Try again
|
|
||||||
if (disconnectField != null) {
|
@Override
|
||||||
setDisconnect(handler, value);
|
public PlayerInjectHooks getHookType() {
|
||||||
return;
|
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
// This is really bad
|
* Represents a CallbackFilter that only matches the SendPacket method.
|
||||||
reporter.reportDetailed(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_MISSING).error(e));
|
* @author Kristian
|
||||||
|
*/
|
||||||
} catch (IllegalAccessException e) {
|
private static class SendMethodFilter implements CallbackFilter {
|
||||||
reporter.reportWarning(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_FAILURE).error(e));
|
private Method sendPacket = MinecraftMethods.getSendPacketMethod();
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
public int accept(Method method) {
|
||||||
@Override
|
if (isCallableEqual(sendPacket, method)) {
|
||||||
public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) {
|
NetworkServerInjector.foundSendPacket = true;
|
||||||
// We support everything
|
return 0;
|
||||||
return null;
|
} else {
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public boolean canInject(GamePhase phase) {
|
|
||||||
// Doesn't work when logging in
|
/**
|
||||||
return phase == GamePhase.PLAYING;
|
* Determine if the two methods are equal in terms of call semantics.
|
||||||
}
|
* <p>
|
||||||
|
* Two methods are equal if they have the same name, parameter types and return type.
|
||||||
@Override
|
* @param first - first method.
|
||||||
public PlayerInjectHooks getHookType() {
|
* @param second - second method.
|
||||||
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
|
* @return TRUE if they are, FALSE otherwise.
|
||||||
}
|
*/
|
||||||
}
|
private boolean isCallableEqual(Method first, Method second) {
|
||||||
|
return first.getName().equals(second.getName()) &&
|
||||||
|
first.getReturnType().equals(second.getReturnType()) &&
|
||||||
|
Arrays.equals(first.getParameterTypes(), second.getParameterTypes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package com.comphenix.protocol.injector.player;
|
package com.comphenix.protocol.injector.player;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
@ -81,7 +82,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
private NetLoginInjector netLoginInjector;
|
private NetLoginInjector netLoginInjector;
|
||||||
|
|
||||||
// The last successful player hook
|
// The last successful player hook
|
||||||
private PlayerInjector lastSuccessfulHook;
|
private WeakReference<PlayerInjector> lastSuccessfulHook;
|
||||||
|
|
||||||
// Dummy injection
|
// Dummy injection
|
||||||
private Cache<Player, PlayerInjector> dummyInjectors =
|
private Cache<Player, PlayerInjector> dummyInjectors =
|
||||||
@ -399,7 +400,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
|
|
||||||
// Update values
|
// Update values
|
||||||
if (injector != null)
|
if (injector != null)
|
||||||
lastSuccessfulHook = injector;
|
lastSuccessfulHook = new WeakReference<PlayerInjector>(injector);
|
||||||
if (permanentHook != getPlayerHook(phase))
|
if (permanentHook != getPlayerHook(phase))
|
||||||
setPlayerHook(phase, tempHook);
|
setPlayerHook(phase, tempHook);
|
||||||
|
|
||||||
@ -649,13 +650,23 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void checkListener(Set<PacketListener> listeners) {
|
public void checkListener(Set<PacketListener> listeners) {
|
||||||
// Make sure the current listeners are compatible
|
// Make sure the current listeners are compatible
|
||||||
if (lastSuccessfulHook != null) {
|
if (getLastSuccessfulHook() != null) {
|
||||||
for (PacketListener listener : listeners) {
|
for (PacketListener listener : listeners) {
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the last successful hook.
|
||||||
|
* <p>
|
||||||
|
* May be NULL if the hook has been uninjected.
|
||||||
|
* @return Last successful hook.
|
||||||
|
*/
|
||||||
|
private PlayerInjector getLastSuccessfulHook() {
|
||||||
|
return lastSuccessfulHook != null ? lastSuccessfulHook.get() : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a listener is valid or not.
|
* Determine if a listener is valid or not.
|
||||||
* <p>
|
* <p>
|
||||||
@ -664,8 +675,10 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void checkListener(PacketListener listener) {
|
public void checkListener(PacketListener listener) {
|
||||||
if (lastSuccessfulHook != null) {
|
PlayerInjector last = getLastSuccessfulHook();
|
||||||
UnsupportedListener result = lastSuccessfulHook.checkListener(version, listener);
|
|
||||||
|
if (last != null) {
|
||||||
|
UnsupportedListener result = last.checkListener(version, listener);
|
||||||
|
|
||||||
// We won't prevent the listener, as it may still have valid packets
|
// We won't prevent the listener, as it may still have valid packets
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren