Allow packet constructor to properly unwrap other Bukkit wrappers.
Dieser Commit ist enthalten in:
Ursprung
ba6c6e5abf
Commit
86f04f53b5
@ -77,7 +77,11 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
// Special case
|
// Special case
|
||||||
if (wrappedObject == null)
|
if (wrappedObject == null)
|
||||||
return null;
|
return null;
|
||||||
Class<?> currentClass = wrappedObject.getClass();
|
Class<?> currentClass = PacketConstructor.getClass(wrappedObject);
|
||||||
|
|
||||||
|
// No need to unwrap primitives
|
||||||
|
if (currentClass.isPrimitive() || currentClass.equals(String.class))
|
||||||
|
return null;
|
||||||
|
|
||||||
// Next, check for types that doesn't have a getHandle()
|
// Next, check for types that doesn't have a getHandle()
|
||||||
if (wrappedObject instanceof Collection) {
|
if (wrappedObject instanceof Collection) {
|
||||||
@ -119,7 +123,7 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
* @param type - the type of the class.
|
* @param type - the type of the class.
|
||||||
* @return An unwrapper for the given class.
|
* @return An unwrapper for the given class.
|
||||||
*/
|
*/
|
||||||
private Unwrapper getSpecificUnwrapper(Class<?> type) {
|
private Unwrapper getSpecificUnwrapper(final Class<?> type) {
|
||||||
// See if we're already determined this
|
// See if we're already determined this
|
||||||
if (unwrapperCache.containsKey(type)) {
|
if (unwrapperCache.containsKey(type)) {
|
||||||
// We will never remove from the cache, so this ought to be thread safe
|
// We will never remove from the cache, so this ought to be thread safe
|
||||||
@ -133,8 +137,9 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
Unwrapper methodUnwrapper = new Unwrapper() {
|
Unwrapper methodUnwrapper = new Unwrapper() {
|
||||||
@Override
|
@Override
|
||||||
public Object unwrapItem(Object wrappedObject) {
|
public Object unwrapItem(Object wrappedObject) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (wrappedObject instanceof Class)
|
||||||
|
return checkClass((Class<?>) wrappedObject, type, find.getReturnType());
|
||||||
return find.invoke(wrappedObject);
|
return find.invoke(wrappedObject);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@ -180,7 +185,7 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
* @param type - a cached field unwrapper.
|
* @param type - a cached field unwrapper.
|
||||||
* @return The cached field unwrapper.
|
* @return The cached field unwrapper.
|
||||||
*/
|
*/
|
||||||
private Unwrapper getFieldUnwrapper(Class<?> type) {
|
private Unwrapper getFieldUnwrapper(final Class<?> type) {
|
||||||
final Field find = FieldUtils.getField(type, "handle", true);
|
final Field find = FieldUtils.getField(type, "handle", true);
|
||||||
|
|
||||||
// See if we succeeded
|
// See if we succeeded
|
||||||
@ -189,6 +194,8 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
@Override
|
@Override
|
||||||
public Object unwrapItem(Object wrappedObject) {
|
public Object unwrapItem(Object wrappedObject) {
|
||||||
try {
|
try {
|
||||||
|
if (wrappedObject instanceof Class)
|
||||||
|
return checkClass((Class<?>) wrappedObject, type, find.getType());
|
||||||
return FieldUtils.readField(find, wrappedObject, true);
|
return FieldUtils.readField(find, wrappedObject, true);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportDetailed(this,
|
reporter.reportDetailed(this,
|
||||||
@ -210,4 +217,11 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Class<?> checkClass(Class<?> input, Class<?> expected, Class<?> result) {
|
||||||
|
if (expected.isAssignableFrom(input)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import com.comphenix.protocol.error.RethrowErrorReporter;
|
|||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
@ -53,18 +54,19 @@ public class PacketConstructor {
|
|||||||
private List<Unwrapper> unwrappers;
|
private List<Unwrapper> unwrappers;
|
||||||
|
|
||||||
// Parameters that need to be unwrapped
|
// Parameters that need to be unwrapped
|
||||||
private boolean[] unwrappable;
|
private Unwrapper[] paramUnwrapper;
|
||||||
|
|
||||||
private PacketConstructor(Constructor<?> constructorMethod) {
|
private PacketConstructor(Constructor<?> constructorMethod) {
|
||||||
this.constructorMethod = constructorMethod;
|
this.constructorMethod = constructorMethod;
|
||||||
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper(new RethrowErrorReporter() ));
|
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper(new RethrowErrorReporter() ));
|
||||||
|
this.unwrappers.addAll(BukkitConverters.getUnwrappers());
|
||||||
}
|
}
|
||||||
|
|
||||||
private PacketConstructor(int packetID, Constructor<?> constructorMethod, List<Unwrapper> unwrappers, boolean[] unwrappable) {
|
private PacketConstructor(int packetID, Constructor<?> constructorMethod, List<Unwrapper> unwrappers, Unwrapper[] paramUnwrapper) {
|
||||||
this.packetID = packetID;
|
this.packetID = packetID;
|
||||||
this.constructorMethod = constructorMethod;
|
this.constructorMethod = constructorMethod;
|
||||||
this.unwrappers = unwrappers;
|
this.unwrappers = unwrappers;
|
||||||
this.unwrappable = unwrappable;
|
this.paramUnwrapper = paramUnwrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableList<Unwrapper> getUnwrappers() {
|
public ImmutableList<Unwrapper> getUnwrappers() {
|
||||||
@ -85,7 +87,7 @@ public class PacketConstructor {
|
|||||||
* @return A constructor with a different set of unwrappers.
|
* @return A constructor with a different set of unwrappers.
|
||||||
*/
|
*/
|
||||||
public PacketConstructor withUnwrappers(List<Unwrapper> unwrappers) {
|
public PacketConstructor withUnwrappers(List<Unwrapper> unwrappers) {
|
||||||
return new PacketConstructor(packetID, constructorMethod, unwrappers, unwrappable);
|
return new PacketConstructor(packetID, constructorMethod, unwrappers, paramUnwrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,12 +102,12 @@ public class PacketConstructor {
|
|||||||
public PacketConstructor withPacket(int id, Object[] values) {
|
public PacketConstructor withPacket(int id, Object[] values) {
|
||||||
Class<?>[] types = new Class<?>[values.length];
|
Class<?>[] types = new Class<?>[values.length];
|
||||||
Throwable lastException = null;
|
Throwable lastException = null;
|
||||||
boolean[] unwrappable = new boolean[values.length];
|
Unwrapper[] paramUnwrapper = new Unwrapper[values.length];
|
||||||
|
|
||||||
for (int i = 0; i < types.length; i++) {
|
for (int i = 0; i < types.length; i++) {
|
||||||
// Default type
|
// Default type
|
||||||
if (values[i] != null) {
|
if (values[i] != null) {
|
||||||
types[i] = (values[i] instanceof Class) ? (Class<?>)values[i] : values[i].getClass();
|
types[i] = PacketConstructor.getClass(values[i]);
|
||||||
|
|
||||||
for (Unwrapper unwrapper : unwrappers) {
|
for (Unwrapper unwrapper : unwrappers) {
|
||||||
Object result = null;
|
Object result = null;
|
||||||
@ -118,8 +120,8 @@ public class PacketConstructor {
|
|||||||
|
|
||||||
// Update type we're searching for
|
// Update type we're searching for
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
types[i] = result.getClass();
|
types[i] = PacketConstructor.getClass(result);
|
||||||
unwrappable[i] = true;
|
paramUnwrapper[i] = unwrapper;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +143,7 @@ public class PacketConstructor {
|
|||||||
|
|
||||||
if (isCompatible(types, params)) {
|
if (isCompatible(types, params)) {
|
||||||
// Right, we've found our type
|
// Right, we've found our type
|
||||||
return new PacketConstructor(id, constructor, unwrappers, unwrappable);
|
return new PacketConstructor(id, constructor, unwrappers, paramUnwrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,15 +162,8 @@ public class PacketConstructor {
|
|||||||
try {
|
try {
|
||||||
// Convert types that needs to be converted
|
// Convert types that needs to be converted
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
if (unwrappable[i]) {
|
if (paramUnwrapper[i] != null) {
|
||||||
for (Unwrapper unwrapper : unwrappers) {
|
values[i] = paramUnwrapper[i].unwrapItem(values[i]);
|
||||||
Object converted = unwrapper.unwrapItem(values[i]);
|
|
||||||
|
|
||||||
if (converted != null) {
|
|
||||||
values[i] = converted;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +191,7 @@ public class PacketConstructor {
|
|||||||
Class<?> paramType = params[i];
|
Class<?> paramType = params[i];
|
||||||
|
|
||||||
// The input type is always wrapped
|
// The input type is always wrapped
|
||||||
if (paramType.isPrimitive()) {
|
if (!inputType.isPrimitive() && paramType.isPrimitive()) {
|
||||||
// Wrap it
|
// Wrap it
|
||||||
paramType = Primitives.wrap(paramType);
|
paramType = Primitives.wrap(paramType);
|
||||||
}
|
}
|
||||||
@ -213,6 +208,17 @@ public class PacketConstructor {
|
|||||||
// Parameter count must match
|
// Parameter count must match
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the class of an object, or just the class if it already is a class object.
|
||||||
|
* @param obj - the object.
|
||||||
|
* @return The class of an object.
|
||||||
|
*/
|
||||||
|
public static Class<?> getClass(Object obj) {
|
||||||
|
if (obj instanceof Class)
|
||||||
|
return (Class<?>) obj;
|
||||||
|
return obj.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a unwrapper for a constructor parameter.
|
* Represents a unwrapper for a constructor parameter.
|
||||||
@ -222,8 +228,11 @@ public class PacketConstructor {
|
|||||||
public static interface Unwrapper {
|
public static interface Unwrapper {
|
||||||
/**
|
/**
|
||||||
* Convert the given wrapped object to the equivalent net.minecraft.server object.
|
* Convert the given wrapped object to the equivalent net.minecraft.server object.
|
||||||
* @param wrappedObject - wrapped object.
|
* <p>
|
||||||
* @return The net.minecraft.server object.
|
* Note that we may pass in a class instead of object - in that case, the unwrapper should
|
||||||
|
* return the equivalent NMS class.
|
||||||
|
* @param wrappedObject - wrapped object or class.
|
||||||
|
* @return The equivalent net.minecraft.server object or class.
|
||||||
*/
|
*/
|
||||||
public Object unwrapItem(Object wrappedObject);
|
public Object unwrapItem(Object wrappedObject);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ package com.comphenix.protocol.reflect;
|
|||||||
public interface EquivalentConverter<TType> {
|
public interface EquivalentConverter<TType> {
|
||||||
/**
|
/**
|
||||||
* Retrieve a copy of the specific type using an instance of the generic type.
|
* Retrieve a copy of the specific type using an instance of the generic type.
|
||||||
|
* <p>
|
||||||
|
* This is usually a wrapper type in the Bukkit API.
|
||||||
* @param generic - the generic type.
|
* @param generic - the generic type.
|
||||||
* @return The new specific type.
|
* @return The new specific type.
|
||||||
*/
|
*/
|
||||||
@ -33,6 +35,8 @@ public interface EquivalentConverter<TType> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a copy of the generic type from a specific type.
|
* Retrieve a copy of the generic type from a specific type.
|
||||||
|
* <p>
|
||||||
|
* This is usually a native net.minecraft.server type in Minecraft.
|
||||||
* @param genericType - class or super class of the generic type.
|
* @param genericType - class or super class of the generic type.
|
||||||
* @param specific - the specific type we need to copy.
|
* @param specific - the specific type we need to copy.
|
||||||
* @return A copy of the specific type.
|
* @return A copy of the specific type.
|
||||||
|
@ -43,6 +43,7 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.Packets;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
import com.comphenix.protocol.error.Report;
|
import com.comphenix.protocol.error.Report;
|
||||||
@ -1120,6 +1121,27 @@ public class MinecraftReflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the net.minecraft.server.MobEffect class.
|
||||||
|
* @return The mob effect class.
|
||||||
|
*/
|
||||||
|
public static Class<?> getMobEffectClass() {
|
||||||
|
try {
|
||||||
|
return getMinecraftClass("MobEffect");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// It is the second parameter in Packet41MobEffect
|
||||||
|
Class<?> packet = PacketRegistry.getPacketClassFromID(Packets.Server.MOB_EFFECT);
|
||||||
|
Constructor<?> constructor = FuzzyReflection.fromClass(packet).getConstructor(
|
||||||
|
FuzzyMethodContract.newBuilder().
|
||||||
|
parameterCount(2).
|
||||||
|
parameterExactType(int.class, 0).
|
||||||
|
parameterMatches(getMinecraftObjectMatcher(), 1).
|
||||||
|
build()
|
||||||
|
);
|
||||||
|
return setMinecraftClass("MobEffect", constructor.getParameterTypes()[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a given method retrieved by ASM is a constructor.
|
* Determine if a given method retrieved by ASM is a constructor.
|
||||||
* @param name - the name of the method.
|
* @param name - the name of the method.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -28,18 +29,24 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
import com.comphenix.protocol.ProtocolManager;
|
import com.comphenix.protocol.ProtocolManager;
|
||||||
|
import com.comphenix.protocol.injector.PacketConstructor;
|
||||||
|
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,11 +62,16 @@ public class BukkitConverters {
|
|||||||
// The static maps
|
// The static maps
|
||||||
private static Map<Class<?>, EquivalentConverter<Object>> specificConverters;
|
private static Map<Class<?>, EquivalentConverter<Object>> specificConverters;
|
||||||
private static Map<Class<?>, EquivalentConverter<Object>> genericConverters;
|
private static Map<Class<?>, EquivalentConverter<Object>> genericConverters;
|
||||||
|
private static List<Unwrapper> unwrappers;
|
||||||
|
|
||||||
// Used to access the world type
|
// Used to access the world type
|
||||||
private static Method worldTypeName;
|
private static Method worldTypeName;
|
||||||
private static Method worldTypeGetType;
|
private static Method worldTypeGetType;
|
||||||
|
|
||||||
|
// Used for potion effect conversion
|
||||||
|
private static volatile Constructor<?> mobEffectConstructor;
|
||||||
|
private static volatile StructureModifier<Object> mobEffectModifier;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
MinecraftReflection.getWorldTypeClass();
|
MinecraftReflection.getWorldTypeClass();
|
||||||
@ -449,6 +461,57 @@ public class BukkitConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Retrieve the converter used to convert between a PotionEffect and the equivalent NMS Mobeffect.
|
||||||
|
* @return The potion effect converter.
|
||||||
|
*/
|
||||||
|
public static EquivalentConverter<PotionEffect> getPotionEffectConverter() {
|
||||||
|
return new IgnoreNullConverter<PotionEffect>() {
|
||||||
|
@Override
|
||||||
|
protected Object getGenericValue(Class<?> genericType, PotionEffect specific) {
|
||||||
|
// Locate the constructor
|
||||||
|
if (mobEffectConstructor == null) {
|
||||||
|
try {
|
||||||
|
mobEffectConstructor = MinecraftReflection.getMobEffectClass().
|
||||||
|
getConstructor(int.class, int.class, int.class, boolean.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot find mob effect constructor (int, int, int, boolean).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the generic value
|
||||||
|
try {
|
||||||
|
return mobEffectConstructor.newInstance(
|
||||||
|
specific.getType().getId(), specific.getDuration(),
|
||||||
|
specific.getAmplifier(), specific.isAmbient());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct MobEffect.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PotionEffect getSpecificValue(Object generic) {
|
||||||
|
if (mobEffectModifier == null) {
|
||||||
|
mobEffectModifier = new StructureModifier<Object>(MinecraftReflection.getMobEffectClass(), false);
|
||||||
|
}
|
||||||
|
StructureModifier<Integer> ints = mobEffectModifier.withTarget(generic).withType(int.class);
|
||||||
|
StructureModifier<Boolean> bools = mobEffectModifier.withTarget(generic).withType(boolean.class);
|
||||||
|
|
||||||
|
return new PotionEffect(
|
||||||
|
PotionEffectType.getById(ints.read(0)), /* effectId */
|
||||||
|
ints.read(1), /* duration */
|
||||||
|
ints.read(2), /* amplification */
|
||||||
|
bools.read(1) /* ambient */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<PotionEffect> getSpecificType() {
|
||||||
|
return PotionEffect.class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored.
|
* Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored.
|
||||||
* @param delegate - the underlying equivalent converter.
|
* @param delegate - the underlying equivalent converter.
|
||||||
* @return A equivalent converter that ignores NULL values.
|
* @return A equivalent converter that ignores NULL values.
|
||||||
@ -473,6 +536,31 @@ public class BukkitConverters {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an equivalent unwrapper for the converter.
|
||||||
|
* @param nativeType - the native NMS type the converter produces.
|
||||||
|
* @param converter - the converter.
|
||||||
|
* @return The equivalent unwrapper.
|
||||||
|
*/
|
||||||
|
public static Unwrapper asUnwrapper(final Class<?> nativeType, final EquivalentConverter<Object> converter) {
|
||||||
|
return new Unwrapper() {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Override
|
||||||
|
public Object unwrapItem(Object wrappedObject) {
|
||||||
|
Class<?> type = PacketConstructor.getClass(wrappedObject);
|
||||||
|
|
||||||
|
// Ensure the type is correct before we test
|
||||||
|
if (converter.getSpecificType().isAssignableFrom(type)) {
|
||||||
|
if (wrappedObject instanceof Class)
|
||||||
|
return nativeType;
|
||||||
|
else
|
||||||
|
return converter.getGeneric((Class) nativeType, wrappedObject);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve every converter that is associated with a specific class.
|
* Retrieve every converter that is associated with a specific class.
|
||||||
* @return Every converter with a unique specific class.
|
* @return Every converter with a unique specific class.
|
||||||
@ -487,7 +575,8 @@ public class BukkitConverters {
|
|||||||
put(ItemStack.class, (EquivalentConverter) getItemStackConverter()).
|
put(ItemStack.class, (EquivalentConverter) getItemStackConverter()).
|
||||||
put(NbtBase.class, (EquivalentConverter) getNbtConverter()).
|
put(NbtBase.class, (EquivalentConverter) getNbtConverter()).
|
||||||
put(NbtCompound.class, (EquivalentConverter) getNbtConverter()).
|
put(NbtCompound.class, (EquivalentConverter) getNbtConverter()).
|
||||||
put(WrappedWatchableObject.class, (EquivalentConverter) getWatchableObjectConverter());
|
put(WrappedWatchableObject.class, (EquivalentConverter) getWatchableObjectConverter()).
|
||||||
|
put(PotionEffect.class, (EquivalentConverter) getPotionEffectConverter());
|
||||||
|
|
||||||
if (hasWorldType)
|
if (hasWorldType)
|
||||||
builder.put(WorldType.class, (EquivalentConverter) getWorldTypeConverter());
|
builder.put(WorldType.class, (EquivalentConverter) getWorldTypeConverter());
|
||||||
@ -512,7 +601,8 @@ public class BukkitConverters {
|
|||||||
put(MinecraftReflection.getItemStackClass(), (EquivalentConverter) getItemStackConverter()).
|
put(MinecraftReflection.getItemStackClass(), (EquivalentConverter) getItemStackConverter()).
|
||||||
put(MinecraftReflection.getNBTBaseClass(), (EquivalentConverter) getNbtConverter()).
|
put(MinecraftReflection.getNBTBaseClass(), (EquivalentConverter) getNbtConverter()).
|
||||||
put(MinecraftReflection.getNBTCompoundClass(), (EquivalentConverter) getNbtConverter()).
|
put(MinecraftReflection.getNBTCompoundClass(), (EquivalentConverter) getNbtConverter()).
|
||||||
put(MinecraftReflection.getWatchableObjectClass(), (EquivalentConverter) getWatchableObjectConverter());
|
put(MinecraftReflection.getWatchableObjectClass(), (EquivalentConverter) getWatchableObjectConverter()).
|
||||||
|
put(MinecraftReflection.getMobEffectClass(), (EquivalentConverter) getPotionEffectConverter());
|
||||||
|
|
||||||
if (hasWorldType)
|
if (hasWorldType)
|
||||||
builder.put(MinecraftReflection.getWorldTypeClass(), (EquivalentConverter) getWorldTypeConverter());
|
builder.put(MinecraftReflection.getWorldTypeClass(), (EquivalentConverter) getWorldTypeConverter());
|
||||||
@ -522,4 +612,20 @@ public class BukkitConverters {
|
|||||||
}
|
}
|
||||||
return genericConverters;
|
return genericConverters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every NMS <-> Bukkit converter as unwrappers.
|
||||||
|
* @return Every unwrapper.
|
||||||
|
*/
|
||||||
|
public static List<Unwrapper> getUnwrappers() {
|
||||||
|
if (unwrappers == null) {
|
||||||
|
ImmutableList.Builder<Unwrapper> builder = ImmutableList.builder();
|
||||||
|
|
||||||
|
for (Map.Entry<Class<?>, EquivalentConverter<Object>> entry : getConvertersForGeneric().entrySet()) {
|
||||||
|
builder.add(asUnwrapper(entry.getKey(), entry.getValue()));
|
||||||
|
}
|
||||||
|
unwrappers = builder.build();
|
||||||
|
}
|
||||||
|
return unwrappers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemFactory;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -42,6 +44,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
|
|||||||
|
|
||||||
import com.comphenix.protocol.BukkitInitialization;
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
import com.comphenix.protocol.Packets;
|
import com.comphenix.protocol.Packets;
|
||||||
|
import com.comphenix.protocol.injector.PacketConstructor;
|
||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
@ -345,7 +348,20 @@ public class PacketContainerTest {
|
|||||||
ToStringBuilder.reflectionToString(clonedSnapshot, ToStringStyle.SHORT_PREFIX_STYLE));
|
ToStringBuilder.reflectionToString(clonedSnapshot, ToStringStyle.SHORT_PREFIX_STYLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPotionEffect() {
|
||||||
|
PotionEffect effect = new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 20 * 60, 1);
|
||||||
|
|
||||||
|
// The constructor we want to call
|
||||||
|
PacketConstructor creator = PacketConstructor.DEFAULT.withPacket(
|
||||||
|
Packets.Server.MOB_EFFECT, new Class<?>[] { int.class, PotionEffect.class });
|
||||||
|
PacketContainer packet = creator.createPacket(1, effect);
|
||||||
|
|
||||||
|
assertEquals(1, (int) packet.getIntegers().read(0));
|
||||||
|
assertEquals(effect.getType().getId(), (byte) packet.getBytes().read(0));
|
||||||
|
assertEquals(effect.getAmplifier(), (byte) packet.getBytes().read(1));
|
||||||
|
assertEquals(effect.getDuration(), (short) packet.getShorts().read(0));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeepClone() {
|
public void testDeepClone() {
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren