Archiviert
13
0

Another diffcult to track down bug.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-09-30 04:24:27 +02:00
Ursprung 1c41f83305
Commit 6063f437fd
4 geänderte Dateien mit 103 neuen und 9 gelöschten Zeilen

Datei anzeigen

@ -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)

Datei anzeigen

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

Datei anzeigen

@ -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) {
// So, cancel all void methods
if (method.getReturnType().equals(Void.TYPE))
return null; return null;
else // Revert to normal for everything else
overridenObject = thisObj;
}
returnValue = proxy.invokeSuper(overridenObject, args); returnValue = proxy.invokeSuper(overridenObject, args);
} else { } else {

Datei anzeigen

@ -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.