mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-24 11:36:51 +01:00
Add support for using multiple lines in WrappedServerPing.
This commit is contained in:
parent
75fe2c6db9
commit
a902c1f186
@ -4,25 +4,50 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod.AsmOpcodes;
|
||||||
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.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import net.sf.cglib.asm.ClassReader;
|
import net.sf.cglib.asm.ClassReader;
|
||||||
import net.sf.cglib.asm.MethodVisitor;
|
import net.sf.cglib.asm.MethodVisitor;
|
||||||
|
import net.sf.cglib.asm.Opcodes;
|
||||||
import net.sf.cglib.asm.Type;
|
import net.sf.cglib.asm.Type;
|
||||||
|
|
||||||
public class ClassAnalyser {
|
public class ClassAnalyser {
|
||||||
/**
|
/**
|
||||||
* Represents a method in ASM.
|
* Represents a method in ASM.
|
||||||
|
* <p>
|
||||||
|
* Keep in mind that this may also invoke a constructor.
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public static class AsmMethod {
|
public static class AsmMethod {
|
||||||
|
public enum AsmOpcodes {
|
||||||
|
INVOKE_VIRTUAL,
|
||||||
|
INVOKE_SPECIAL,
|
||||||
|
INVOKE_STATIC,
|
||||||
|
INVOKE_INTERFACE,
|
||||||
|
INVOKE_DYNAMIC;
|
||||||
|
|
||||||
|
public static AsmOpcodes fromIntOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case Opcodes.INVOKEVIRTUAL: return AsmOpcodes.INVOKE_VIRTUAL;
|
||||||
|
case Opcodes.INVOKESPECIAL: return AsmOpcodes.INVOKE_SPECIAL;
|
||||||
|
case Opcodes.INVOKESTATIC: return AsmOpcodes.INVOKE_STATIC;
|
||||||
|
case Opcodes.INVOKEINTERFACE: return AsmOpcodes.INVOKE_INTERFACE;
|
||||||
|
case Opcodes.INVOKEDYNAMIC: return AsmOpcodes.INVOKE_DYNAMIC;
|
||||||
|
default: throw new IllegalArgumentException("Unknown opcode: " + opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AsmOpcodes opcode;
|
||||||
private final String ownerClass;
|
private final String ownerClass;
|
||||||
private final String methodName;
|
private final String methodName;
|
||||||
private final String signature;
|
private final String signature;
|
||||||
|
|
||||||
public AsmMethod(String ownerClass, String methodName, String signature) {
|
public AsmMethod(AsmOpcodes opcode, String ownerClass, String methodName, String signature) {
|
||||||
|
this.opcode = opcode;
|
||||||
this.ownerClass = ownerClass;
|
this.ownerClass = ownerClass;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
@ -32,6 +57,14 @@ public class ClassAnalyser {
|
|||||||
return ownerClass;
|
return ownerClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the opcode used to invoke this method or constructor.
|
||||||
|
* @return The opcode.
|
||||||
|
*/
|
||||||
|
public AsmOpcodes getOpcode() {
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the associated owner class.
|
* Retrieve the associated owner class.
|
||||||
* @return The owner class.
|
* @return The owner class.
|
||||||
@ -92,7 +125,7 @@ public class ClassAnalyser {
|
|||||||
return new EmptyMethodVisitor() {
|
return new EmptyMethodVisitor() {
|
||||||
@Override
|
@Override
|
||||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||||
output.add(new AsmMethod(owner, name, desc));
|
output.add(new AsmMethod(AsmOpcodes.fromIntOpcode(opcode), owner, methodName, desc));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -670,6 +670,33 @@ public class MinecraftReflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the NMS chat component text class.
|
||||||
|
* @return The chat component class.
|
||||||
|
*/
|
||||||
|
public static Class<?> getChatComponentTextClass() {
|
||||||
|
try {
|
||||||
|
return getMinecraftClass("ChatComponentText");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
try {
|
||||||
|
Method getScoreboardDisplayName = FuzzyReflection.fromClass(getEntityClass()).
|
||||||
|
getMethodByParameters("getScoreboardDisplayName", getIChatBaseComponentClass(), new Class<?>[0]);
|
||||||
|
Class<?> baseClass = getIChatBaseComponentClass();
|
||||||
|
|
||||||
|
for (AsmMethod method : ClassAnalyser.getDefault().getMethodCalls(getScoreboardDisplayName)) {
|
||||||
|
Class<?> owner = method.getOwnerClass();
|
||||||
|
|
||||||
|
if (isMinecraftClass(owner) && baseClass.isAssignableFrom(owner)) {
|
||||||
|
return setMinecraftClass("ChatComponentText", owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e1) {
|
||||||
|
throw new IllegalStateException("Cannot find ChatComponentText class.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Cannot find ChatComponentText class.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to find the ChatSerializer class.
|
* Attempt to find the ChatSerializer class.
|
||||||
* @return The serializer class.
|
* @return The serializer class.
|
||||||
|
@ -4,8 +4,10 @@ import org.bukkit.ChatColor;
|
|||||||
|
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a chat component added in Minecraft 1.7.2
|
* Represents a chat component added in Minecraft 1.7.2
|
||||||
@ -17,6 +19,7 @@ public class WrappedChatComponent extends AbstractWrapper {
|
|||||||
private static MethodAccessor SERIALIZE_COMPONENT = null;
|
private static MethodAccessor SERIALIZE_COMPONENT = null;
|
||||||
private static MethodAccessor DESERIALIZE_COMPONENT = null;
|
private static MethodAccessor DESERIALIZE_COMPONENT = null;
|
||||||
private static MethodAccessor CONSTRUCT_COMPONENT = null;
|
private static MethodAccessor CONSTRUCT_COMPONENT = null;
|
||||||
|
private static ConstructorAccessor CONSTRUCT_TEXT_COMPONENT = null;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER);
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER);
|
||||||
@ -30,6 +33,10 @@ public class WrappedChatComponent extends AbstractWrapper {
|
|||||||
// Get a component from a standard Minecraft message
|
// Get a component from a standard Minecraft message
|
||||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(
|
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(
|
||||||
MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
||||||
|
|
||||||
|
// And the component text constructor
|
||||||
|
CONSTRUCT_TEXT_COMPONENT = Accessors.getConstructorAccessor(
|
||||||
|
MinecraftReflection.getChatComponentTextClass(), String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private transient String cache;
|
private transient String cache;
|
||||||
@ -58,6 +65,16 @@ public class WrappedChatComponent extends AbstractWrapper {
|
|||||||
return new WrappedChatComponent(DESERIALIZE_COMPONENT.invoke(null, json), json);
|
return new WrappedChatComponent(DESERIALIZE_COMPONENT.invoke(null, json), json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a wrapper around a new text chat component with the given text.
|
||||||
|
* @param text - the text of the text chat component.
|
||||||
|
* @return The wrapper around the new chat component.
|
||||||
|
*/
|
||||||
|
public static WrappedChatComponent fromText(String text) {
|
||||||
|
Preconditions.checkNotNull(text, "text cannot be NULL.");
|
||||||
|
return fromHandle(CONSTRUCT_TEXT_COMPONENT.invoke(text));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an array of chat components from a standard Minecraft message.
|
* Construct an array of chat components from a standard Minecraft message.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -134,13 +134,11 @@ public class WrappedServerPing extends AbstractWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the message of the day.
|
* Set the message of the day.
|
||||||
* <p>
|
|
||||||
* <b>Warning:</b> Only the first line will be transmitted.
|
|
||||||
* @param description - the message.
|
* @param description - the message.
|
||||||
*/
|
*/
|
||||||
public void setMotD(String message) {
|
public void setMotD(String message) {
|
||||||
setMotD(WrappedChatComponent.fromChatMessage(message)[0]);
|
setMotD(WrappedChatComponent.fromText(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package com.comphenix.protocol.utility;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_7_R1.ChatComponentText;
|
||||||
import net.minecraft.server.v1_7_R1.ChatSerializer;
|
import net.minecraft.server.v1_7_R1.ChatSerializer;
|
||||||
import net.minecraft.server.v1_7_R1.ChunkCoordIntPair;
|
import net.minecraft.server.v1_7_R1.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_7_R1.IChatBaseComponent;
|
import net.minecraft.server.v1_7_R1.IChatBaseComponent;
|
||||||
@ -44,6 +45,11 @@ public class MinecraftReflectionTest {
|
|||||||
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
|
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChatComponentText() {
|
||||||
|
assertEquals(ChatComponentText.class, MinecraftReflection.getChatComponentTextClass());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChatSerializer() {
|
public void testChatSerializer() {
|
||||||
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
|
|
||||||
|
public class WrappedChatComponentTest {
|
||||||
|
@BeforeClass
|
||||||
|
public static void initializeBukkit() throws IllegalAccessException {
|
||||||
|
BukkitInitialization.initializePackage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testText() {
|
||||||
|
WrappedChatComponent test = WrappedChatComponent.fromText("Hello.");
|
||||||
|
String json = test.getJson();
|
||||||
|
|
||||||
|
assertNotNull(json);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user