Use the object wrappers when printing custom Minecraft objects.
Dieser Commit ist enthalten in:
Ursprung
34f5278605
Commit
5c2fc8684e
@ -44,10 +44,13 @@ import com.comphenix.protocol.events.ListeningWhitelist;
|
|||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
import com.comphenix.protocol.injector.GamePhase;
|
import com.comphenix.protocol.injector.GamePhase;
|
||||||
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.PrettyPrinter;
|
import com.comphenix.protocol.reflect.PrettyPrinter;
|
||||||
|
import com.comphenix.protocol.reflect.PrettyPrinter.ObjectPrinter;
|
||||||
import com.comphenix.protocol.utility.ChatExtensions;
|
import com.comphenix.protocol.utility.ChatExtensions;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
import com.google.common.collect.DiscreteDomains;
|
import com.google.common.collect.DiscreteDomains;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
import com.google.common.collect.Ranges;
|
import com.google.common.collect.Ranges;
|
||||||
@ -432,7 +435,20 @@ class CommandPacket extends CommandBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info(shortDescription + ":\n" +
|
logger.info(shortDescription + ":\n" +
|
||||||
PrettyPrinter.printObject(packet, clazz, MinecraftReflection.getPacketClass())
|
PrettyPrinter.printObject(packet, clazz, MinecraftReflection.getPacketClass(), PrettyPrinter.RECURSE_DEPTH, new ObjectPrinter() {
|
||||||
|
@Override
|
||||||
|
public boolean print(StringBuilder output, Object value) {
|
||||||
|
if (value != null) {
|
||||||
|
EquivalentConverter<Object> converter = BukkitConverters.getGenericConverters().get(value.getClass());
|
||||||
|
|
||||||
|
if (converter != null) {
|
||||||
|
output.append(converter.getSpecific(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
|
@ -33,6 +33,28 @@ import com.google.common.primitives.Primitives;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class PrettyPrinter {
|
public class PrettyPrinter {
|
||||||
|
/**
|
||||||
|
* Represents a generic object printer.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public interface ObjectPrinter {
|
||||||
|
public static final ObjectPrinter DEFAULT = new ObjectPrinter() {
|
||||||
|
@Override
|
||||||
|
public boolean print(StringBuilder output, Object value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the content of the given object.
|
||||||
|
* <p>
|
||||||
|
* Return FALSE in order for let the default printer take over.
|
||||||
|
* @param output - where to print the output.
|
||||||
|
* @param value - the value to print, may be NULL.
|
||||||
|
* @return TRUE if we processed the value and added to the output, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean print(StringBuilder output, Object value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How far we will recurse.
|
* How far we will recurse.
|
||||||
@ -74,6 +96,19 @@ public class PrettyPrinter {
|
|||||||
* @throws IllegalAccessException
|
* @throws IllegalAccessException
|
||||||
*/
|
*/
|
||||||
public static String printObject(Object object, Class<?> start, Class<?> stop, int hierachyDepth) throws IllegalAccessException {
|
public static String printObject(Object object, Class<?> start, Class<?> stop, int hierachyDepth) throws IllegalAccessException {
|
||||||
|
return printObject(object, start, stop, hierachyDepth, ObjectPrinter.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the content of an object.
|
||||||
|
* @param object - the object to serialize.
|
||||||
|
* @param stop - superclass that will stop the process.
|
||||||
|
* @param hierachyDepth - maximum recursion level.
|
||||||
|
* @param transformer - a generic object printer.
|
||||||
|
* @return String representation of the class.
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
*/
|
||||||
|
public static String printObject(Object object, Class<?> start, Class<?> stop, int hierachyDepth, ObjectPrinter printer) throws IllegalAccessException {
|
||||||
if (object == null)
|
if (object == null)
|
||||||
throw new IllegalArgumentException("object cannot be NULL.");
|
throw new IllegalArgumentException("object cannot be NULL.");
|
||||||
|
|
||||||
@ -82,7 +117,7 @@ public class PrettyPrinter {
|
|||||||
|
|
||||||
// Start and stop
|
// Start and stop
|
||||||
output.append("{ ");
|
output.append("{ ");
|
||||||
printObject(output, object, start, stop, previous, hierachyDepth, true);
|
printObject(output, object, start, stop, previous, hierachyDepth, true, printer);
|
||||||
output.append(" }");
|
output.append(" }");
|
||||||
|
|
||||||
return output.toString();
|
return output.toString();
|
||||||
@ -90,7 +125,7 @@ public class PrettyPrinter {
|
|||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static void printIterables(StringBuilder output, Iterable iterable, Class<?> current, Class<?> stop,
|
private static void printIterables(StringBuilder output, Iterable iterable, Class<?> current, Class<?> stop,
|
||||||
Set<Object> previous, int hierachyIndex) throws IllegalAccessException {
|
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||||
|
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
output.append("(");
|
output.append("(");
|
||||||
@ -102,7 +137,7 @@ public class PrettyPrinter {
|
|||||||
output.append(", ");
|
output.append(", ");
|
||||||
|
|
||||||
// Print value
|
// Print value
|
||||||
printValue(output, value, stop, previous, hierachyIndex - 1);
|
printValue(output, value, stop, previous, hierachyIndex - 1, printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.append(")");
|
output.append(")");
|
||||||
@ -119,7 +154,7 @@ public class PrettyPrinter {
|
|||||||
* @throws IllegalAccessException If any reflection went wrong.
|
* @throws IllegalAccessException If any reflection went wrong.
|
||||||
*/
|
*/
|
||||||
private static void printMap(StringBuilder output, Map<Object, Object> map, Class<?> current, Class<?> stop,
|
private static void printMap(StringBuilder output, Map<Object, Object> map, Class<?> current, Class<?> stop,
|
||||||
Set<Object> previous, int hierachyIndex) throws IllegalAccessException {
|
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||||
|
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
output.append("[");
|
output.append("[");
|
||||||
@ -130,16 +165,16 @@ public class PrettyPrinter {
|
|||||||
else
|
else
|
||||||
output.append(", ");
|
output.append(", ");
|
||||||
|
|
||||||
printValue(output, entry.getKey(), stop, previous, hierachyIndex - 1);
|
printValue(output, entry.getKey(), stop, previous, hierachyIndex - 1, printer);
|
||||||
output.append(": ");
|
output.append(": ");
|
||||||
printValue(output, entry.getValue(), stop, previous, hierachyIndex - 1);
|
printValue(output, entry.getValue(), stop, previous, hierachyIndex - 1, printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.append("]");
|
output.append("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printArray(StringBuilder output, Object array, Class<?> current, Class<?> stop,
|
private static void printArray(StringBuilder output, Object array, Class<?> current, Class<?> stop,
|
||||||
Set<Object> previous, int hierachyIndex) throws IllegalAccessException {
|
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||||
|
|
||||||
Class<?> component = current.getComponentType();
|
Class<?> component = current.getComponentType();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
@ -156,7 +191,7 @@ public class PrettyPrinter {
|
|||||||
|
|
||||||
// Handle exceptions
|
// Handle exceptions
|
||||||
try {
|
try {
|
||||||
printValue(output, Array.get(array, i), component, stop, previous, hierachyIndex - 1);
|
printValue(output, Array.get(array, i), component, stop, previous, hierachyIndex - 1, printer);
|
||||||
} catch (ArrayIndexOutOfBoundsException e) {
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
break;
|
break;
|
||||||
@ -171,7 +206,8 @@ public class PrettyPrinter {
|
|||||||
|
|
||||||
// Internal recursion method
|
// Internal recursion method
|
||||||
private static void printObject(StringBuilder output, Object object, Class<?> current, Class<?> stop,
|
private static void printObject(StringBuilder output, Object object, Class<?> current, Class<?> stop,
|
||||||
Set<Object> previous, int hierachyIndex, boolean first) throws IllegalAccessException {
|
Set<Object> previous, int hierachyIndex, boolean first,
|
||||||
|
ObjectPrinter printer) throws IllegalAccessException {
|
||||||
|
|
||||||
// See if we're supposed to skip this class
|
// See if we're supposed to skip this class
|
||||||
if (current == Object.class || (stop != null && current.equals(stop))) {
|
if (current == Object.class || (stop != null && current.equals(stop))) {
|
||||||
@ -203,42 +239,46 @@ public class PrettyPrinter {
|
|||||||
|
|
||||||
output.append(field.getName());
|
output.append(field.getName());
|
||||||
output.append(" = ");
|
output.append(" = ");
|
||||||
printValue(output, value, type, stop, previous, hierachyIndex - 1);
|
printValue(output, value, type, stop, previous, hierachyIndex - 1, printer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse
|
// Recurse
|
||||||
printObject(output, object, current.getSuperclass(), stop, previous, hierachyIndex, first);
|
printObject(output, object, current.getSuperclass(), stop, previous, hierachyIndex, first, printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printValue(StringBuilder output, Object value, Class<?> stop,
|
private static void printValue(StringBuilder output, Object value, Class<?> stop,
|
||||||
Set<Object> previous, int hierachyIndex) throws IllegalAccessException {
|
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||||
// Handle the NULL case
|
// Handle the NULL case
|
||||||
printValue(output, value, value != null ? value.getClass() : null, stop, previous, hierachyIndex);
|
printValue(output, value, value != null ? value.getClass() : null, stop, previous, hierachyIndex, printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
private static void printValue(StringBuilder output, Object value, Class<?> type,
|
private static void printValue(StringBuilder output, Object value, Class<?> type,
|
||||||
Class<?> stop, Set<Object> previous, int hierachyIndex) throws IllegalAccessException {
|
Class<?> stop, Set<Object> previous, int hierachyIndex,
|
||||||
|
ObjectPrinter printer) throws IllegalAccessException {
|
||||||
|
|
||||||
// Just print primitive types
|
// Just print primitive types
|
||||||
if (value == null) {
|
if (printer.print(output, value)) {
|
||||||
|
return;
|
||||||
|
} else if (value == null) {
|
||||||
output.append("NULL");
|
output.append("NULL");
|
||||||
} else if (type.isPrimitive() || Primitives.isWrapperType(type)) {
|
} else if (type.isPrimitive() || Primitives.isWrapperType(type)) {
|
||||||
output.append(value);
|
output.append(value);
|
||||||
} else if (type == String.class || hierachyIndex <= 0) {
|
} else if (type == String.class || hierachyIndex <= 0) {
|
||||||
output.append("\"" + value + "\"");
|
output.append("\"" + value + "\"");
|
||||||
} else if (type.isArray()) {
|
} else if (type.isArray()) {
|
||||||
printArray(output, value, type, stop, previous, hierachyIndex);
|
printArray(output, value, type, stop, previous, hierachyIndex, printer);
|
||||||
} else if (Iterable.class.isAssignableFrom(type)) {
|
} else if (Iterable.class.isAssignableFrom(type)) {
|
||||||
printIterables(output, (Iterable) value, type, stop, previous, hierachyIndex);
|
printIterables(output, (Iterable) value, type, stop, previous, hierachyIndex, printer);
|
||||||
} else if (Map.class.isAssignableFrom(type)) {
|
} else if (Map.class.isAssignableFrom(type)) {
|
||||||
printMap(output, (Map<Object, Object>) value, type, stop, previous, hierachyIndex);
|
printMap(output, (Map<Object, Object>) value, type, stop, previous, hierachyIndex, printer);
|
||||||
} else if (ClassLoader.class.isAssignableFrom(type) || previous.contains(value)) {
|
} else if (ClassLoader.class.isAssignableFrom(type) || previous.contains(value)) {
|
||||||
// Don't print previous objects
|
// Don't print previous objects
|
||||||
output.append("\"" + value + "\"");
|
output.append("\"" + value + "\"");
|
||||||
} else {
|
} else {
|
||||||
output.append("{ ");
|
output.append("{ ");
|
||||||
printObject(output, value, value.getClass(), stop, previous, hierachyIndex, true);
|
printObject(output, value, value.getClass(), stop, previous, hierachyIndex, true, printer);
|
||||||
output.append(" }");
|
output.append(" }");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
|||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||||
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||||
|
import com.comphenix.protocol.wrappers.nbt.NbtType;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -869,6 +871,21 @@ public class MinecraftReflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the NBT Compound class.
|
||||||
|
* @return The NBT Compond class.
|
||||||
|
*/
|
||||||
|
public static Class<?> getNBTCompoundClass() {
|
||||||
|
try {
|
||||||
|
return getMinecraftClass("NBTTagCompound");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return setMinecraftClass(
|
||||||
|
"NBTTagCompound",
|
||||||
|
NbtFactory.ofWrapper(NbtType.TAG_COMPOUND, "Test").getHandle().getClass()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the EntityTracker (NMS) class.
|
* Retrieve the EntityTracker (NMS) class.
|
||||||
* @return EntityTracker class.
|
* @return EntityTracker class.
|
||||||
|
@ -22,6 +22,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
@ -35,8 +36,10 @@ import com.comphenix.protocol.reflect.FieldAccessException;
|
|||||||
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.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.ImmutableMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains several useful equivalent converters for normal Bukkit types.
|
* Contains several useful equivalent converters for normal Bukkit types.
|
||||||
@ -47,6 +50,10 @@ public class BukkitConverters {
|
|||||||
// Check whether or not certain classes exists
|
// Check whether or not certain classes exists
|
||||||
private static boolean hasWorldType = false;
|
private static boolean hasWorldType = false;
|
||||||
|
|
||||||
|
// The static maps
|
||||||
|
private static Map<Class<?>, EquivalentConverter<Object>> specificConverters;
|
||||||
|
private static Map<Class<?>, EquivalentConverter<Object>> genericConverters;
|
||||||
|
|
||||||
// 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;
|
||||||
@ -416,4 +423,44 @@ public class BukkitConverters {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every converter that is associated with a specific class.
|
||||||
|
* @return Every converter with a unique specific class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
public static Map<Class<?>, EquivalentConverter<Object>> getSpecificConverters() {
|
||||||
|
if (specificConverters == null) {
|
||||||
|
// Generics doesn't work, as usual
|
||||||
|
specificConverters = ImmutableMap.<Class<?>, EquivalentConverter<Object>>builder().
|
||||||
|
put(WrappedDataWatcher.class, (EquivalentConverter) getDataWatcherConverter()).
|
||||||
|
put(ItemStack.class, (EquivalentConverter) getItemStackConverter()).
|
||||||
|
put(NbtBase.class, (EquivalentConverter) getNbtConverter()).
|
||||||
|
put(NbtCompound.class, (EquivalentConverter) getNbtConverter()).
|
||||||
|
put(WrappedWatchableObject.class, (EquivalentConverter) getWatchableObjectConverter()).
|
||||||
|
put(WorldType.class, (EquivalentConverter) getWorldTypeConverter()).
|
||||||
|
build();
|
||||||
|
}
|
||||||
|
return specificConverters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every converter that is associated with a generic class.
|
||||||
|
* @return Every converter with a unique generic class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
public static Map<Class<?>, EquivalentConverter<Object>> getGenericConverters() {
|
||||||
|
if (genericConverters == null) {
|
||||||
|
// Generics doesn't work, as usual
|
||||||
|
genericConverters = ImmutableMap.<Class<?>, EquivalentConverter<Object>>builder().
|
||||||
|
put(MinecraftReflection.getDataWatcherClass(), (EquivalentConverter) getDataWatcherConverter()).
|
||||||
|
put(MinecraftReflection.getItemStackClass(), (EquivalentConverter) getItemStackConverter()).
|
||||||
|
put(MinecraftReflection.getNBTBaseClass(), (EquivalentConverter) getNbtConverter()).
|
||||||
|
put(MinecraftReflection.getNBTCompoundClass(), (EquivalentConverter) getNbtConverter()).
|
||||||
|
put(MinecraftReflection.getWatchableObjectClass(), (EquivalentConverter) getWatchableObjectConverter()).
|
||||||
|
put(MinecraftReflection.getWorldTypeClass(), (EquivalentConverter) getWorldTypeConverter()).
|
||||||
|
build();
|
||||||
|
}
|
||||||
|
return genericConverters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren