Correct a missing noEntryValue in Spigot.

Again.
This commit is contained in:
Kristian S. Stangeland 2013-12-14 04:39:12 +01:00
parent 9b349299a0
commit 85d415de7c
5 changed files with 70 additions and 24 deletions

View File

@ -35,7 +35,6 @@ import com.comphenix.protocol.injector.spigot.AbstractPacketInjector;
import com.comphenix.protocol.injector.spigot.AbstractPlayerHandler;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Lists;

View File

@ -20,6 +20,7 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.TroveWrapper;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -164,18 +165,16 @@ class LegacyPacketRegistry {
FuzzyFieldContract.newBuilder().typeMatches(mapLike).build());
Object troveMap = FieldUtils.readStaticField(packetsField, true);
// Check for stupid no_entry_values
try {
Field field = FieldUtils.getField(troveMap.getClass(), "no_entry_value", true);
Integer value = (Integer) FieldUtils.readField(field, troveMap, true);
// Fix incorrect no entry values
TroveWrapper.transformNoEntryValue(troveMap, new Function<Integer, Integer>() {
public Integer apply(Integer value) {
if (value >= 0 && value < 256) {
// Someone forgot to set the no entry value. Let's help them.
FieldUtils.writeField(field, troveMap, -1);
return -1;
}
} catch (IllegalArgumentException e) {
throw new CannotCorrectTroveMapException(e);
return value;
}
});
// We'll assume this a Trove map
return TroveWrapper.getDecoratedMap(troveMap);
@ -333,12 +332,4 @@ class LegacyPacketRegistry {
return packetCount;
}
}
public static class CannotCorrectTroveMapException extends RuntimeException {
private static final long serialVersionUID = 1L;
private CannotCorrectTroveMapException(Throwable inner) {
super("Cannot correct trove map.", inner);
}
}
}

View File

@ -28,10 +28,10 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.CannotCorrectTroveMapException;
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.TroveWrapper.CannotFindTroveNoEntryValue;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -119,7 +119,7 @@ public class PacketRegistry {
PacketRegistry.class, Report.newBuilder(REPORT_INSUFFICIENT_SERVER_PACKETS).messageParam(e.getPacketCount())
);
}
} catch (CannotCorrectTroveMapException e) {
} catch (CannotFindTroveNoEntryValue e) {
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class,
Report.newBuilder(REPORT_CANNOT_CORRECT_TROVE_MAP).error(e.getCause()));
}

View File

@ -10,11 +10,13 @@ import java.util.Set;
import javax.annotation.Nonnull;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.ReadOnlyFieldAccessor;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
import com.comphenix.protocol.utility.ClassSource;
import com.google.common.base.Function;
/**
* Wrap a GNU Trove Collection class with an equivalent Java Collection class.
@ -38,9 +40,24 @@ public class TroveWrapper {
* @return The read only accessor.
*/
public static ReadOnlyFieldAccessor wrapMapField(final FieldAccessor accessor) {
return wrapMapField(accessor, null);
}
/**
* Retrieve a read-only field accessor that automatically wraps the underlying Trove instance.
* @param accessor - the accessor.
* @param noEntryTransform - transform the no entry value, or NULL to ignore.
* @return The read only accessor.
*/
public static ReadOnlyFieldAccessor wrapMapField(final FieldAccessor accessor, final Function<Integer, Integer> noEntryTransform) {
return new ReadOnlyFieldAccessor() {
public Object get(Object instance) {
return getDecoratedMap(accessor.get(instance));
Object troveMap = accessor.get(instance);
// Apply transform as well
if (noEntryTransform != null)
TroveWrapper.transformNoEntryValue(troveMap, noEntryTransform);
return getDecoratedMap(troveMap);
}
public Field getField() {
return accessor.getField();
@ -131,6 +148,28 @@ public class TroveWrapper {
return getClassSource(clazz) != null;
}
/**
* Transform the no entry value in the given map.
* @param troveMap - the trove map.
* @param transform - the transform.
*/
public static void transformNoEntryValue(Object troveMap, Function<Integer, Integer> transform) {
// Check for stupid no_entry_values
try {
Field field = FieldUtils.getField(troveMap.getClass(), "no_entry_value", true);
int current = (Integer) FieldUtils.readField(field, troveMap, true);
int transformed = transform.apply(current);
if (current != transformed) {
FieldUtils.writeField(field, troveMap, transformed);
}
} catch (IllegalArgumentException e) {
throw new CannotFindTroveNoEntryValue(e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot access reflection.", e);
}
}
/**
* Retrieve the correct class source from the given class.
* @param clazz - the class source.
@ -189,4 +228,12 @@ public class TroveWrapper {
throw new IllegalArgumentException("Cannot find decorator for " + trove + " (" + trove.getClass() + ")");
}
public static class CannotFindTroveNoEntryValue extends RuntimeException {
private static final long serialVersionUID = 1L;
private CannotFindTroveNoEntryValue(Throwable inner) {
super("Cannot correct trove map.", inner);
}
}
}

View File

@ -598,7 +598,16 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
if (TroveWrapper.isTroveClass(type)) {
// Create a wrapper accessor
final ReadOnlyFieldAccessor accessor = TroveWrapper.wrapMapField(Accessors.getFieldAccessor(lookup, true));
final ReadOnlyFieldAccessor accessor = TroveWrapper.wrapMapField(
Accessors.getFieldAccessor(lookup, true), new Function<Integer, Integer>() {
@Override
public Integer apply(@Nullable Integer value) {
// Do not use zero for no entry value
if (value == 0)
return -1;
return value;
}
});
if (Modifier.isStatic(lookup.getModifiers())) {
TYPE_MAP_ACCESSOR = accessor;