mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-28 05:35:28 +01:00
Attempting to add support for MCPC.
Still have to track down a very elusive bug however.
This commit is contained in:
parent
8b12907dfb
commit
e8c615b203
@ -19,6 +19,7 @@ package com.comphenix.protocol.async;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
@ -67,10 +68,16 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<AsyncList
|
||||
public PacketProcessingQueue(PlayerSendingHandler sendingHandler, int initialSize, int maximumSize, int maximumConcurrency) {
|
||||
super();
|
||||
|
||||
this.processingQueue = Synchronization.queue(MinMaxPriorityQueue.
|
||||
expectedSize(initialSize).
|
||||
maximumSize(maximumSize).
|
||||
<PacketEventHolder>create(), null);
|
||||
try {
|
||||
this.processingQueue = Synchronization.queue(MinMaxPriorityQueue.
|
||||
expectedSize(initialSize).
|
||||
maximumSize(maximumSize).
|
||||
<PacketEventHolder>create(), null);
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
// It's a Beta class after all
|
||||
this.processingQueue = Synchronization.queue(
|
||||
new PriorityQueue<PacketEventHolder>(), null);
|
||||
}
|
||||
|
||||
this.maximumConcurrency = maximumConcurrency;
|
||||
this.concurrentProcessing = new Semaphore(maximumConcurrency);
|
||||
|
@ -164,9 +164,9 @@ class EntityUtilities {
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
Object worldServer = unwrapper.unwrapItem(world);
|
||||
|
||||
// We have to rely on the class naming here.
|
||||
if (entityTrackerField == null)
|
||||
entityTrackerField = FuzzyReflection.fromObject(worldServer).getFieldByType(".*Tracker");
|
||||
entityTrackerField = FuzzyReflection.fromObject(worldServer).
|
||||
getFieldByType("tracker", MinecraftReflection.getEntityTrackerClass());
|
||||
|
||||
// Get the tracker
|
||||
Object tracker = null;
|
||||
@ -191,7 +191,7 @@ class EntityUtilities {
|
||||
|
||||
// The Minecraft field that's NOT filled in by the constructor
|
||||
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher(), ignoredTypes);
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex(), ignoredTypes);
|
||||
}
|
||||
|
||||
// Read the entity hashmap
|
||||
@ -250,8 +250,16 @@ class EntityUtilities {
|
||||
|
||||
// Handle NULL cases
|
||||
if (trackerEntry != null) {
|
||||
if (trackerField == null)
|
||||
trackerField = trackerEntry.getClass().getField("tracker");
|
||||
if (trackerField == null) {
|
||||
try {
|
||||
trackerField = trackerEntry.getClass().getField("tracker");
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Assume it's the first public entity field then
|
||||
trackerField = FuzzyReflection.fromObject(trackerEntry).getFieldByType(
|
||||
"tracker", MinecraftReflection.getEntityClass());
|
||||
}
|
||||
}
|
||||
|
||||
tracker = FieldUtils.readField(trackerField, trackerEntry, true);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class PacketInjector {
|
||||
if (intHashMap == null) {
|
||||
// We're looking for the first static field with a Minecraft-object. This should be a IntHashMap.
|
||||
Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher());
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
|
||||
|
||||
try {
|
||||
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);
|
||||
|
@ -107,12 +107,10 @@ class InjectedServerConnection {
|
||||
}
|
||||
|
||||
private void injectListenerThread() {
|
||||
|
||||
try {
|
||||
|
||||
if (listenerThreadField == null)
|
||||
listenerThreadField = FuzzyReflection.fromObject(minecraftServer).
|
||||
getFieldByType(".*NetworkListenThread");
|
||||
if (listenerThreadField == null)
|
||||
listenerThreadField = FuzzyReflection.fromObject(minecraftServer).
|
||||
getFieldByType("networkListenThread", MinecraftReflection.getNetworkListenThreadClass());
|
||||
} catch (RuntimeException e) {
|
||||
reporter.reportDetailed(this, "Cannot find listener thread in MinecraftServer.", e, minecraftServer);
|
||||
return;
|
||||
|
@ -20,7 +20,8 @@ package com.comphenix.protocol.injector.player;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.sf.cglib.proxy.Callback;
|
||||
import net.sf.cglib.proxy.CallbackFilter;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
@ -43,6 +44,7 @@ import com.comphenix.protocol.reflect.VolatileField;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Represents a player hook into the NetServerHandler class.
|
||||
@ -91,10 +93,60 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
|
||||
// Get the send packet method!
|
||||
if (hasInitialized) {
|
||||
if (sendPacketMethod == null)
|
||||
sendPacketMethod = FuzzyReflection.fromObject(serverHandler).getMethodByName("sendPacket.*");
|
||||
if (sendPacketMethod == null) {
|
||||
try {
|
||||
sendPacketMethod = FuzzyReflection.fromObject(serverHandler).getMethodByName("sendPacket.*");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Map<String, Method> netServer = getMethodList(
|
||||
MinecraftReflection.getNetServerHandlerClass(), MinecraftReflection.getPacketClass());
|
||||
Map<String, Method> netHandler = getMethodList(
|
||||
MinecraftReflection.getNetHandlerClass(), MinecraftReflection.getPacketClass());
|
||||
|
||||
// Remove every method in net handler from net server
|
||||
for (String methodName : netHandler.keySet()) {
|
||||
netServer.remove(methodName);
|
||||
}
|
||||
|
||||
// The remainder is the send packet method
|
||||
if (netServer.size() == 1) {
|
||||
Method[] methods = netServer.values().toArray(new Method[0]);
|
||||
sendPacketMethod = methods[0];
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to find the sendPacket method in NetServerHandler/PlayerConnection.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method mapped list of every method with the given signature.
|
||||
* @param source - class source.
|
||||
* @param params - parameters.
|
||||
* @return Method mapped list.
|
||||
*/
|
||||
private Map<String, Method> getMethodList(Class<?> source, Class<?>... params) {
|
||||
return getMappedMethods(
|
||||
FuzzyReflection.fromClass(source, true).
|
||||
getMethodListByParameters(Void.TYPE, params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every method as a map over names.
|
||||
* <p>
|
||||
* Note that overloaded methods will only occur once in the resulting map.
|
||||
* @param methods - every method.
|
||||
* @return A map over every given method.
|
||||
*/
|
||||
private Map<String, Method> getMappedMethods(List<Method> methods) {
|
||||
Map<String, Method> map = Maps.newHashMap();
|
||||
|
||||
for (Method method : methods) {
|
||||
map.put(method.getName(), method);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||
@ -296,8 +348,22 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
}
|
||||
FieldUtils.writeField(disconnectField, handler, value);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
reporter.reportDetailed(this, "Unable to find disconnect field. Is ProtocolLib up to date?", e, handler);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Assume it's the first ...
|
||||
if (disconnectField == null) {
|
||||
disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class);
|
||||
reporter.reportWarning(this, "Unable to find 'disconnected' field. Assuming " + disconnectField);
|
||||
|
||||
// Try again
|
||||
if (disconnectField != null) {
|
||||
setDisconnect(handler, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This is really bad
|
||||
reporter.reportDetailed(this, "Cannot find disconnected field. Is ProtocolLib up to date?", e);
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
reporter.reportWarning(this, "Unable to update disconnected field. Player quit event may be sent twice.");
|
||||
}
|
||||
|
@ -167,8 +167,8 @@ abstract class PlayerInjector {
|
||||
|
||||
// Next, get the network manager
|
||||
if (networkManagerField == null)
|
||||
networkManagerField = FuzzyReflection.fromObject(serverHandler).
|
||||
getFieldByType(".*" + MinecraftReflection.getNetworkManagerName());
|
||||
networkManagerField = FuzzyReflection.fromObject(serverHandler).getFieldByType(
|
||||
"networkManager", MinecraftReflection.getNetworkManagerClass());
|
||||
initializeNetworkManager(networkManagerField, serverHandler);
|
||||
}
|
||||
}
|
||||
@ -184,7 +184,7 @@ abstract class PlayerInjector {
|
||||
|
||||
if (netLoginNetworkField == null)
|
||||
netLoginNetworkField = FuzzyReflection.fromObject(netLoginHandler).
|
||||
getFieldByType(".*" + MinecraftReflection.getNetworkManagerName());
|
||||
getFieldByType("networkManager", MinecraftReflection.getNetworkManagerClass());
|
||||
initializeNetworkManager(netLoginNetworkField, netLoginHandler);
|
||||
}
|
||||
}
|
||||
@ -290,7 +290,13 @@ abstract class PlayerInjector {
|
||||
// Execute disconnect on it
|
||||
if (handler != null) {
|
||||
if (disconnect == null) {
|
||||
disconnect = FuzzyReflection.fromObject(handler).getMethodByName("disconnect.*");
|
||||
try {
|
||||
disconnect = FuzzyReflection.fromObject(handler).getMethodByName("disconnect.*");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Just assume it's the first String method
|
||||
disconnect = FuzzyReflection.fromObject(handler).getMethodByParameters("disconnect", String.class);
|
||||
reporter.reportWarning(this, "Cannot find disconnect method by name. Assuming " + disconnect);
|
||||
}
|
||||
|
||||
// Save the method for later
|
||||
if (usingNetServer)
|
||||
@ -380,7 +386,7 @@ abstract class PlayerInjector {
|
||||
try {
|
||||
// Well, that sucks. Try just Minecraft objects then.
|
||||
netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true).
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher());
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
|
||||
|
||||
} catch (RuntimeException e2) {
|
||||
throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage());
|
||||
|
@ -72,4 +72,64 @@ public abstract class AbstractFuzzyMatcher<T> implements Comparable<AbstractFuzz
|
||||
// No match
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fuzzy matcher that returns the opposite result of the current matcher.
|
||||
* @return An inverted fuzzy matcher.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<T> inverted() {
|
||||
return new AbstractFuzzyMatcher<T>() {
|
||||
@Override
|
||||
public boolean isMatch(T value, Object parent) {
|
||||
return !AbstractFuzzyMatcher.this.isMatch(value, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
return -2;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that this and the given matcher be TRUE.
|
||||
* @param other - the other fuzzy matcher.
|
||||
* @return A combined fuzzy matcher.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<T> and(final AbstractFuzzyMatcher<T> other) {
|
||||
return new AbstractFuzzyMatcher<T>() {
|
||||
@Override
|
||||
public boolean isMatch(T value, Object parent) {
|
||||
// They both have to be true
|
||||
return AbstractFuzzyMatcher.this.isMatch(value, parent) &&
|
||||
other.isMatch(value, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
return combineRounds(AbstractFuzzyMatcher.this.getRoundNumber(), other.getRoundNumber());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that either this or the other given matcher be TRUE.
|
||||
* @param other - the other fuzzy matcher.
|
||||
* @return A combined fuzzy matcher.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<T> or(final AbstractFuzzyMatcher<T> other) {
|
||||
return new AbstractFuzzyMatcher<T>() {
|
||||
@Override
|
||||
public boolean isMatch(T value, Object parent) {
|
||||
// Either can be true
|
||||
return AbstractFuzzyMatcher.this.isMatch(value, parent) ||
|
||||
other.isMatch(value, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
return combineRounds(AbstractFuzzyMatcher.this.getRoundNumber(), other.getRoundNumber());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ import javax.annotation.Nonnull;
|
||||
*/
|
||||
public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzzyMatcher<T> {
|
||||
// Accessibility matchers
|
||||
private int modifiersRequired;
|
||||
private int modifiersBanned;
|
||||
protected int modifiersRequired;
|
||||
protected int modifiersBanned;
|
||||
|
||||
private Pattern nameRegex;
|
||||
private AbstractFuzzyMatcher<Class<?>> declaringMatcher = ExactClassMatcher.MATCH_ALL;
|
||||
protected Pattern nameRegex;
|
||||
protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ExactClassMatcher.MATCH_ALL;
|
||||
|
||||
/**
|
||||
* Whether or not this contract can be modified.
|
||||
@ -89,7 +89,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassExactType(Class<?> declaringClass) {
|
||||
member.declaringMatcher = ExactClassMatcher.matchExact(declaringClass);
|
||||
member.declaringMatcher = FuzzyMatchers.matchExact(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassSuperOf(Class<?> declaringClass) {
|
||||
member.declaringMatcher = ExactClassMatcher.matchSuper(declaringClass);
|
||||
member.declaringMatcher = FuzzyMatchers.matchSuper(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassDerivedOf(Class<?> declaringClass) {
|
||||
member.declaringMatcher = ExactClassMatcher.matchDerived(declaringClass);
|
||||
member.declaringMatcher = FuzzyMatchers.matchDerived(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -34,38 +34,12 @@ class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
||||
private final Class<?> matcher;
|
||||
private final Options option;
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches types exactly.
|
||||
* @param matcher - the matching class.
|
||||
*/
|
||||
public static ExactClassMatcher matchExact(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, Options.MATCH_EXACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches super types of the given class.
|
||||
* @param matcher - the matching type must be a super class of this type.
|
||||
* @return A new class mathcher.
|
||||
*/
|
||||
public static ExactClassMatcher matchSuper(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, Options.MATCH_SUPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches derived types of the given class.
|
||||
* @param matcher - the matching type must be a derived class of this type.
|
||||
* @return A new class mathcher.
|
||||
*/
|
||||
public static ExactClassMatcher matchDerived(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, Options.MATCH_DERIVED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new class matcher.
|
||||
* @param matcher - the matching class, or NULL to represent anything.
|
||||
* @param option - options specifying the matching rules.
|
||||
*/
|
||||
private ExactClassMatcher(Class<?> matcher, Options option) {
|
||||
ExactClassMatcher(Class<?> matcher, Options option) {
|
||||
this.matcher = matcher;
|
||||
this.option = option;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.comphenix.protocol.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@ -107,32 +107,6 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher<Class<?>> {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the parent class of a method, field or constructor.
|
||||
* @return Parent matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchParent() {
|
||||
return new AbstractFuzzyMatcher<Class<?>>() {
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
if (parent instanceof Member) {
|
||||
return ((Member) parent).getDeclaringClass().equals(value);
|
||||
} else if (parent instanceof Class) {
|
||||
return parent.equals(value);
|
||||
} else {
|
||||
// Can't be a match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
// We match a very specific type
|
||||
return -100;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new fuzzy class contract with the given contracts.
|
||||
* @param fieldContracts - field contracts.
|
||||
@ -197,7 +171,7 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher<Class<?>> {
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
FuzzyReflection reflection = FuzzyReflection.fromClass(value);
|
||||
FuzzyReflection reflection = FuzzyReflection.fromClass(value, true);
|
||||
|
||||
// Make sure all the contracts are valid
|
||||
return processContracts(reflection.getFields(), value, fieldContracts) &&
|
||||
|
@ -13,6 +13,11 @@ import javax.annotation.Nonnull;
|
||||
public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
||||
private AbstractFuzzyMatcher<Class<?>> typeMatcher = ExactClassMatcher.MATCH_ALL;
|
||||
|
||||
/**
|
||||
* Represents a builder for a field matcher.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Builder extends AbstractFuzzyMember.Builder<FuzzyFieldContract> {
|
||||
@Override
|
||||
public Builder requireModifier(int modifier) {
|
||||
@ -74,12 +79,22 @@ public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
||||
}
|
||||
|
||||
public Builder typeExact(Class<?> type) {
|
||||
member.typeMatcher = ExactClassMatcher.matchExact(type);
|
||||
member.typeMatcher = FuzzyMatchers.matchExact(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeSuperOf(Class<?> type) {
|
||||
member.typeMatcher = ExactClassMatcher.matchSuper(type);
|
||||
member.typeMatcher = FuzzyMatchers.matchSuper(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeDerivedOf(Class<?> type) {
|
||||
member.typeMatcher = FuzzyMatchers.matchDerived(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeMatches(AbstractFuzzyMatcher<Class<?>> matcher) {
|
||||
member.typeMatcher = matcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -90,6 +105,10 @@ public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new fuzzy field contract builder.
|
||||
* @return New fuzzy field contract builder.
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
package com.comphenix.protocol.reflect;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Contains factory methods for matching classes.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyMatchers {
|
||||
private FuzzyMatchers() {
|
||||
// Don't make this constructable
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches types exactly.
|
||||
* @param matcher - the matching class.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchExact(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_EXACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches super types of the given class.
|
||||
* @param matcher - the matching type must be a super class of this type.
|
||||
* @return A new class mathcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchSuper(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_SUPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches derived types of the given class.
|
||||
* @param matcher - the matching type must be a derived class of this type.
|
||||
* @return A new class mathcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchDerived(Class<?> matcher) {
|
||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_DERIVED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher based on the canonical names of classes.
|
||||
* @param regex - regular expression pattern matching class names.
|
||||
* @param priority - the priority this matcher takes - higher is better.
|
||||
* @return A fuzzy class matcher based on name.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchRegex(final Pattern regex, final int priority) {
|
||||
return new AbstractFuzzyMatcher<Class<?>>() {
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
if (value != null)
|
||||
return regex.matcher(value.getCanonicalName()).matches();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
return -priority;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher based on the canonical names of classes.
|
||||
* @param regex - regular expression matching class names.
|
||||
* @param priority - the priority this matcher takes - higher is better.
|
||||
* @return A fuzzy class matcher based on name.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchRegex(String regex, final int priority) {
|
||||
return FuzzyMatchers.matchRegex(Pattern.compile(regex), priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the parent class of a method, field or constructor.
|
||||
* @return Parent matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchParent() {
|
||||
return new AbstractFuzzyMatcher<Class<?>>() {
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
if (parent instanceof Member) {
|
||||
return ((Member) parent).getDeclaringClass().equals(value);
|
||||
} else if (parent instanceof Class) {
|
||||
return parent.equals(value);
|
||||
} else {
|
||||
// Can't be a match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateRoundNumber() {
|
||||
// We match a very specific type
|
||||
return -100;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -85,6 +85,11 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
// Expected parameter count
|
||||
private Integer paramCount;
|
||||
|
||||
/**
|
||||
* Represents a builder for a fuzzy method contract.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Builder extends AbstractFuzzyMember.Builder<FuzzyMethodContract> {
|
||||
public Builder requireModifier(int modifier) {
|
||||
super.requireModifier(modifier);
|
||||
@ -145,19 +150,19 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterExactType(Class<?> type) {
|
||||
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type)));
|
||||
member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must be a superlcass of the given type.
|
||||
* Add a new required parameter whose type must be a superclass of the given type.
|
||||
* <p>
|
||||
* If a parameter is of type Number, any derived class (Integer, Long, etc.) will match it.
|
||||
* @param type - a type or derived type of the matching parameter.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterSuperOf(Class<?> type) {
|
||||
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type)));
|
||||
member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -178,7 +183,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterExactType(Class<?> type, int index) {
|
||||
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type), index));
|
||||
member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -191,7 +196,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterSuperOf(Class<?> type, int index) {
|
||||
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type), index));
|
||||
member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -230,7 +235,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnTypeExact(Class<?> type) {
|
||||
member.returnMatcher = ExactClassMatcher.matchExact(type);
|
||||
member.returnMatcher = FuzzyMatchers.matchExact(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -240,7 +245,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnDerivedOf(Class<?> type) {
|
||||
member.returnMatcher = ExactClassMatcher.matchDerived(type);
|
||||
member.returnMatcher = FuzzyMatchers.matchDerived(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -260,7 +265,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionExactType(Class<?> type) {
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type)));
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -270,7 +275,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionSuperOf(Class<?> type) {
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type)));
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -291,7 +296,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionExactType(Class<?> type, int index) {
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type), index));
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -302,7 +307,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionSuperOf(Class<?> type, int index) {
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type), index));
|
||||
member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -330,6 +335,10 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a method contract builder.
|
||||
* @return Method contract builder.
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
@ -254,7 +254,6 @@ public class FuzzyReflection {
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public Field getFieldByName(String nameRegex) {
|
||||
|
||||
Pattern match = Pattern.compile(nameRegex);
|
||||
|
||||
for (Field field : getFields()) {
|
||||
@ -276,7 +275,6 @@ public class FuzzyReflection {
|
||||
* @return The first field with a type that is an instance of the given type.
|
||||
*/
|
||||
public Field getFieldByType(String name, Class<?> type) {
|
||||
|
||||
List<Field> fields = getFieldListByType(type);
|
||||
|
||||
if (fields.size() > 0) {
|
||||
@ -295,7 +293,6 @@ public class FuzzyReflection {
|
||||
* @return Every field with a type that is an instance of the given type.
|
||||
*/
|
||||
public List<Field> getFieldListByType(Class<?> type) {
|
||||
|
||||
List<Field> fields = new ArrayList<Field>();
|
||||
|
||||
// Field with a compatible type
|
||||
|
@ -17,9 +17,17 @@
|
||||
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -29,6 +37,13 @@ import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.reflect.AbstractFuzzyMatcher;
|
||||
import com.comphenix.protocol.reflect.FuzzyClassContract;
|
||||
import com.comphenix.protocol.reflect.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
/**
|
||||
@ -40,7 +55,7 @@ public class MinecraftReflection {
|
||||
/**
|
||||
* Regular expression that matches a Minecraft object.
|
||||
* <p>
|
||||
* Replaced by the method {@link #getMinecraftObjectMatcher()}.
|
||||
* Replaced by the method {@link #getMinecraftObjectRegex()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String MINECRAFT_OBJECT = "net\\.minecraft(\\.\\w+)+";
|
||||
@ -81,12 +96,20 @@ public class MinecraftReflection {
|
||||
* Retrieve a regular expression that can match Minecraft package objects.
|
||||
* @return Minecraft package matcher.
|
||||
*/
|
||||
public static String getMinecraftObjectMatcher() {
|
||||
public static String getMinecraftObjectRegex() {
|
||||
if (DYNAMIC_PACKAGE_MATCHER == null)
|
||||
getMinecraftPackage();
|
||||
return DYNAMIC_PACKAGE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a abstract fuzzy class matcher for Minecraft objects.
|
||||
* @return A matcher for Minecraft objects.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> getMinecraftObjectMatcher() {
|
||||
return FuzzyMatchers.matchRegex(getMinecraftObjectRegex(), 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of the Minecraft server package.
|
||||
* @return Full canonical name of the Minecraft server package.
|
||||
@ -120,6 +143,10 @@ public class MinecraftReflection {
|
||||
DYNAMIC_PACKAGE_MATCHER =
|
||||
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ?
|
||||
Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + "\\w+";
|
||||
|
||||
// We'll still accept the default location, however
|
||||
DYNAMIC_PACKAGE_MATCHER = "(" + DYNAMIC_PACKAGE_MATCHER + ")|(" + MINECRAFT_OBJECT + ")";
|
||||
|
||||
} else {
|
||||
// Use the standard matcher
|
||||
DYNAMIC_PACKAGE_MATCHER = MINECRAFT_OBJECT;
|
||||
@ -146,6 +173,9 @@ public class MinecraftReflection {
|
||||
public static void setMinecraftPackage(String minecraftPackage, String craftBukkitPackage) {
|
||||
MINECRAFT_FULL_PACKAGE = minecraftPackage;
|
||||
CRAFTBUKKIT_PACKAGE = craftBukkitPackage;
|
||||
|
||||
// Standard matcher
|
||||
DYNAMIC_PACKAGE_MATCHER = MINECRAFT_OBJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,7 +355,22 @@ public class MinecraftReflection {
|
||||
* @return The entity class.
|
||||
*/
|
||||
public static Class<?> getEntityPlayerClass() {
|
||||
return getMinecraftClass("EntityPlayer");
|
||||
try {
|
||||
return getMinecraftClass("EntityPlayer");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
// A fairly stable method
|
||||
Method detect = FuzzyReflection.fromClass(getCraftBukkitClass("CraftServer")).
|
||||
getMethodByName("detectListNameConflict");
|
||||
|
||||
// EntityPlayer is then the first parameter
|
||||
return detect.getParameterTypes()[0];
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Last resort
|
||||
return fallbackMethodReturn("EntityPlayer", "entity.CraftPlayer", "getHandle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,7 +378,38 @@ public class MinecraftReflection {
|
||||
* @return The entity class.
|
||||
*/
|
||||
public static Class<?> getEntityClass() {
|
||||
try {
|
||||
return getMinecraftClass("Entity");
|
||||
} catch (RuntimeException e) {
|
||||
return fallbackMethodReturn("Entity", "entity.CraftEntity", "getHandle");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the WorldServer (NMS) class.
|
||||
* @return The WorldServer class.
|
||||
*/
|
||||
public static Class<?> getWorldServerClass() {
|
||||
try {
|
||||
return getMinecraftClass("WorldServer");
|
||||
} catch (RuntimeException e) {
|
||||
return fallbackMethodReturn("WorldServer", "CraftWorld", "getHandle");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback on the return value of a named method in order to get a NMS class.
|
||||
* @param nmsClass - the expected name of the Minecraft class.
|
||||
* @param craftClass - a CraftBukkit class to look at.
|
||||
* @param methodName - the method we will use.
|
||||
* @return The return value of this method, which will be saved to the package cache.
|
||||
*/
|
||||
private static Class<?> fallbackMethodReturn(String nmsClass, String craftClass, String methodName) {
|
||||
Class<?> result = FuzzyReflection.fromClass(getCraftBukkitClass(craftClass)).
|
||||
getMethodByName(methodName).getReturnType();
|
||||
|
||||
// Save the result
|
||||
return setMinecraftClass(nmsClass, result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -341,15 +417,89 @@ public class MinecraftReflection {
|
||||
* @return The packet class.
|
||||
*/
|
||||
public static Class<?> getPacketClass() {
|
||||
return getMinecraftClass("Packet");
|
||||
try {
|
||||
return getMinecraftClass("Packet");
|
||||
} catch (RuntimeException e) {
|
||||
// What kind of class we're looking for (sanity check)
|
||||
FuzzyClassContract paketContract =
|
||||
FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Map.class).
|
||||
requireModifier(Modifier.STATIC)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Set.class).
|
||||
requireModifier(Modifier.STATIC)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterSuperOf(DataInputStream.class).
|
||||
returnTypeVoid()).
|
||||
build();
|
||||
|
||||
// Select a method with one Minecraft object parameter
|
||||
Method selected = FuzzyReflection.fromClass(getNetHandlerClass()).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
parameterMatches(paketContract, 0).
|
||||
parameterCount(1).
|
||||
build()
|
||||
);
|
||||
|
||||
// Save and return
|
||||
Class<?> clazz = getTopmostClass(selected.getParameterTypes()[0]);
|
||||
return setMinecraftClass("Packet", clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the least derived class, except Object.
|
||||
* @return Least derived super class.
|
||||
*/
|
||||
private static Class<?> getTopmostClass(Class<?> clazz) {
|
||||
while (true) {
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
|
||||
if (superClass == Object.class || superClass == null)
|
||||
return clazz;
|
||||
else
|
||||
clazz = superClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the MinecraftServer class.
|
||||
* @return MinecraftServer class.
|
||||
*/
|
||||
public static Class<?> getMinecraftServerClass() {
|
||||
try {
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
} catch (RuntimeException e) {
|
||||
// Get the first constructor that matches CraftServer(MINECRAFT_OBJECT, ANY)
|
||||
Constructor<?> selected = FuzzyReflection.fromClass(getCraftBukkitClass("CraftServer")).
|
||||
getConstructor(FuzzyMethodContract.newBuilder().
|
||||
parameterMatches(getMinecraftObjectMatcher(), 0).
|
||||
parameterCount(2).
|
||||
build()
|
||||
);
|
||||
Class<?>[] params = selected.getParameterTypes();
|
||||
|
||||
// Jackpot - two classes at the same time!
|
||||
setMinecraftClass("MinecraftServer", params[0]);
|
||||
setMinecraftClass("ServerConfigurationManager", params[1]);
|
||||
return params[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the player list class (or ServerConfigurationManager),
|
||||
* @return The player list class.
|
||||
*/
|
||||
public static Class<?> getPlayerListClass() {
|
||||
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
|
||||
try {
|
||||
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
|
||||
} catch (RuntimeException e) {
|
||||
// Try again
|
||||
getMinecraftServerClass();
|
||||
return getMinecraftClass("ServerConfigurationManager");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -357,7 +507,22 @@ public class MinecraftReflection {
|
||||
* @return The NetLoginHandler class.
|
||||
*/
|
||||
public static Class<?> getNetLoginHandlerClass() {
|
||||
return getMinecraftClass("NetLoginHandler", "PendingConnection");
|
||||
try {
|
||||
return getMinecraftClass("NetLoginHandler", "PendingConnection");
|
||||
} catch (RuntimeException e) {
|
||||
Method selected = FuzzyReflection.fromClass(getPlayerListClass()).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
parameterMatches(
|
||||
FuzzyMatchers.matchExact(getEntityPlayerClass()).inverted(), 0
|
||||
).
|
||||
parameterExactType(String.class, 1).
|
||||
parameterExactType(String.class, 2).
|
||||
build()
|
||||
);
|
||||
|
||||
// Save the pending connection reference
|
||||
return setMinecraftClass("NetLoginHandler", selected.getParameterTypes()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -365,15 +530,35 @@ public class MinecraftReflection {
|
||||
* @return The NetServerHandler class.
|
||||
*/
|
||||
public static Class<?> getNetServerHandlerClass() {
|
||||
return getMinecraftClass("NetServerHandler", "PlayerConnection");
|
||||
try {
|
||||
return getMinecraftClass("NetServerHandler", "PlayerConnection");
|
||||
} catch (RuntimeException e) {
|
||||
// Use the player connection field
|
||||
return setMinecraftClass("NetLoginHandler",
|
||||
FuzzyReflection.fromClass(getEntityPlayerClass()).
|
||||
getFieldByType("playerConnection", getNetHandlerClass()).getType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NetworkManager class.
|
||||
* @return The NetworkManager class.
|
||||
* Retrieve the NetworkManager class or its interface.
|
||||
* @return The NetworkManager class or its interface.
|
||||
*/
|
||||
public static Class<?> getNetworkManagerClass() {
|
||||
return getMinecraftClass("NetworkManager");
|
||||
try {
|
||||
return getMinecraftClass("INetworkManager", "NetworkManager");
|
||||
} catch (RuntimeException e) {
|
||||
Constructor<?> selected = FuzzyReflection.fromClass(getNetServerHandlerClass()).
|
||||
getConstructor(FuzzyMethodContract.newBuilder().
|
||||
parameterSuperOf(getMinecraftServerClass(), 0).
|
||||
parameterSuperOf(getEntityPlayerClass(), 2).
|
||||
build()
|
||||
);
|
||||
|
||||
// And we're done
|
||||
return setMinecraftClass("INetworkManager", selected.getParameterTypes()[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,7 +566,11 @@ public class MinecraftReflection {
|
||||
* @return The NetHandler class.
|
||||
*/
|
||||
public static Class<?> getNetHandlerClass() {
|
||||
return getMinecraftClass("NetHandler", "Connection");
|
||||
try {
|
||||
return getMinecraftClass("NetHandler", "Connection");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("NetHandler", getNetLoginHandlerClass().getSuperclass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,7 +578,13 @@ public class MinecraftReflection {
|
||||
* @return The ItemStack class.
|
||||
*/
|
||||
public static Class<?> getItemStackClass() {
|
||||
return getMinecraftClass("ItemStack");
|
||||
try {
|
||||
return getMinecraftClass("ItemStack");
|
||||
} catch (RuntimeException e) {
|
||||
// Use the handle reference
|
||||
return setMinecraftClass("ItemStack",
|
||||
FuzzyReflection.fromClass(getCraftItemStackClass(), true).getFieldByName("handle").getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -397,15 +592,21 @@ public class MinecraftReflection {
|
||||
* @return The WorldType class.
|
||||
*/
|
||||
public static Class<?> getWorldTypeClass() {
|
||||
return getMinecraftClass("WorldType");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the MinecraftServer class.
|
||||
* @return MinecraftServer class.
|
||||
*/
|
||||
public static Class<?> getMinecraftServerClass() {
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
try {
|
||||
return getMinecraftClass("WorldType");
|
||||
} catch (RuntimeException e) {
|
||||
// Get the first constructor that matches CraftServer(MINECRAFT_OBJECT, ANY)
|
||||
Method selected = FuzzyReflection.fromClass(getMinecraftServerClass(), true).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(String.class, 0).
|
||||
parameterExactType(String.class, 1).
|
||||
parameterMatches(getMinecraftObjectMatcher()).
|
||||
parameterExactType(String.class, 4).
|
||||
parameterCount(5).
|
||||
build()
|
||||
);
|
||||
return setMinecraftClass("WorldType", selected.getParameterTypes()[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -413,7 +614,33 @@ public class MinecraftReflection {
|
||||
* @return The DataWatcher class.
|
||||
*/
|
||||
public static Class<?> getDataWatcherClass() {
|
||||
return getMinecraftClass("DataWatcher");
|
||||
try {
|
||||
return getMinecraftClass("DataWatcher");
|
||||
} catch (RuntimeException e) {
|
||||
// Describe the DataWatcher
|
||||
FuzzyClassContract dataWatcherContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
requireModifier(Modifier.STATIC).
|
||||
typeDerivedOf(Map.class)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
banModifier(Modifier.STATIC).
|
||||
typeDerivedOf(Map.class)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(int.class).
|
||||
parameterExactType(Object.class).
|
||||
returnTypeVoid()).
|
||||
build();
|
||||
FuzzyFieldContract fieldContract = FuzzyFieldContract.newBuilder().
|
||||
typeMatches(dataWatcherContract).
|
||||
build();
|
||||
|
||||
// Get such a field and save the result
|
||||
return setMinecraftClass("DataWatcher",
|
||||
FuzzyReflection.fromClass(getEntityClass(), true).
|
||||
getField(fieldContract).
|
||||
getType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -421,7 +648,25 @@ public class MinecraftReflection {
|
||||
* @return The ChunkPosition class.
|
||||
*/
|
||||
public static Class<?> getChunkPositionClass() {
|
||||
return getMinecraftClass("ChunkPosition");
|
||||
try {
|
||||
return getMinecraftClass("ChunkPosition");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> normalChunkGenerator = getCraftBukkitClass("generator.NormalChunkGenerator");
|
||||
|
||||
// ChunkPosition a(net.minecraft.server.World world, String string, int i, int i1, int i2) {
|
||||
FuzzyMethodContract selected = FuzzyMethodContract.newBuilder().
|
||||
banModifier(Modifier.STATIC).
|
||||
parameterMatches(getMinecraftObjectMatcher(), 0).
|
||||
parameterExactType(String.class, 1).
|
||||
parameterExactType(int.class, 2).
|
||||
parameterExactType(int.class, 3).
|
||||
parameterExactType(int.class, 4).
|
||||
build();
|
||||
|
||||
return setMinecraftClass("ChunkPosition",
|
||||
FuzzyReflection.fromClass(normalChunkGenerator).
|
||||
getMethod(selected).getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -429,7 +674,11 @@ public class MinecraftReflection {
|
||||
* @return The ChunkPosition class.
|
||||
*/
|
||||
public static Class<?> getChunkCoordinatesClass() {
|
||||
return getMinecraftClass("ChunkCoordinates");
|
||||
try {
|
||||
return getMinecraftClass("ChunkCoordinates");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("ChunkCoordinates", WrappedDataWatcher.getTypeClass(6));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -437,7 +686,19 @@ public class MinecraftReflection {
|
||||
* @return The WatchableObject class.
|
||||
*/
|
||||
public static Class<?> getWatchableObjectClass() {
|
||||
return getMinecraftClass("WatchableObject");
|
||||
try {
|
||||
return getMinecraftClass("WatchableObject");
|
||||
} catch (RuntimeException e) {
|
||||
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
requireModifier(Modifier.STATIC).
|
||||
parameterSuperOf(DataOutputStream.class, 0).
|
||||
parameterMatches(getMinecraftObjectMatcher(), 1).
|
||||
build());
|
||||
|
||||
// Use the second parameter
|
||||
return setMinecraftClass("WatchableObject", selected.getParameterTypes()[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,7 +706,26 @@ public class MinecraftReflection {
|
||||
* @return The ServerConnection class.
|
||||
*/
|
||||
public static Class<?> getServerConnectionClass() {
|
||||
return getMinecraftClass("ServerConnection");
|
||||
try {
|
||||
return getMinecraftClass("ServerConnection");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract serverConnectionContract = FuzzyClassContract.newBuilder().
|
||||
constructor(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(getMinecraftServerClass()).
|
||||
parameterCount(1)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(getNetServerHandlerClass())).
|
||||
build();
|
||||
|
||||
Method selected = FuzzyReflection.fromClass(getMinecraftServerClass()).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
requireModifier(Modifier.ABSTRACT).
|
||||
returnTypeMatches(serverConnectionContract).
|
||||
build());
|
||||
|
||||
// Use the return type
|
||||
return setMinecraftClass("ServerConnection", selected.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,7 +733,95 @@ public class MinecraftReflection {
|
||||
* @return The NBT base class.
|
||||
*/
|
||||
public static Class<?> getNBTBaseClass() {
|
||||
return getMinecraftClass("NBTBase");
|
||||
try {
|
||||
return getMinecraftClass("NBTBase");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract tagCompoundContract = FuzzyClassContract.newBuilder().
|
||||
constructor(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(String.class).
|
||||
parameterCount(1)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Map.class)).
|
||||
build();
|
||||
|
||||
Method selected = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
requireModifier(Modifier.STATIC).
|
||||
parameterSuperOf(DataInputStream.class).
|
||||
parameterCount(1).
|
||||
returnTypeMatches(tagCompoundContract).
|
||||
build()
|
||||
);
|
||||
|
||||
// Use the return type here too
|
||||
return setMinecraftClass("NBTBase", selected.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the EntityTracker (NMS) class.
|
||||
* @return EntityTracker class.
|
||||
*/
|
||||
public static Class<?> getEntityTrackerClass() {
|
||||
try {
|
||||
return getMinecraftClass("EntityTracker");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract entityTrackerContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Set.class)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterSuperOf(MinecraftReflection.getEntityClass()).
|
||||
parameterCount(1).
|
||||
returnTypeVoid()).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterSuperOf(MinecraftReflection.getEntityClass(), 0).
|
||||
parameterSuperOf(int.class, 1).
|
||||
parameterSuperOf(int.class, 2).
|
||||
parameterCount(3).
|
||||
returnTypeVoid()).
|
||||
build();
|
||||
|
||||
Field selected = FuzzyReflection.fromClass(MinecraftReflection.getWorldServerClass(), true).
|
||||
getField(FuzzyFieldContract.newBuilder().
|
||||
typeMatches(entityTrackerContract).
|
||||
build()
|
||||
);
|
||||
|
||||
// Go by the defined type of this field
|
||||
return setMinecraftClass("EntityTracker", selected.getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NetworkListenThread class (NMS).
|
||||
* <p>
|
||||
* Note that this class was removed after Minecraft 1.3.1.
|
||||
* @return NetworkListenThread class.
|
||||
*/
|
||||
public static Class<?> getNetworkListenThreadClass() {
|
||||
try {
|
||||
return getMinecraftClass("NetworkListenThread");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract networkListenContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(ServerSocket.class)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Thread.class)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(List.class)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(getNetServerHandlerClass())).
|
||||
build();
|
||||
|
||||
Field selected = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftServerClass(), true).
|
||||
getField(FuzzyFieldContract.newBuilder().
|
||||
typeMatches(networkListenContract).
|
||||
build()
|
||||
);
|
||||
|
||||
// Go by the defined type of this field
|
||||
return setMinecraftClass("NetworkListenThread", selected.getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -619,6 +987,19 @@ public class MinecraftReflection {
|
||||
return minecraftPackage.getPackageClass(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class object for the specific Minecraft class.
|
||||
* @param className - name of the Minecraft class.
|
||||
* @param clazz - the new class object.
|
||||
* @return The provided clazz object.
|
||||
*/
|
||||
private static Class<?> setMinecraftClass(String className, Class<?> clazz) {
|
||||
if (minecraftPackage == null)
|
||||
minecraftPackage = new CachedPackage(getMinecraftPackage());
|
||||
minecraftPackage.setPackageClass(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first class that matches a specified Minecraft name.
|
||||
* @param className - the specific Minecraft class.
|
||||
|
Loading…
Reference in New Issue
Block a user