mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-28 05:35:28 +01:00
Added the ability to read and modify server-side chat messages.
This introduces the new WrappedChatComponent class, which can be accessed through PacketContainer.getChatComponents().
This commit is contained in:
parent
1aaf272878
commit
154d73ae51
@ -66,6 +66,7 @@ import com.comphenix.protocol.utility.StreamSerializer;
|
|||||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||||
import com.comphenix.protocol.wrappers.WrappedAttribute;
|
import com.comphenix.protocol.wrappers.WrappedAttribute;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||||
@ -478,7 +479,7 @@ public class PacketContainer implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a read/write structure for game profiles.
|
* Retrieves a read/write structure for game profiles in Minecraft 1.7.2.
|
||||||
* <p>
|
* <p>
|
||||||
* This modifier will automatically marshall between WrappedGameProfile and the
|
* This modifier will automatically marshall between WrappedGameProfile and the
|
||||||
* internal Minecraft GameProfile.
|
* internal Minecraft GameProfile.
|
||||||
@ -490,6 +491,19 @@ public class PacketContainer implements Serializable {
|
|||||||
GameProfile.class, BukkitConverters.getWrappedGameProfileConverter());
|
GameProfile.class, BukkitConverters.getWrappedGameProfileConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a read/write structure for chat components in Minecraft 1.7.2.
|
||||||
|
* <p>
|
||||||
|
* This modifier will automatically marshall between WrappedChatComponent and the
|
||||||
|
* internal Minecraft GameProfile.
|
||||||
|
* @return A modifier for GameProfile fields.
|
||||||
|
*/
|
||||||
|
public StructureModifier<WrappedChatComponent> getChatComponents() {
|
||||||
|
// Convert to and from the Bukkit wrapper
|
||||||
|
return structureModifier.<WrappedChatComponent>withType(
|
||||||
|
MinecraftReflection.getIChatBaseComponent(), BukkitConverters.getWrappedChatComponentConverter());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the ID of this packet.
|
* Retrieves the ID of this packet.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
|
import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
|
||||||
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
|
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import net.sf.cglib.asm.ClassReader;
|
import net.sf.cglib.asm.ClassReader;
|
||||||
@ -28,10 +29,19 @@ public class ClassAnalyser {
|
|||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOwnerClass() {
|
public String getOwnerName() {
|
||||||
return ownerClass;
|
return ownerClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the associated owner class.
|
||||||
|
* @return The owner class.
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
*/
|
||||||
|
public Class<?> getOwnerClass() throws ClassNotFoundException {
|
||||||
|
return AsmMethod.class.getClassLoader().loadClass(getOwnerName().replace('/', '.'));
|
||||||
|
}
|
||||||
|
|
||||||
public String getMethodName() {
|
public String getMethodName() {
|
||||||
return methodName;
|
return methodName;
|
||||||
}
|
}
|
||||||
@ -57,7 +67,18 @@ public class ClassAnalyser {
|
|||||||
* @throws IOException Cannot access the parent class.
|
* @throws IOException Cannot access the parent class.
|
||||||
*/
|
*/
|
||||||
public List<AsmMethod> getMethodCalls(Method method) throws IOException {
|
public List<AsmMethod> getMethodCalls(Method method) throws IOException {
|
||||||
final ClassReader reader = new ClassReader(method.getDeclaringClass().getCanonicalName());
|
return getMethodCalls(method.getDeclaringClass(), method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every method calls in the given method.
|
||||||
|
* @param clazz - the parent class.
|
||||||
|
* @param method - the method to analyse.
|
||||||
|
* @return The method calls.
|
||||||
|
* @throws IOException Cannot access the parent class.
|
||||||
|
*/
|
||||||
|
public List<AsmMethod> getMethodCalls(Class<?> clazz, Method method) throws IOException {
|
||||||
|
final ClassReader reader = new ClassReader(clazz.getCanonicalName());
|
||||||
final List<AsmMethod> output = Lists.newArrayList();
|
final List<AsmMethod> output = Lists.newArrayList();
|
||||||
|
|
||||||
// The method we are looking for
|
// The method we are looking for
|
||||||
|
@ -543,6 +543,14 @@ public class MinecraftReflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the CraftChatMessage in Minecraft 1.7.2.
|
||||||
|
* @return The CraftChatMessage class.
|
||||||
|
*/
|
||||||
|
public static Class<?> getCraftChatMessage() {
|
||||||
|
return getCraftBukkitClass("util.CraftChatMessage");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the WorldServer (NMS) class.
|
* Retrieve the WorldServer (NMS) class.
|
||||||
* @return The WorldServer class.
|
* @return The WorldServer class.
|
||||||
@ -637,6 +645,52 @@ public class MinecraftReflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the IChatBaseComponent class.
|
||||||
|
* @return The IChatBaseComponent.
|
||||||
|
*/
|
||||||
|
public static Class<?> getIChatBaseComponent() {
|
||||||
|
try {
|
||||||
|
return getMinecraftClass("IChatBaseComponent");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return setMinecraftClass("IChatBaseComponent",
|
||||||
|
FuzzyReflection.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
|
||||||
|
getMethod().getReturnType().getComponentType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to find the ChatSerializer class.
|
||||||
|
* @return The serializer class.
|
||||||
|
* @throws IllegalStateException If the class could not be found or deduced.
|
||||||
|
*/
|
||||||
|
public static Class<?> getChatSerializer() {
|
||||||
|
try {
|
||||||
|
return getMinecraftClass("ChatSerializer");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// Analyse the ASM
|
||||||
|
try {
|
||||||
|
List<AsmMethod> methodCalls = ClassAnalyser.getDefault().getMethodCalls(
|
||||||
|
PacketType.Play.Server.CHAT.getPacketClass(),
|
||||||
|
MinecraftMethods.getPacketReadByteBufMethod()
|
||||||
|
);
|
||||||
|
Class<?> packetSerializer = getPacketDataSerializerClass();
|
||||||
|
|
||||||
|
for (AsmMethod method : methodCalls) {
|
||||||
|
Class<?> owner = method.getOwnerClass();
|
||||||
|
|
||||||
|
if (isMinecraftClass(owner) && !owner.equals(packetSerializer)) {
|
||||||
|
return setMinecraftClass("ChatSerializer", owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e1) {
|
||||||
|
throw new IllegalStateException("Cannot find ChatSerializer class.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Cannot find ChatSerializer class.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if this Minecraft version is using Netty.
|
* Determine if this Minecraft version is using Netty.
|
||||||
* <p>
|
* <p>
|
||||||
@ -1300,7 +1354,7 @@ public class MinecraftReflection {
|
|||||||
try {
|
try {
|
||||||
// Now -- we inspect all the method calls within that method, and use the first foreign Minecraft class
|
// Now -- we inspect all the method calls within that method, and use the first foreign Minecraft class
|
||||||
for (AsmMethod method : ClassAnalyser.getDefault().getMethodCalls(writeNbt)) {
|
for (AsmMethod method : ClassAnalyser.getDefault().getMethodCalls(writeNbt)) {
|
||||||
Class<?> owner = MinecraftReflection.class.getClassLoader().loadClass(method.getOwnerClass().replace('/', '.'));
|
Class<?> owner = method.getOwnerClass();
|
||||||
|
|
||||||
if (!packetSerializer.equals(owner) && isMinecraftClass(owner)) {
|
if (!packetSerializer.equals(owner) && isMinecraftClass(owner)) {
|
||||||
return setMinecraftClass("NBTCompressedStreamTools", owner);
|
return setMinecraftClass("NBTCompressedStreamTools", owner);
|
||||||
|
@ -257,6 +257,29 @@ public class BukkitConverters {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a converter for wrapped chat components.
|
||||||
|
* @return Wrapped chat componetns.
|
||||||
|
*/
|
||||||
|
public static EquivalentConverter<WrappedChatComponent> getWrappedChatComponentConverter() {
|
||||||
|
return new IgnoreNullConverter<WrappedChatComponent>() {
|
||||||
|
@Override
|
||||||
|
protected Object getGenericValue(Class<?> genericType, WrappedChatComponent specific) {
|
||||||
|
return specific.getHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WrappedChatComponent getSpecificValue(Object generic) {
|
||||||
|
return WrappedChatComponent.fromHandle(generic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<WrappedChatComponent> getSpecificType() {
|
||||||
|
return WrappedChatComponent.class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a converter for wrapped attribute snapshots.
|
* Retrieve a converter for wrapped attribute snapshots.
|
||||||
* @return Wrapped attribute snapshot converter.
|
* @return Wrapped attribute snapshot converter.
|
||||||
@ -601,6 +624,12 @@ public class BukkitConverters {
|
|||||||
put(WrappedWatchableObject.class, (EquivalentConverter) getWatchableObjectConverter()).
|
put(WrappedWatchableObject.class, (EquivalentConverter) getWatchableObjectConverter()).
|
||||||
put(PotionEffect.class, (EquivalentConverter) getPotionEffectConverter());
|
put(PotionEffect.class, (EquivalentConverter) getPotionEffectConverter());
|
||||||
|
|
||||||
|
// Types added in 1.7.2
|
||||||
|
if (MinecraftReflection.isUsingNetty()) {
|
||||||
|
builder.put(WrappedGameProfile.class, (EquivalentConverter) getWrappedGameProfileConverter());
|
||||||
|
builder.put(WrappedChatComponent.class, (EquivalentConverter) getWrappedChatComponentConverter());
|
||||||
|
}
|
||||||
|
|
||||||
if (hasWorldType)
|
if (hasWorldType)
|
||||||
builder.put(WorldType.class, (EquivalentConverter) getWorldTypeConverter());
|
builder.put(WorldType.class, (EquivalentConverter) getWorldTypeConverter());
|
||||||
if (hasAttributeSnapshot)
|
if (hasAttributeSnapshot)
|
||||||
@ -631,6 +660,12 @@ public class BukkitConverters {
|
|||||||
builder.put(MinecraftReflection.getWorldTypeClass(), (EquivalentConverter) getWorldTypeConverter());
|
builder.put(MinecraftReflection.getWorldTypeClass(), (EquivalentConverter) getWorldTypeConverter());
|
||||||
if (hasAttributeSnapshot)
|
if (hasAttributeSnapshot)
|
||||||
builder.put(MinecraftReflection.getAttributeSnapshotClass(), (EquivalentConverter) getWrappedAttributeConverter());
|
builder.put(MinecraftReflection.getAttributeSnapshotClass(), (EquivalentConverter) getWrappedAttributeConverter());
|
||||||
|
|
||||||
|
// Types added in 1.7.2
|
||||||
|
if (MinecraftReflection.isUsingNetty()) {
|
||||||
|
builder.put(MinecraftReflection.getGameProfileClass(), (EquivalentConverter) getWrappedGameProfileConverter());
|
||||||
|
builder.put(MinecraftReflection.getIChatBaseComponent(), (EquivalentConverter) getWrappedChatComponentConverter());
|
||||||
|
}
|
||||||
genericConverters = builder.build();
|
genericConverters = builder.build();
|
||||||
}
|
}
|
||||||
return genericConverters;
|
return genericConverters;
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a chat component added in Minecraft 1.7.2
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class WrappedChatComponent {
|
||||||
|
private static final Class<?> SERIALIZER = MinecraftReflection.getChatSerializer();
|
||||||
|
private static final Class<?> COMPONENT = MinecraftReflection.getIChatBaseComponent();
|
||||||
|
private static MethodAccessor SERIALIZE_COMPONENT = null;
|
||||||
|
private static MethodAccessor DESERIALIZE_COMPONENT = null;
|
||||||
|
private static MethodAccessor CONSTRUCT_COMPONENT = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER);
|
||||||
|
|
||||||
|
// Retrieve the correct methods
|
||||||
|
SERIALIZE_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||||
|
fuzzy.getMethodByParameters("serialize", String.class, new Class<?>[] { COMPONENT }));
|
||||||
|
DESERIALIZE_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||||
|
fuzzy.getMethodByParameters("serialize", COMPONENT, new Class<?>[] { String.class }));
|
||||||
|
|
||||||
|
// Get a component from a standard Minecraft message
|
||||||
|
CONSTRUCT_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||||
|
MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object handle;
|
||||||
|
private transient String cache;
|
||||||
|
|
||||||
|
private WrappedChatComponent(Object handle, String cache) {
|
||||||
|
this.handle = handle;
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new chat component wrapper around the given NMS object.
|
||||||
|
* @param handle - the NMS object.
|
||||||
|
* @return The wrapper.
|
||||||
|
*/
|
||||||
|
public static WrappedChatComponent fromHandle(Object handle) {
|
||||||
|
if (handle == null)
|
||||||
|
throw new IllegalArgumentException("handle cannot be NULL.");
|
||||||
|
if (!COMPONENT.isAssignableFrom(handle.getClass()))
|
||||||
|
throw new IllegalArgumentException("handle (" + handle + ") is not a " + COMPONENT);
|
||||||
|
return new WrappedChatComponent(handle, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new chat component wrapper from the given JSON string.
|
||||||
|
* @param json - the json.
|
||||||
|
* @return The chat component wrapper.
|
||||||
|
*/
|
||||||
|
public static WrappedChatComponent fromJson(String json) {
|
||||||
|
return new WrappedChatComponent(DESERIALIZE_COMPONENT.invoke(null, json), json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an array of chat components from a standard Minecraft message.
|
||||||
|
* <p>
|
||||||
|
* This uses {@link ChatColor} for formating.
|
||||||
|
* @param message - the message.
|
||||||
|
* @return The equivalent chat components.
|
||||||
|
*/
|
||||||
|
public static WrappedChatComponent[] fromChatMessage(String message) {
|
||||||
|
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message);
|
||||||
|
WrappedChatComponent[] result = new WrappedChatComponent[components.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < components.length; i++) {
|
||||||
|
result[i] = fromHandle(components[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a copy of this component as a JSON string.
|
||||||
|
* <p>
|
||||||
|
* Note that any modifications to this JSON string will not update the current component.
|
||||||
|
* @return The JSON representation of this object.
|
||||||
|
*/
|
||||||
|
public String getJson() {
|
||||||
|
if (cache == null) {
|
||||||
|
cache = (String) SERIALIZE_COMPONENT.invoke(null, handle);
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the content of this component using a JSON object.
|
||||||
|
* @param obj - the JSON that represents the new component.
|
||||||
|
*/
|
||||||
|
public void setJson(String obj) {
|
||||||
|
this.handle = DESERIALIZE_COMPONENT.invoke(null, obj);
|
||||||
|
this.cache = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the underlying IChatBaseComponent instance.
|
||||||
|
* @return The underlying instance.
|
||||||
|
*/
|
||||||
|
public Object getHandle() {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this)
|
||||||
|
return true;
|
||||||
|
if (obj instanceof WrappedChatComponent) {
|
||||||
|
return ((WrappedChatComponent) obj).handle.equals(handle);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return handle.hashCode();
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ import org.apache.commons.lang.builder.ToStringStyle;
|
|||||||
// Will have to be updated for every version though
|
// Will have to be updated for every version though
|
||||||
import org.bukkit.craftbukkit.v1_7_R1.inventory.CraftItemFactory;
|
import org.bukkit.craftbukkit.v1_7_R1.inventory.CraftItemFactory;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
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;
|
||||||
@ -53,6 +54,7 @@ import com.comphenix.protocol.utility.MinecraftMethods;
|
|||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||||
@ -336,6 +338,16 @@ public class PacketContainerTest {
|
|||||||
assertEquals(profile, spawnEntity.getGameProfiles().read(0));
|
assertEquals(profile, spawnEntity.getGameProfiles().read(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChatComponents() {
|
||||||
|
PacketContainer chatPacket = new PacketContainer(PacketType.Play.Server.CHAT);
|
||||||
|
chatPacket.getChatComponents().write(0,
|
||||||
|
WrappedChatComponent.fromChatMessage("You shall not " + ChatColor.ITALIC + "pass!")[0]);
|
||||||
|
|
||||||
|
assertEquals("{\"extra\":[\"You shall not \",{\"italic\":true,\"text\":\"pass!\"}],\"text\":\"\"}",
|
||||||
|
chatPacket.getChatComponents().read(0).getJson());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialization() {
|
public void testSerialization() {
|
||||||
PacketContainer chat = new PacketContainer(PacketType.Play.Client.CHAT);
|
PacketContainer chat = new PacketContainer(PacketType.Play.Client.CHAT);
|
||||||
|
@ -2,6 +2,8 @@ package com.comphenix.protocol.utility;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_7_R1.ChatSerializer;
|
||||||
|
import net.minecraft.server.v1_7_R1.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_7_R1.NBTCompressedStreamTools;
|
import net.minecraft.server.v1_7_R1.NBTCompressedStreamTools;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@ -32,4 +34,14 @@ public class MinecraftReflectionTest {
|
|||||||
public void testNbtStreamTools() {
|
public void testNbtStreamTools() {
|
||||||
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
|
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChatComponent() {
|
||||||
|
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChatSerializer() {
|
||||||
|
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user