Another diffcult to track down bug.
Dieser Commit ist enthalten in:
Ursprung
1c41f83305
Commit
6063f437fd
@ -3,11 +3,17 @@ package com.comphenix.protocol.async;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.server.Packet;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketStream;
|
import com.comphenix.protocol.PacketStream;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.injector.PrioritizedListener;
|
import com.comphenix.protocol.injector.PrioritizedListener;
|
||||||
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +65,10 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
|||||||
// Whether or not the asynchronous processing itself should be cancelled
|
// Whether or not the asynchronous processing itself should be cancelled
|
||||||
private volatile boolean asyncCancelled;
|
private volatile boolean asyncCancelled;
|
||||||
|
|
||||||
|
// Determine if Minecraft processes this packet asynchronously
|
||||||
|
private static Method isMinecraftAsync;
|
||||||
|
private static boolean alwaysSync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a container for asyncronous packets.
|
* Create a container for asyncronous packets.
|
||||||
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
|
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
|
||||||
@ -240,6 +250,49 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if Minecraft allows asynchronous processing of this packet.
|
||||||
|
* @return TRUE if it does, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isMinecraftAsync(PacketEvent event) throws FieldAccessException {
|
||||||
|
|
||||||
|
if (isMinecraftAsync == null) {
|
||||||
|
try {
|
||||||
|
isMinecraftAsync = FuzzyReflection.fromClass(Packet.class).getMethodByName("a_.*");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// This will occur in 1.2.5 (or possibly in later versions)
|
||||||
|
List<Method> methods = FuzzyReflection.fromClass(Packet.class).
|
||||||
|
getMethodListByParameters(boolean.class, new Class[] {});
|
||||||
|
|
||||||
|
// Try to look for boolean methods
|
||||||
|
if (methods.size() == 2) {
|
||||||
|
isMinecraftAsync = methods.get(1);
|
||||||
|
} else if (methods.size() == 1) {
|
||||||
|
// We're in 1.2.5
|
||||||
|
alwaysSync = true;
|
||||||
|
} else {
|
||||||
|
System.err.println("Cannot determine asynchronous state of packets!");
|
||||||
|
alwaysSync = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alwaysSync) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
// Wrap exceptions
|
||||||
|
return (Boolean) isMinecraftAsync.invoke(event.getPacket().getHandle());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new FieldAccessException("Illegal argument", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new FieldAccessException("Unable to reflect method call 'a_', or: isAsyncPacket.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new FieldAccessException("Minecraft error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(AsyncMarker o) {
|
public int compareTo(AsyncMarker o) {
|
||||||
if (o == null)
|
if (o == null)
|
||||||
|
@ -8,6 +8,7 @@ import java.util.Set;
|
|||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.google.common.collect.ComparisonChain;
|
import com.google.common.collect.ComparisonChain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,10 +86,6 @@ class PacketSendingQueue {
|
|||||||
*/
|
*/
|
||||||
public void trySendPackets(boolean onMainThread) {
|
public void trySendPackets(boolean onMainThread) {
|
||||||
|
|
||||||
// Abort if we're not on the main thread
|
|
||||||
if (synchronizeMain && !onMainThread)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Transmit as many packets as we can
|
// Transmit as many packets as we can
|
||||||
while (true) {
|
while (true) {
|
||||||
PacketEvent current = sendingQueue.peek();
|
PacketEvent current = sendingQueue.peek();
|
||||||
@ -96,6 +93,22 @@ class PacketSendingQueue {
|
|||||||
if (current != null) {
|
if (current != null) {
|
||||||
AsyncMarker marker = current.getAsyncMarker();
|
AsyncMarker marker = current.getAsyncMarker();
|
||||||
|
|
||||||
|
// Abort if we're not on the main thread
|
||||||
|
if (synchronizeMain) {
|
||||||
|
try {
|
||||||
|
boolean wantAsync = marker.isMinecraftAsync(current);
|
||||||
|
boolean wantSync = !wantAsync;
|
||||||
|
|
||||||
|
// Quit if we haven't fulfilled our promise
|
||||||
|
if ((onMainThread && wantAsync) || (!onMainThread && wantSync))
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (FieldAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (marker.isProcessed() || marker.hasExpired()) {
|
if (marker.isProcessed() || marker.hasExpired()) {
|
||||||
if (marker.isProcessed() && !current.isCancelled()) {
|
if (marker.isProcessed() && !current.isCancelled()) {
|
||||||
sendPacket(current);
|
sendPacket(current);
|
||||||
|
@ -77,9 +77,14 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
if (override.containsKey(thisObj)) {
|
if (override.containsKey(thisObj)) {
|
||||||
Object overridenObject = override.get(thisObj);
|
Object overridenObject = override.get(thisObj);
|
||||||
|
|
||||||
// Cancel EVERYTHING, including "processPacket"
|
// This packet has been cancelled
|
||||||
if (overridenObject == null)
|
if (overridenObject == null) {
|
||||||
return null;
|
// So, cancel all void methods
|
||||||
|
if (method.getReturnType().equals(Void.TYPE))
|
||||||
|
return null;
|
||||||
|
else // Revert to normal for everything else
|
||||||
|
overridenObject = thisObj;
|
||||||
|
}
|
||||||
|
|
||||||
returnValue = proxy.invokeSuper(overridenObject, args);
|
returnValue = proxy.invokeSuper(overridenObject, args);
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,8 +19,10 @@ package com.comphenix.protocol.reflect;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -96,6 +98,7 @@ public class FuzzyReflection {
|
|||||||
* Retrieves a method by looking at its name.
|
* Retrieves a method by looking at its name.
|
||||||
* @param nameRegex - regular expression that will match method names.
|
* @param nameRegex - regular expression that will match method names.
|
||||||
* @return The first method that satisfies the regular expression.
|
* @return The first method that satisfies the regular expression.
|
||||||
|
* @throws RuntimeException If the method cannot be found.
|
||||||
*/
|
*/
|
||||||
public Method getMethodByName(String nameRegex) {
|
public Method getMethodByName(String nameRegex) {
|
||||||
|
|
||||||
@ -151,6 +154,26 @@ public class FuzzyReflection {
|
|||||||
throw new RuntimeException("Unable to find " + name + " in " + source.getName());
|
throw new RuntimeException("Unable to find " + name + " in " + source.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves every method that has the given parameter types and return type.
|
||||||
|
* @param returnType - return type of the method to find.
|
||||||
|
* @param args - parameter types of the method to find.
|
||||||
|
* @return Every method that satisfies the given constraints.
|
||||||
|
*/
|
||||||
|
public List<Method> getMethodListByParameters(Class<?> returnType, Class<?>[] args) {
|
||||||
|
|
||||||
|
List<Method> methods = new ArrayList<Method>();
|
||||||
|
|
||||||
|
// Find the correct method to call
|
||||||
|
for (Method method : getMethods()) {
|
||||||
|
if (method.getReturnType().equals(returnType) && Arrays.equals(method.getParameterTypes(), args)) {
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a field by name.
|
* Retrieves a field by name.
|
||||||
* @param nameRegex - regular expression that will match a field name.
|
* @param nameRegex - regular expression that will match a field name.
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren