Make the proxy creation even more flexible.
Now we even support Orebfuscator without using Spout.
Dieser Commit ist enthalten in:
Ursprung
18ef06ea21
Commit
0e76d8ea2b
@ -21,6 +21,7 @@ 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;
|
||||||
|
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;
|
||||||
|
|
||||||
@ -97,6 +98,29 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
if (serverHandlerRef.getValue() instanceof Factory)
|
if (serverHandlerRef.getValue() instanceof Factory)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!tryInjectManager()) {
|
||||||
|
|
||||||
|
// Try to override the proxied object
|
||||||
|
if (proxyServerField != null) {
|
||||||
|
serverHandlerRef = new VolatileField(proxyServerField, serverHandler, true);
|
||||||
|
serverHandler = serverHandlerRef.getValue();
|
||||||
|
|
||||||
|
if (serverHandler == null)
|
||||||
|
throw new RuntimeException("Cannot hook player: Inner proxy object is NULL.");
|
||||||
|
|
||||||
|
// Try again
|
||||||
|
if (tryInjectManager()) {
|
||||||
|
// It worked - probably
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Cannot hook player: Unable to find a valid constructor for the NetServerHandler object.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryInjectManager() {
|
||||||
Class<?> serverClass = serverHandler.getClass();
|
Class<?> serverClass = serverHandler.getClass();
|
||||||
|
|
||||||
Enhancer ex = new Enhancer();
|
Enhancer ex = new Enhancer();
|
||||||
@ -135,16 +159,20 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use the existing field values when we create our copy
|
// Find the Minecraft NetServerHandler superclass
|
||||||
|
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
||||||
|
ExistingGenerator generator = ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass);
|
||||||
DefaultInstances serverInstances = null;
|
DefaultInstances serverInstances = null;
|
||||||
|
|
||||||
if (hasProxyServerHandler()) {
|
// Maybe the proxy instance can help?
|
||||||
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
Object proxyInstance = getProxyServerHandler();
|
||||||
serverInstances = DefaultInstances.fromArray(
|
|
||||||
ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass));
|
// Use the existing server proxy when we create one
|
||||||
|
if (proxyInstance != null && proxyInstance != serverHandler) {
|
||||||
|
serverInstances = DefaultInstances.fromArray(generator,
|
||||||
|
ExistingGenerator.fromObjectArray(new Object[] { proxyInstance }));
|
||||||
} else {
|
} else {
|
||||||
serverInstances = DefaultInstances.fromArray(
|
serverInstances = DefaultInstances.fromArray(generator);
|
||||||
ExistingGenerator.fromObjectFields(serverHandler));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstances.setNonNull(true);
|
serverInstances.setNonNull(true);
|
||||||
@ -158,19 +186,31 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
//copyTo(serverHandler, proxyObject);
|
//copyTo(serverHandler, proxyObject);
|
||||||
serverInjection.replaceServerHandler(serverHandler, proxyObject);
|
serverInjection.replaceServerHandler(serverHandler, proxyObject);
|
||||||
serverHandlerRef.setValue(proxyObject);
|
serverHandlerRef.setValue(proxyObject);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException(
|
return false;
|
||||||
"Cannot hook player: Unable to find a valid constructor for the NetServerHandler object.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object getProxyServerHandler() {
|
||||||
|
if (proxyServerField != null && !proxyServerField.equals(serverHandlerRef.getField())) {
|
||||||
|
try {
|
||||||
|
return FieldUtils.readField(proxyServerField, serverHandler, true);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Oh well
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
||||||
if (clazz.getName().startsWith("net.minecraft"))
|
if (clazz.getName().startsWith("net.minecraft.server."))
|
||||||
return clazz;
|
return clazz;
|
||||||
else if (clazz.equals(Object.class))
|
else if (clazz.equals(Object.class))
|
||||||
return clazz;
|
return clazz;
|
||||||
else
|
else
|
||||||
return clazz.getSuperclass();
|
return getFirstMinecraftSuperClass(clazz.getSuperclass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,8 +43,8 @@ import com.comphenix.protocol.reflect.VolatileField;
|
|||||||
abstract class PlayerInjector {
|
abstract class PlayerInjector {
|
||||||
|
|
||||||
// Cache previously retrieved fields
|
// Cache previously retrieved fields
|
||||||
private static Field serverHandlerField;
|
protected static Field serverHandlerField;
|
||||||
private static Field proxyServerField;
|
protected static Field proxyServerField;
|
||||||
|
|
||||||
protected static Field networkManagerField;
|
protected static Field networkManagerField;
|
||||||
protected static Field inputField;
|
protected static Field inputField;
|
||||||
@ -115,12 +115,7 @@ abstract class PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Yo dawg
|
// Yo dawg
|
||||||
if (proxyServerField != null) {
|
serverHandlerRef = new VolatileField(serverHandlerField, notchEntity);
|
||||||
Object container = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
|
||||||
serverHandlerRef = new VolatileField(proxyServerField, container);
|
|
||||||
} else {
|
|
||||||
serverHandlerRef = new VolatileField(serverHandlerField, notchEntity);
|
|
||||||
}
|
|
||||||
serverHandler = serverHandlerRef.getValue();
|
serverHandler = serverHandlerRef.getValue();
|
||||||
|
|
||||||
// Next, get the network manager
|
// Next, get the network manager
|
||||||
@ -166,6 +161,7 @@ abstract class PlayerInjector {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
hasProxyType = true;
|
hasProxyType = true;
|
||||||
|
logger.log(Level.WARNING, "Detected server handler proxy type by another plugin. Conflict may occur!");
|
||||||
|
|
||||||
// No? Is it a Proxy type?
|
// No? Is it a Proxy type?
|
||||||
try {
|
try {
|
||||||
@ -175,7 +171,7 @@ abstract class PlayerInjector {
|
|||||||
return reflection.getFieldByType(".*NetServerHandler");
|
return reflection.getFieldByType(".*NetServerHandler");
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
logger.log(Level.WARNING, "Detected server handler proxy type by another plugin. Conflict may occur!");
|
// Damn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,9 +156,12 @@ public class DefaultInstances {
|
|||||||
* @param type - type to construct.
|
* @param type - type to construct.
|
||||||
* @return A constructor with the fewest number of parameters, or NULL if the type has no constructors.
|
* @return A constructor with the fewest number of parameters, or NULL if the type has no constructors.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> Constructor<T> getMinimumConstructor(Class<T> type) {
|
public <T> Constructor<T> getMinimumConstructor(Class<T> type) {
|
||||||
|
return getMinimumConstructor(type, registered, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> Constructor<T> getMinimumConstructor(Class<T> type, List<InstanceProvider> providers, int recursionLevel) {
|
||||||
Constructor<T> minimum = null;
|
Constructor<T> minimum = null;
|
||||||
int lastCount = Integer.MAX_VALUE;
|
int lastCount = Integer.MAX_VALUE;
|
||||||
|
|
||||||
@ -170,6 +173,13 @@ public class DefaultInstances {
|
|||||||
// require itself in the constructor.
|
// require itself in the constructor.
|
||||||
if (types.length < lastCount) {
|
if (types.length < lastCount) {
|
||||||
if (!contains(types, type)) {
|
if (!contains(types, type)) {
|
||||||
|
if (nonNull) {
|
||||||
|
// Make sure all of these types are non-null
|
||||||
|
if (isAnyNull(types, providers, recursionLevel)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
minimum = (Constructor<T>) candidate;
|
minimum = (Constructor<T>) candidate;
|
||||||
lastCount = types.length;
|
lastCount = types.length;
|
||||||
|
|
||||||
@ -183,6 +193,27 @@ public class DefaultInstances {
|
|||||||
return minimum;
|
return minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if any of the given types will be NULL once created.
|
||||||
|
* <p>
|
||||||
|
* Recursion level is the number of times the default method has been called.
|
||||||
|
* @param types - types to check.
|
||||||
|
* @param providers - instance providers.
|
||||||
|
* @param recursionLevel - current recursion level.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isAnyNull(Class<?>[] types, List<InstanceProvider> providers, int recursionLevel) {
|
||||||
|
// Just check if any of them are NULL
|
||||||
|
for (Class<?> type : types) {
|
||||||
|
if (getDefaultInternal(type, providers, recursionLevel) == null) {
|
||||||
|
System.out.println(type.getName() + " is NULL!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a default instance or value that is assignable to this type.
|
* Retrieves a default instance or value that is assignable to this type.
|
||||||
* <p>
|
* <p>
|
||||||
@ -198,7 +229,7 @@ public class DefaultInstances {
|
|||||||
* </ul>
|
* </ul>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param type - the type to construct a default value.
|
* @param type - the type to construct a default value.
|
||||||
* @param providers - instance providers used during the
|
* @param providers - instance providers used during the construction.
|
||||||
* @return A default value/instance, or NULL if not possible.
|
* @return A default value/instance, or NULL if not possible.
|
||||||
*/
|
*/
|
||||||
public <T> T getDefault(Class<T> type, List<InstanceProvider> providers) {
|
public <T> T getDefault(Class<T> type, List<InstanceProvider> providers) {
|
||||||
@ -221,7 +252,7 @@ public class DefaultInstances {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Constructor<T> minimum = getMinimumConstructor(type);
|
Constructor<T> minimum = getMinimumConstructor(type, providers, recursionLevel + 1);
|
||||||
|
|
||||||
// Create the type with this constructor using default values. This might fail, though.
|
// Create the type with this constructor using default values. This might fail, though.
|
||||||
try {
|
try {
|
||||||
|
@ -17,8 +17,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
|
|||||||
*/
|
*/
|
||||||
public class ExistingGenerator implements InstanceProvider {
|
public class ExistingGenerator implements InstanceProvider {
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
private Map<String, Object> existingValues = new HashMap<String, Object>();
|
||||||
private Map<Class, Object> existingValues = new HashMap<Class, Object>();
|
|
||||||
|
|
||||||
private ExistingGenerator() {
|
private ExistingGenerator() {
|
||||||
// Only accessible to the constructors
|
// Only accessible to the constructors
|
||||||
@ -94,18 +93,17 @@ public class ExistingGenerator implements InstanceProvider {
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
throw new IllegalArgumentException("Value cannot be NULL.");
|
throw new IllegalArgumentException("Value cannot be NULL.");
|
||||||
|
|
||||||
existingValues.put(value.getClass(), value);
|
existingValues.put(value.getClass().getName(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addObject(Class<?> type, Object value) {
|
private void addObject(Class<?> type, Object value) {
|
||||||
existingValues.put(type, value);
|
existingValues.put(type.getName(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object create(@Nullable Class<?> type) {
|
public Object create(@Nullable Class<?> type) {
|
||||||
|
|
||||||
Object value = existingValues.get(type);
|
Object value = existingValues.get(type.getName());
|
||||||
|
|
||||||
// NULL values indicate that the generator failed
|
// NULL values indicate that the generator failed
|
||||||
return value;
|
return value;
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren