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.FuzzyReflection;
|
||||
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.ExistingGenerator;
|
||||
|
||||
@ -97,6 +98,29 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
if (serverHandlerRef.getValue() instanceof Factory)
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
if (hasProxyServerHandler()) {
|
||||
Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
|
||||
serverInstances = DefaultInstances.fromArray(
|
||||
ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass));
|
||||
// Maybe the proxy instance can help?
|
||||
Object proxyInstance = getProxyServerHandler();
|
||||
|
||||
// Use the existing server proxy when we create one
|
||||
if (proxyInstance != null && proxyInstance != serverHandler) {
|
||||
serverInstances = DefaultInstances.fromArray(generator,
|
||||
ExistingGenerator.fromObjectArray(new Object[] { proxyInstance }));
|
||||
} else {
|
||||
serverInstances = DefaultInstances.fromArray(
|
||||
ExistingGenerator.fromObjectFields(serverHandler));
|
||||
serverInstances = DefaultInstances.fromArray(generator);
|
||||
}
|
||||
|
||||
serverInstances.setNonNull(true);
|
||||
@ -158,19 +186,31 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
//copyTo(serverHandler, proxyObject);
|
||||
serverInjection.replaceServerHandler(serverHandler, proxyObject);
|
||||
serverHandlerRef.setValue(proxyObject);
|
||||
return true;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Cannot hook player: Unable to find a valid constructor for the NetServerHandler object.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (clazz.getName().startsWith("net.minecraft"))
|
||||
if (clazz.getName().startsWith("net.minecraft.server."))
|
||||
return clazz;
|
||||
else if (clazz.equals(Object.class))
|
||||
return clazz;
|
||||
else
|
||||
return clazz.getSuperclass();
|
||||
return getFirstMinecraftSuperClass(clazz.getSuperclass());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,8 +43,8 @@ import com.comphenix.protocol.reflect.VolatileField;
|
||||
abstract class PlayerInjector {
|
||||
|
||||
// Cache previously retrieved fields
|
||||
private static Field serverHandlerField;
|
||||
private static Field proxyServerField;
|
||||
protected static Field serverHandlerField;
|
||||
protected static Field proxyServerField;
|
||||
|
||||
protected static Field networkManagerField;
|
||||
protected static Field inputField;
|
||||
@ -115,12 +115,7 @@ abstract class PlayerInjector {
|
||||
}
|
||||
|
||||
// Yo dawg
|
||||
if (proxyServerField != null) {
|
||||
Object container = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
||||
serverHandlerRef = new VolatileField(proxyServerField, container);
|
||||
} else {
|
||||
serverHandlerRef = new VolatileField(serverHandlerField, notchEntity);
|
||||
}
|
||||
serverHandler = serverHandlerRef.getValue();
|
||||
|
||||
// Next, get the network manager
|
||||
@ -166,6 +161,7 @@ abstract class PlayerInjector {
|
||||
return null;
|
||||
|
||||
hasProxyType = true;
|
||||
logger.log(Level.WARNING, "Detected server handler proxy type by another plugin. Conflict may occur!");
|
||||
|
||||
// No? Is it a Proxy type?
|
||||
try {
|
||||
@ -175,7 +171,7 @@ abstract class PlayerInjector {
|
||||
return reflection.getFieldByType(".*NetServerHandler");
|
||||
|
||||
} 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.
|
||||
* @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) {
|
||||
return getMinimumConstructor(type, registered, 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Constructor<T> getMinimumConstructor(Class<T> type, List<InstanceProvider> providers, int recursionLevel) {
|
||||
Constructor<T> minimum = null;
|
||||
int lastCount = Integer.MAX_VALUE;
|
||||
|
||||
@ -170,6 +173,13 @@ public class DefaultInstances {
|
||||
// require itself in the constructor.
|
||||
if (types.length < lastCount) {
|
||||
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;
|
||||
lastCount = types.length;
|
||||
|
||||
@ -183,6 +193,27 @@ public class DefaultInstances {
|
||||
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.
|
||||
* <p>
|
||||
@ -198,7 +229,7 @@ public class DefaultInstances {
|
||||
* </ul>
|
||||
* </ul>
|
||||
* @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.
|
||||
*/
|
||||
public <T> T getDefault(Class<T> type, List<InstanceProvider> providers) {
|
||||
@ -221,7 +252,7 @@ public class DefaultInstances {
|
||||
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.
|
||||
try {
|
||||
|
@ -17,8 +17,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
*/
|
||||
public class ExistingGenerator implements InstanceProvider {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Map<Class, Object> existingValues = new HashMap<Class, Object>();
|
||||
private Map<String, Object> existingValues = new HashMap<String, Object>();
|
||||
|
||||
private ExistingGenerator() {
|
||||
// Only accessible to the constructors
|
||||
@ -94,18 +93,17 @@ public class ExistingGenerator implements InstanceProvider {
|
||||
if (value == 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) {
|
||||
existingValues.put(type, value);
|
||||
existingValues.put(type.getName(), value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object create(@Nullable Class<?> type) {
|
||||
|
||||
Object value = existingValues.get(type);
|
||||
Object value = existingValues.get(type.getName());
|
||||
|
||||
// NULL values indicate that the generator failed
|
||||
return value;
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren