Archiviert
13
0

Attempting to add support for MCPC.

Still have to track down a very elusive bug however.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-01-31 06:23:01 +01:00
Ursprung 8b12907dfb
Commit e8c615b203
15 geänderte Dateien mit 729 neuen und 130 gelöschten Zeilen

Datei anzeigen

@ -19,6 +19,7 @@ package com.comphenix.protocol.async;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
@ -67,10 +68,16 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<AsyncList
public PacketProcessingQueue(PlayerSendingHandler sendingHandler, int initialSize, int maximumSize, int maximumConcurrency) { public PacketProcessingQueue(PlayerSendingHandler sendingHandler, int initialSize, int maximumSize, int maximumConcurrency) {
super(); super();
try {
this.processingQueue = Synchronization.queue(MinMaxPriorityQueue. this.processingQueue = Synchronization.queue(MinMaxPriorityQueue.
expectedSize(initialSize). expectedSize(initialSize).
maximumSize(maximumSize). maximumSize(maximumSize).
<PacketEventHolder>create(), null); <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.maximumConcurrency = maximumConcurrency;
this.concurrentProcessing = new Semaphore(maximumConcurrency); this.concurrentProcessing = new Semaphore(maximumConcurrency);

Datei anzeigen

@ -164,9 +164,9 @@ class EntityUtilities {
BukkitUnwrapper unwrapper = new BukkitUnwrapper(); BukkitUnwrapper unwrapper = new BukkitUnwrapper();
Object worldServer = unwrapper.unwrapItem(world); Object worldServer = unwrapper.unwrapItem(world);
// We have to rely on the class naming here.
if (entityTrackerField == null) if (entityTrackerField == null)
entityTrackerField = FuzzyReflection.fromObject(worldServer).getFieldByType(".*Tracker"); entityTrackerField = FuzzyReflection.fromObject(worldServer).
getFieldByType("tracker", MinecraftReflection.getEntityTrackerClass());
// Get the tracker // Get the tracker
Object tracker = null; Object tracker = null;
@ -191,7 +191,7 @@ class EntityUtilities {
// The Minecraft field that's NOT filled in by the constructor // The Minecraft field that's NOT filled in by the constructor
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true). trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher(), ignoredTypes); getFieldByType(MinecraftReflection.getMinecraftObjectRegex(), ignoredTypes);
} }
// Read the entity hashmap // Read the entity hashmap
@ -250,8 +250,16 @@ class EntityUtilities {
// Handle NULL cases // Handle NULL cases
if (trackerEntry != null) { if (trackerEntry != null) {
if (trackerField == null) if (trackerField == null) {
try {
trackerField = trackerEntry.getClass().getField("tracker"); 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); tracker = FieldUtils.readField(trackerField, trackerEntry, true);
} }

Datei anzeigen

@ -93,7 +93,7 @@ class PacketInjector {
if (intHashMap == null) { if (intHashMap == null) {
// We're looking for the first static field with a Minecraft-object. This should be a IntHashMap. // We're looking for the first static field with a Minecraft-object. This should be a IntHashMap.
Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true). Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher()); getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
try { try {
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true); intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);

Datei anzeigen

@ -107,12 +107,10 @@ class InjectedServerConnection {
} }
private void injectListenerThread() { private void injectListenerThread() {
try { try {
if (listenerThreadField == null) if (listenerThreadField == null)
listenerThreadField = FuzzyReflection.fromObject(minecraftServer). listenerThreadField = FuzzyReflection.fromObject(minecraftServer).
getFieldByType(".*NetworkListenThread"); getFieldByType("networkListenThread", MinecraftReflection.getNetworkListenThreadClass());
} catch (RuntimeException e) { } catch (RuntimeException e) {
reporter.reportDetailed(this, "Cannot find listener thread in MinecraftServer.", e, minecraftServer); reporter.reportDetailed(this, "Cannot find listener thread in MinecraftServer.", e, minecraftServer);
return; return;

Datei anzeigen

@ -20,7 +20,8 @@ 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.List;
import java.util.Map;
import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer; 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.DefaultInstances;
import com.comphenix.protocol.reflect.instances.ExistingGenerator; import com.comphenix.protocol.reflect.instances.ExistingGenerator;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Maps;
/** /**
* Represents a player hook into the NetServerHandler class. * Represents a player hook into the NetServerHandler class.
@ -91,9 +93,59 @@ public class NetworkServerInjector extends PlayerInjector {
// Get the send packet method! // Get the send packet method!
if (hasInitialized) { if (hasInitialized) {
if (sendPacketMethod == null) if (sendPacketMethod == null) {
try {
sendPacketMethod = FuzzyReflection.fromObject(serverHandler).getMethodByName("sendPacket.*"); 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 @Override
@ -297,7 +349,21 @@ public class NetworkServerInjector extends PlayerInjector {
FieldUtils.writeField(disconnectField, handler, value); FieldUtils.writeField(disconnectField, handler, value);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
reporter.reportDetailed(this, "Unable to find disconnect field. Is ProtocolLib up to date?", e, handler); // 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) { } catch (IllegalAccessException e) {
reporter.reportWarning(this, "Unable to update disconnected field. Player quit event may be sent twice."); reporter.reportWarning(this, "Unable to update disconnected field. Player quit event may be sent twice.");
} }

Datei anzeigen

@ -167,8 +167,8 @@ abstract class PlayerInjector {
// Next, get the network manager // Next, get the network manager
if (networkManagerField == null) if (networkManagerField == null)
networkManagerField = FuzzyReflection.fromObject(serverHandler). networkManagerField = FuzzyReflection.fromObject(serverHandler).getFieldByType(
getFieldByType(".*" + MinecraftReflection.getNetworkManagerName()); "networkManager", MinecraftReflection.getNetworkManagerClass());
initializeNetworkManager(networkManagerField, serverHandler); initializeNetworkManager(networkManagerField, serverHandler);
} }
} }
@ -184,7 +184,7 @@ abstract class PlayerInjector {
if (netLoginNetworkField == null) if (netLoginNetworkField == null)
netLoginNetworkField = FuzzyReflection.fromObject(netLoginHandler). netLoginNetworkField = FuzzyReflection.fromObject(netLoginHandler).
getFieldByType(".*" + MinecraftReflection.getNetworkManagerName()); getFieldByType("networkManager", MinecraftReflection.getNetworkManagerClass());
initializeNetworkManager(netLoginNetworkField, netLoginHandler); initializeNetworkManager(netLoginNetworkField, netLoginHandler);
} }
} }
@ -290,7 +290,13 @@ abstract class PlayerInjector {
// Execute disconnect on it // Execute disconnect on it
if (handler != null) { if (handler != null) {
if (disconnect == null) { if (disconnect == null) {
try {
disconnect = FuzzyReflection.fromObject(handler).getMethodByName("disconnect.*"); 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 // Save the method for later
if (usingNetServer) if (usingNetServer)
@ -380,7 +386,7 @@ abstract class PlayerInjector {
try { try {
// Well, that sucks. Try just Minecraft objects then. // Well, that sucks. Try just Minecraft objects then.
netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true). netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true).
getFieldByType(MinecraftReflection.getMinecraftObjectMatcher()); getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
} catch (RuntimeException e2) { } catch (RuntimeException e2) {
throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage()); throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage());

Datei anzeigen

@ -72,4 +72,64 @@ public abstract class AbstractFuzzyMatcher<T> implements Comparable<AbstractFuzz
// No match // No match
return -1; 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());
}
};
}
} }

Datei anzeigen

@ -13,11 +13,11 @@ import javax.annotation.Nonnull;
*/ */
public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzzyMatcher<T> { public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzzyMatcher<T> {
// Accessibility matchers // Accessibility matchers
private int modifiersRequired; protected int modifiersRequired;
private int modifiersBanned; protected int modifiersBanned;
private Pattern nameRegex; protected Pattern nameRegex;
private AbstractFuzzyMatcher<Class<?>> declaringMatcher = ExactClassMatcher.MATCH_ALL; protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ExactClassMatcher.MATCH_ALL;
/** /**
* Whether or not this contract can be modified. * 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. * @return This builder, for chaining.
*/ */
public Builder<T> declaringClassExactType(Class<?> declaringClass) { public Builder<T> declaringClassExactType(Class<?> declaringClass) {
member.declaringMatcher = ExactClassMatcher.matchExact(declaringClass); member.declaringMatcher = FuzzyMatchers.matchExact(declaringClass);
return this; return this;
} }
@ -99,7 +99,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder<T> declaringClassSuperOf(Class<?> declaringClass) { public Builder<T> declaringClassSuperOf(Class<?> declaringClass) {
member.declaringMatcher = ExactClassMatcher.matchSuper(declaringClass); member.declaringMatcher = FuzzyMatchers.matchSuper(declaringClass);
return this; return this;
} }
@ -109,7 +109,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder<T> declaringClassDerivedOf(Class<?> declaringClass) { public Builder<T> declaringClassDerivedOf(Class<?> declaringClass) {
member.declaringMatcher = ExactClassMatcher.matchDerived(declaringClass); member.declaringMatcher = FuzzyMatchers.matchDerived(declaringClass);
return this; return this;
} }

Datei anzeigen

@ -34,38 +34,12 @@ class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
private final Class<?> matcher; private final Class<?> matcher;
private final Options option; 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. * Constructs a new class matcher.
* @param matcher - the matching class, or NULL to represent anything. * @param matcher - the matching class, or NULL to represent anything.
* @param option - options specifying the matching rules. * @param option - options specifying the matching rules.
*/ */
private ExactClassMatcher(Class<?> matcher, Options option) { ExactClassMatcher(Class<?> matcher, Options option) {
this.matcher = matcher; this.matcher = matcher;
this.option = option; this.option = option;
} }

Datei anzeigen

@ -1,10 +1,10 @@
package com.comphenix.protocol.reflect; package com.comphenix.protocol.reflect;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -107,32 +107,6 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher<Class<?>> {
return new Builder(); 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. * Constructs a new fuzzy class contract with the given contracts.
* @param fieldContracts - field contracts. * @param fieldContracts - field contracts.
@ -197,7 +171,7 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher<Class<?>> {
@Override @Override
public boolean isMatch(Class<?> value, Object parent) { 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 // Make sure all the contracts are valid
return processContracts(reflection.getFields(), value, fieldContracts) && return processContracts(reflection.getFields(), value, fieldContracts) &&

Datei anzeigen

@ -13,6 +13,11 @@ import javax.annotation.Nonnull;
public class FuzzyFieldContract extends AbstractFuzzyMember<Field> { public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
private AbstractFuzzyMatcher<Class<?>> typeMatcher = ExactClassMatcher.MATCH_ALL; private AbstractFuzzyMatcher<Class<?>> typeMatcher = ExactClassMatcher.MATCH_ALL;
/**
* Represents a builder for a field matcher.
*
* @author Kristian
*/
public static class Builder extends AbstractFuzzyMember.Builder<FuzzyFieldContract> { public static class Builder extends AbstractFuzzyMember.Builder<FuzzyFieldContract> {
@Override @Override
public Builder requireModifier(int modifier) { public Builder requireModifier(int modifier) {
@ -74,12 +79,22 @@ public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
} }
public Builder typeExact(Class<?> type) { public Builder typeExact(Class<?> type) {
member.typeMatcher = ExactClassMatcher.matchExact(type); member.typeMatcher = FuzzyMatchers.matchExact(type);
return this; return this;
} }
public Builder typeSuperOf(Class<?> type) { 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; 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() { public static Builder newBuilder() {
return new Builder(); return new Builder();
} }

Datei anzeigen

@ -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;
}
};
}
}

Datei anzeigen

@ -85,6 +85,11 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
// Expected parameter count // Expected parameter count
private Integer paramCount; private Integer paramCount;
/**
* Represents a builder for a fuzzy method contract.
*
* @author Kristian
*/
public static class Builder extends AbstractFuzzyMember.Builder<FuzzyMethodContract> { public static class Builder extends AbstractFuzzyMember.Builder<FuzzyMethodContract> {
public Builder requireModifier(int modifier) { public Builder requireModifier(int modifier) {
super.requireModifier(modifier); super.requireModifier(modifier);
@ -145,19 +150,19 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder parameterExactType(Class<?> type) { public Builder parameterExactType(Class<?> type) {
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type))); member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
return this; 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> * <p>
* If a parameter is of type Number, any derived class (Integer, Long, etc.) will match it. * 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. * @param type - a type or derived type of the matching parameter.
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder parameterSuperOf(Class<?> type) { public Builder parameterSuperOf(Class<?> type) {
member.paramMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type))); member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
return this; return this;
} }
@ -178,7 +183,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder parameterExactType(Class<?> type, int index) { 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; return this;
} }
@ -191,7 +196,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder parameterSuperOf(Class<?> type, int index) { 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; return this;
} }
@ -230,7 +235,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder returnTypeExact(Class<?> type) { public Builder returnTypeExact(Class<?> type) {
member.returnMatcher = ExactClassMatcher.matchExact(type); member.returnMatcher = FuzzyMatchers.matchExact(type);
return this; return this;
} }
@ -240,7 +245,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder returnDerivedOf(Class<?> type) { public Builder returnDerivedOf(Class<?> type) {
member.returnMatcher = ExactClassMatcher.matchDerived(type); member.returnMatcher = FuzzyMatchers.matchDerived(type);
return this; return this;
} }
@ -260,7 +265,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder exceptionExactType(Class<?> type) { public Builder exceptionExactType(Class<?> type) {
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchExact(type))); member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
return this; return this;
} }
@ -270,7 +275,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder exceptionSuperOf(Class<?> type) { public Builder exceptionSuperOf(Class<?> type) {
member.exceptionMatchers.add(new ParameterClassMatcher(ExactClassMatcher.matchSuper(type))); member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
return this; return this;
} }
@ -291,7 +296,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder exceptionExactType(Class<?> type, int index) { 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; return this;
} }
@ -302,7 +307,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
* @return This builder, for chaining. * @return This builder, for chaining.
*/ */
public Builder exceptionSuperOf(Class<?> type, int index) { 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; 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() { public static Builder newBuilder() {
return new Builder(); return new Builder();
} }

Datei anzeigen

@ -254,7 +254,6 @@ public class FuzzyReflection {
* @throws IllegalArgumentException If the field cannot be found. * @throws IllegalArgumentException If the field cannot be found.
*/ */
public Field getFieldByName(String nameRegex) { public Field getFieldByName(String nameRegex) {
Pattern match = Pattern.compile(nameRegex); Pattern match = Pattern.compile(nameRegex);
for (Field field : getFields()) { 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. * @return The first field with a type that is an instance of the given type.
*/ */
public Field getFieldByType(String name, Class<?> type) { public Field getFieldByType(String name, Class<?> type) {
List<Field> fields = getFieldListByType(type); List<Field> fields = getFieldListByType(type);
if (fields.size() > 0) { 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. * @return Every field with a type that is an instance of the given type.
*/ */
public List<Field> getFieldListByType(Class<?> type) { public List<Field> getFieldListByType(Class<?> type) {
List<Field> fields = new ArrayList<Field>(); List<Field> fields = new ArrayList<Field>();
// Field with a compatible type // Field with a compatible type

Datei anzeigen

@ -17,9 +17,17 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; 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 java.util.regex.Pattern;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -29,6 +37,13 @@ import org.bukkit.Server;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.injector.BukkitUnwrapper; 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; import com.google.common.base.Joiner;
/** /**
@ -40,7 +55,7 @@ public class MinecraftReflection {
/** /**
* Regular expression that matches a Minecraft object. * Regular expression that matches a Minecraft object.
* <p> * <p>
* Replaced by the method {@link #getMinecraftObjectMatcher()}. * Replaced by the method {@link #getMinecraftObjectRegex()}.
*/ */
@Deprecated @Deprecated
public static final String MINECRAFT_OBJECT = "net\\.minecraft(\\.\\w+)+"; 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. * Retrieve a regular expression that can match Minecraft package objects.
* @return Minecraft package matcher. * @return Minecraft package matcher.
*/ */
public static String getMinecraftObjectMatcher() { public static String getMinecraftObjectRegex() {
if (DYNAMIC_PACKAGE_MATCHER == null) if (DYNAMIC_PACKAGE_MATCHER == null)
getMinecraftPackage(); getMinecraftPackage();
return DYNAMIC_PACKAGE_MATCHER; 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. * Retrieve the name of the Minecraft server package.
* @return Full canonical 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 = DYNAMIC_PACKAGE_MATCHER =
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ? (MINECRAFT_PREFIX_PACKAGE.length() > 0 ?
Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + "\\w+"; Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + "\\w+";
// We'll still accept the default location, however
DYNAMIC_PACKAGE_MATCHER = "(" + DYNAMIC_PACKAGE_MATCHER + ")|(" + MINECRAFT_OBJECT + ")";
} else { } else {
// Use the standard matcher // Use the standard matcher
DYNAMIC_PACKAGE_MATCHER = MINECRAFT_OBJECT; DYNAMIC_PACKAGE_MATCHER = MINECRAFT_OBJECT;
@ -146,6 +173,9 @@ public class MinecraftReflection {
public static void setMinecraftPackage(String minecraftPackage, String craftBukkitPackage) { public static void setMinecraftPackage(String minecraftPackage, String craftBukkitPackage) {
MINECRAFT_FULL_PACKAGE = minecraftPackage; MINECRAFT_FULL_PACKAGE = minecraftPackage;
CRAFTBUKKIT_PACKAGE = craftBukkitPackage; CRAFTBUKKIT_PACKAGE = craftBukkitPackage;
// Standard matcher
DYNAMIC_PACKAGE_MATCHER = MINECRAFT_OBJECT;
} }
/** /**
@ -325,7 +355,22 @@ public class MinecraftReflection {
* @return The entity class. * @return The entity class.
*/ */
public static Class<?> getEntityPlayerClass() { public static Class<?> getEntityPlayerClass() {
try {
return getMinecraftClass("EntityPlayer"); 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. * @return The entity class.
*/ */
public static Class<?> getEntityClass() { public static Class<?> getEntityClass() {
try {
return getMinecraftClass("Entity"); 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,7 +417,75 @@ public class MinecraftReflection {
* @return The packet class. * @return The packet class.
*/ */
public static Class<?> getPacketClass() { public static Class<?> getPacketClass() {
try {
return getMinecraftClass("Packet"); 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];
}
} }
/** /**
@ -349,7 +493,13 @@ public class MinecraftReflection {
* @return The player list class. * @return The player list class.
*/ */
public static Class<?> getPlayerListClass() { public static Class<?> getPlayerListClass() {
try {
return getMinecraftClass("ServerConfigurationManager", "PlayerList"); return getMinecraftClass("ServerConfigurationManager", "PlayerList");
} catch (RuntimeException e) {
// Try again
getMinecraftServerClass();
return getMinecraftClass("ServerConfigurationManager");
}
} }
/** /**
@ -357,7 +507,22 @@ public class MinecraftReflection {
* @return The NetLoginHandler class. * @return The NetLoginHandler class.
*/ */
public static Class<?> getNetLoginHandlerClass() { public static Class<?> getNetLoginHandlerClass() {
try {
return getMinecraftClass("NetLoginHandler", "PendingConnection"); 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. * @return The NetServerHandler class.
*/ */
public static Class<?> getNetServerHandlerClass() { public static Class<?> getNetServerHandlerClass() {
try {
return getMinecraftClass("NetServerHandler", "PlayerConnection"); 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. * Retrieve the NetworkManager class or its interface.
* @return The NetworkManager class. * @return The NetworkManager class or its interface.
*/ */
public static Class<?> getNetworkManagerClass() { 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. * @return The NetHandler class.
*/ */
public static Class<?> getNetHandlerClass() { public static Class<?> getNetHandlerClass() {
try {
return getMinecraftClass("NetHandler", "Connection"); return getMinecraftClass("NetHandler", "Connection");
} catch (RuntimeException e) {
return setMinecraftClass("NetHandler", getNetLoginHandlerClass().getSuperclass());
}
} }
/** /**
@ -389,7 +578,13 @@ public class MinecraftReflection {
* @return The ItemStack class. * @return The ItemStack class.
*/ */
public static Class<?> getItemStackClass() { public static Class<?> getItemStackClass() {
try {
return getMinecraftClass("ItemStack"); 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. * @return The WorldType class.
*/ */
public static Class<?> getWorldTypeClass() { public static Class<?> getWorldTypeClass() {
try {
return getMinecraftClass("WorldType"); 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]);
} }
/**
* Retrieve the MinecraftServer class.
* @return MinecraftServer class.
*/
public static Class<?> getMinecraftServerClass() {
return getMinecraftClass("MinecraftServer");
} }
/** /**
@ -413,7 +614,33 @@ public class MinecraftReflection {
* @return The DataWatcher class. * @return The DataWatcher class.
*/ */
public static Class<?> getDataWatcherClass() { public static Class<?> getDataWatcherClass() {
try {
return getMinecraftClass("DataWatcher"); 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. * @return The ChunkPosition class.
*/ */
public static Class<?> getChunkPositionClass() { public static Class<?> getChunkPositionClass() {
try {
return getMinecraftClass("ChunkPosition"); 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. * @return The ChunkPosition class.
*/ */
public static Class<?> getChunkCoordinatesClass() { public static Class<?> getChunkCoordinatesClass() {
try {
return getMinecraftClass("ChunkCoordinates"); return getMinecraftClass("ChunkCoordinates");
} catch (RuntimeException e) {
return setMinecraftClass("ChunkCoordinates", WrappedDataWatcher.getTypeClass(6));
}
} }
/** /**
@ -437,7 +686,19 @@ public class MinecraftReflection {
* @return The WatchableObject class. * @return The WatchableObject class.
*/ */
public static Class<?> getWatchableObjectClass() { public static Class<?> getWatchableObjectClass() {
try {
return getMinecraftClass("WatchableObject"); 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. * @return The ServerConnection class.
*/ */
public static Class<?> getServerConnectionClass() { public static Class<?> getServerConnectionClass() {
try {
return getMinecraftClass("ServerConnection"); 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. * @return The NBT base class.
*/ */
public static Class<?> getNBTBaseClass() { public static Class<?> getNBTBaseClass() {
try {
return getMinecraftClass("NBTBase"); 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); 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. * Retrieve the first class that matches a specified Minecraft name.
* @param className - the specific Minecraft class. * @param className - the specific Minecraft class.