Park these files for now if I ever want to go this route...
Signed-off-by: Irmo van den Berge <irmo.vandenberge@mailbox.org>
This commit is contained in:
1 parent
4f5752a20c
commit
f1379401f7
8 files changed
+1445
No files matched your search
@@ -13,11 +13,17 @@ import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.bergerkiller.bukkit.common.cloud.audiences.PaperAdventureAdapter;
|
||||
import com.bergerkiller.bukkit.common.cloud.captions.BKCommonLibCaptionRegistry;
|
||||
import com.bergerkiller.bukkit.common.cloud.parsers.SoundEffectParser;
|
||||
import com.bergerkiller.bukkit.common.internal.CommonBootstrap;
|
||||
import com.bergerkiller.bukkit.common.resources.ResourceKey;
|
||||
import com.bergerkiller.bukkit.common.resources.SoundEffect;
|
||||
import com.bergerkiller.mountiplex.reflection.declarations.Template;
|
||||
import net.kyori.adventure.chat.ChatType;
|
||||
import net.kyori.adventure.chat.SignedMessage;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -224,6 +230,34 @@ public class CloudSimpleHandler {
|
||||
|
||||
// Used by the help system
|
||||
this.bukkitAudiences = BukkitAudiences.create(plugin);
|
||||
|
||||
/*
|
||||
// Testing!
|
||||
PaperAdventureAdapter adapter = Template.Class.create(PaperAdventureAdapter.class, Common.TEMPLATE_RESOLVER);
|
||||
adapter.forceInitialization();
|
||||
|
||||
{
|
||||
Object o = adapter.adaptKey(Key.key("test", "world"));
|
||||
System.out.println("RESULT: " + o);
|
||||
Key key = adapter.reverseKey(o);
|
||||
System.out.println("RESULT REV: " + key);
|
||||
}
|
||||
|
||||
{
|
||||
Object o = adapter.adaptChatType(ChatType.SAY_COMMAND);
|
||||
System.out.println("RESULT: " + o);
|
||||
ChatType type = adapter.reverseChatType(o);
|
||||
System.out.println("RESULT REV: " + type);
|
||||
}
|
||||
|
||||
{
|
||||
Object o = adapter.adaptSignedMessage(SignedMessage.system("cool", Component.text("test")));
|
||||
System.out.println("RESULT: " + o);
|
||||
SignedMessage type = adapter.reverseSignedMessage(o);
|
||||
System.out.println("RESULT REV: " + type + " " + type.message() + " " + type.unsignedContent());
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
private void handleException(CommandSender sender, Throwable exception) throws Throwable {
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
import com.bergerkiller.mountiplex.reflection.ReflectionUtil;
|
||||
import com.bergerkiller.mountiplex.reflection.util.ExtendedClassWriter;
|
||||
import com.bergerkiller.mountiplex.reflection.util.FastConstructor;
|
||||
import com.bergerkiller.mountiplex.reflection.util.UniqueHash;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* Generates an implementation type of Audience that calls all the methods on
|
||||
* another (adapted) Audience implementation. All parameters for these function
|
||||
* calls are adapted using {@link PaperAdventureAdapter}.
|
||||
*/
|
||||
final class AudienceAdapterImpl implements PaperAdventureAdapter.AudienceAdapter {
|
||||
private static final UniqueHash generatedClassCtr = new UniqueHash();
|
||||
private final PaperAdventureAdapter adapter;
|
||||
private final FastConstructor<Audience> ctor;
|
||||
|
||||
public AudienceAdapterImpl(PaperAdventureAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
|
||||
final Class<?> adaptedAudienceType = adapter.getAdventureClass(
|
||||
/* String join to avoid the gradle remapper changing it */
|
||||
String.join(".", "net", "kyori", "adventure", "audience", "Audience"));
|
||||
|
||||
ExtendedClassWriter<? extends Audience> cw = ExtendedClassWriter.builder(Audience.class)
|
||||
.setFlags(ClassWriter.COMPUTE_MAXS)
|
||||
.setAccess(ACC_FINAL)
|
||||
.setExactName(AudienceAdapterImpl.class.getName() + "$AudienceImpl" + generatedClassCtr.nextHex())
|
||||
.build();
|
||||
|
||||
FieldVisitor fieldVisitor;
|
||||
MethodVisitor methodVisitor;
|
||||
|
||||
// Add field storing the PaperAdventureAdapter
|
||||
{
|
||||
fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, "adapter",
|
||||
MPLType.getDescriptor(PaperAdventureAdapter.class), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Add field storing the adapted original Audience
|
||||
{
|
||||
fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, "aud",
|
||||
MPLType.getDescriptor(adaptedAudienceType), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Add constructor assigning both fields
|
||||
{
|
||||
String ctorDesc = "(" + MPLType.getDescriptor(PaperAdventureAdapter.class) + MPLType.getDescriptor(adaptedAudienceType) + ")V";
|
||||
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC, "<init>", ctorDesc, null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 1);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), "adapter", MPLType.getDescriptor(PaperAdventureAdapter.class));
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 2);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), "aud", MPLType.getDescriptor(adaptedAudienceType));
|
||||
|
||||
methodVisitor.visitInsn(RETURN);
|
||||
methodVisitor.visitMaxs(2, 2);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Implement all methods that feature parameter types that we can adapt
|
||||
// If we cannot, leave the default implementation unless it is abstract, then throw a NotSupported exception
|
||||
List<Method> methodsToImplement = ReflectionUtil.getAllMethods(Audience.class)
|
||||
.filter(m -> !Modifier.isStatic(m.getModifiers()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Method method : methodsToImplement) {
|
||||
// Go by all method parameters and the return type and verify that we know how to adapt it
|
||||
boolean canAdapt = true;
|
||||
List<PaperAdventureAdapter.TypeAdapter> adaptedParamTypes = new ArrayList<>();
|
||||
PaperAdventureAdapter.TypeAdapter adaptedReturnType = null;
|
||||
for (Class<?> type : method.getParameterTypes()) {
|
||||
PaperAdventureAdapter.TypeAdapter paramTypeAdapter = adapter.getTypeAdapter(type);
|
||||
if (paramTypeAdapter == null) {
|
||||
canAdapt = false;
|
||||
break;
|
||||
} else {
|
||||
adaptedParamTypes.add(paramTypeAdapter);
|
||||
}
|
||||
}
|
||||
if (canAdapt) {
|
||||
adaptedReturnType = adapter.getTypeAdapter(method.getReturnType());
|
||||
if (adaptedReturnType == null) {
|
||||
canAdapt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the exact same method name on the other audience implementation, with the same (adapted) args
|
||||
Method adaptedMethod = null;
|
||||
if (canAdapt) {
|
||||
try {
|
||||
Class<?>[] params = adaptedParamTypes.stream()
|
||||
.map(PaperAdventureAdapter.TypeAdapter::getAdaptedType)
|
||||
.toArray(Class<?>[]::new);
|
||||
adaptedMethod = adaptedAudienceType.getMethod(method.getName(), params);
|
||||
if (!adaptedMethod.getReturnType().equals(adaptedReturnType.getAdaptedType())) {
|
||||
canAdapt = false;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
canAdapt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if we can't implement it
|
||||
if (!canAdapt) {
|
||||
System.out.println("Cannot implement: " + method);
|
||||
if (Modifier.isAbstract(method.getModifiers())) {
|
||||
cw.visitMethodUnsupported(method, "Not implemented by this Paper Audience adapter");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Implementing: " + method);
|
||||
|
||||
// Implement the method
|
||||
// Start by reading the adapter and aud field
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, MPLType.getName(method), MPLType.getMethodDescriptor(method), null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, cw.getInternalName(), "adapter", MPLType.getDescriptor(PaperAdventureAdapter.class));
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, cw.getInternalName(), "aud", MPLType.getDescriptor(adaptedAudienceType));
|
||||
|
||||
// Next, go by all parameters and process them with the parameter type mapping we got
|
||||
int register = 1;
|
||||
for (PaperAdventureAdapter.TypeAdapter parameterType : adaptedParamTypes) {
|
||||
register = parameterType.applyParameter(cw, methodVisitor, register);
|
||||
}
|
||||
|
||||
// Call the same method on the adapted audience
|
||||
methodVisitor.visitMethodInsn(INVOKEINTERFACE, MPLType.getInternalName(adaptedAudienceType),
|
||||
method.getName(), MPLType.getMethodDescriptor(adaptedMethod), true);
|
||||
|
||||
// Adapt the return type as well (could emit no instructions if void)
|
||||
{
|
||||
adaptedReturnType.applyReturn(cw, methodVisitor);
|
||||
}
|
||||
|
||||
// Return the value and done
|
||||
methodVisitor.visitInsn(MPLType.getOpcode(method.getReturnType(), IRETURN));
|
||||
methodVisitor.visitMaxs(6, 5);
|
||||
methodVisitor.visitEnd();
|
||||
};
|
||||
|
||||
// public MyReturnType method(long l, MyParamType type, int k)
|
||||
|
||||
/*
|
||||
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "method", "(JLcom/bergerkiller/mountiplex/ASMPlaygroundTest$MyParamType;I)Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$MyReturnType;", null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, "com/bergerkiller/mountiplex/ASMPlaygroundTest$AdaptedAudience", "adapter", "Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$Adapter;");
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, "com/bergerkiller/mountiplex/ASMPlaygroundTest$AdaptedAudience", "aud", "Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$OtherAudience;");
|
||||
|
||||
methodVisitor.visitVarInsn(LLOAD, 1);
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, "com/bergerkiller/mountiplex/ASMPlaygroundTest$AdaptedAudience", "adapter", "Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$Adapter;");
|
||||
methodVisitor.visitVarInsn(ALOAD, 3);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "com/bergerkiller/mountiplex/ASMPlaygroundTest$Adapter", "adaptParamType", "(Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$MyParamType;)Ljava/lang/Object;", false);
|
||||
methodVisitor.visitTypeInsn(CHECKCAST, "com/bergerkiller/mountiplex/ASMPlaygroundTest$OtherMyParamType");
|
||||
|
||||
methodVisitor.visitVarInsn(ILOAD, 4);
|
||||
|
||||
methodVisitor.visitMethodInsn(INVOKEINTERFACE, "com/bergerkiller/mountiplex/ASMPlaygroundTest$OtherAudience", "method", "(JLcom/bergerkiller/mountiplex/ASMPlaygroundTest$OtherMyParamType;I)Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$OtherMyReturnType;", true);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "com/bergerkiller/mountiplex/ASMPlaygroundTest$Adapter", "reverseReturnType", "(Ljava/lang/Object;)Lcom/bergerkiller/mountiplex/ASMPlaygroundTest$MyReturnType;", false);
|
||||
methodVisitor.visitInsn(ARETURN);
|
||||
methodVisitor.visitMaxs(6, 5);
|
||||
methodVisitor.visitEnd();
|
||||
*/
|
||||
|
||||
// Generate and done
|
||||
this.ctor = new FastConstructor<>(cw.generateConstructor(PaperAdventureAdapter.class, adaptedAudienceType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audience reverseAudience(Object audience) {
|
||||
return this.ctor.newInstance(this.adapter, audience);
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
import com.bergerkiller.mountiplex.reflection.ReflectionUtil;
|
||||
import com.bergerkiller.mountiplex.reflection.util.ExtendedClassWriter;
|
||||
import com.bergerkiller.mountiplex.reflection.util.FastConstructor;
|
||||
import com.bergerkiller.mountiplex.reflection.util.UniqueHash;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.platform.AudienceProvider;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
|
||||
/**
|
||||
* Generates an implementation type of AudienceProvider that calls all the methods on
|
||||
* another (adapted) AudienceProvider implementation. All parameters for these function
|
||||
* calls are adapted using {@link PaperAdventureAdapter}.
|
||||
*/
|
||||
final class AudienceProviderAdapterImpl implements PaperAdventureAdapter.AudienceProviderAdapter {
|
||||
private static final UniqueHash generatedClassCtr = new UniqueHash();
|
||||
private final PaperAdventureAdapter adapter;
|
||||
private final FastConstructor<AudienceProvider> ctor;
|
||||
|
||||
public AudienceProviderAdapterImpl(PaperAdventureAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
|
||||
final Class<?> adaptedAudienceProviderType = adapter.getAdventureClass(
|
||||
/* String join to avoid the gradle remapper changing it */
|
||||
String.join(".", "net", "kyori", "adventure", "platform", "AudienceProvider"));
|
||||
|
||||
ExtendedClassWriter<? extends AudienceProvider> cw = ExtendedClassWriter.builder(AudienceProvider.class)
|
||||
.setFlags(ClassWriter.COMPUTE_MAXS)
|
||||
.setAccess(ACC_FINAL)
|
||||
.setExactName(AudienceProviderAdapterImpl.class.getName() + "$AudienceProviderImpl" + generatedClassCtr.nextHex())
|
||||
.build();
|
||||
|
||||
|
||||
FieldVisitor fieldVisitor;
|
||||
MethodVisitor methodVisitor;
|
||||
|
||||
// Add field storing the PaperAdventureAdapter
|
||||
{
|
||||
fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, "adapter",
|
||||
MPLType.getDescriptor(PaperAdventureAdapter.class), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Add field storing the adapted original Audience
|
||||
{
|
||||
fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, "aud",
|
||||
MPLType.getDescriptor(adaptedAudienceProviderType), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Add constructor assigning both fields
|
||||
{
|
||||
String ctorDesc = "(" + MPLType.getDescriptor(PaperAdventureAdapter.class) + MPLType.getDescriptor(adaptedAudienceProviderType) + ")V";
|
||||
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC, "<init>", ctorDesc, null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 1);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), "adapter", MPLType.getDescriptor(PaperAdventureAdapter.class));
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 2);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), "aud", MPLType.getDescriptor(adaptedAudienceProviderType));
|
||||
|
||||
methodVisitor.visitInsn(RETURN);
|
||||
methodVisitor.visitMaxs(2, 2);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Implement all methods that feature parameter types that we can adapt
|
||||
// If we cannot, leave the default implementation unless it is abstract, then throw a NotSupported exception
|
||||
List<Method> methodsToImplement = ReflectionUtil.getAllMethods(Audience.class)
|
||||
.filter(m -> !Modifier.isStatic(m.getModifiers()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Method method : methodsToImplement) {
|
||||
// Go by all method parameters and the return type and verify that we know how to adapt it
|
||||
boolean canAdapt = true;
|
||||
List<PaperAdventureAdapter.TypeAdapter> adaptedParamTypes = new ArrayList<>();
|
||||
PaperAdventureAdapter.TypeAdapter adaptedReturnType = null;
|
||||
for (Class<?> type : method.getParameterTypes()) {
|
||||
PaperAdventureAdapter.TypeAdapter paramTypeAdapter = adapter.getTypeAdapter(type);
|
||||
if (paramTypeAdapter == null) {
|
||||
canAdapt = false;
|
||||
break;
|
||||
} else {
|
||||
adaptedParamTypes.add(paramTypeAdapter);
|
||||
}
|
||||
}
|
||||
if (canAdapt) {
|
||||
adaptedReturnType = adapter.getTypeAdapter(method.getReturnType());
|
||||
if (adaptedReturnType == null) {
|
||||
canAdapt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the exact same method name on the other audience implementation, with the same (adapted) args
|
||||
Method adaptedMethod = null;
|
||||
if (canAdapt) {
|
||||
try {
|
||||
Class<?>[] params = adaptedParamTypes.stream()
|
||||
.map(PaperAdventureAdapter.TypeAdapter::getAdaptedType)
|
||||
.toArray(Class<?>[]::new);
|
||||
adaptedMethod = adaptedAudienceProviderType.getMethod(method.getName(), params);
|
||||
if (!adaptedMethod.getReturnType().equals(adaptedReturnType.getAdaptedType())) {
|
||||
canAdapt = false;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
canAdapt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if we can't implement it
|
||||
if (!canAdapt) {
|
||||
System.out.println("Cannot implement: " + method);
|
||||
if (Modifier.isAbstract(method.getModifiers())) {
|
||||
cw.visitMethodUnsupported(method, "Not implemented by this Paper Audience adapter");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Implementing: " + method);
|
||||
|
||||
// Implement the method
|
||||
// Start by reading the adapter and aud field
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, MPLType.getName(method), MPLType.getMethodDescriptor(method), null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, cw.getInternalName(), "adapter", MPLType.getDescriptor(PaperAdventureAdapter.class));
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, cw.getInternalName(), "aud", MPLType.getDescriptor(adaptedAudienceProviderType));
|
||||
|
||||
// Next, go by all parameters and process them with the parameter type mapping we got
|
||||
int register = 1;
|
||||
for (PaperAdventureAdapter.TypeAdapter parameterType : adaptedParamTypes) {
|
||||
register = parameterType.applyParameter(cw, methodVisitor, register);
|
||||
}
|
||||
|
||||
// Call the same method on the adapted audience
|
||||
methodVisitor.visitMethodInsn(INVOKEINTERFACE, MPLType.getInternalName(adaptedAudienceProviderType),
|
||||
method.getName(), MPLType.getMethodDescriptor(adaptedMethod), true);
|
||||
|
||||
// Adapt the return type as well (could emit no instructions if void)
|
||||
{
|
||||
adaptedReturnType.applyReturn(cw, methodVisitor);
|
||||
}
|
||||
|
||||
// Return the value and done
|
||||
methodVisitor.visitInsn(MPLType.getOpcode(method.getReturnType(), IRETURN));
|
||||
methodVisitor.visitMaxs(6, 5);
|
||||
methodVisitor.visitEnd();
|
||||
};
|
||||
|
||||
// Generate and done
|
||||
this.ctor = new FastConstructor<>(cw.generateConstructor(PaperAdventureAdapter.class, adaptedAudienceProviderType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudienceProvider reverseAudienceProvider(Object audienceProvider) {
|
||||
return this.ctor.newInstance(this.adapter, audienceProvider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
/**
|
||||
* Type Adapter. These implementations exist:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.key.Key</li>
|
||||
* <li>net.kyori.adventure.text.ComponentLike</li>
|
||||
* <li>net.kyori.adventure.text.Component</li>
|
||||
* <li>net.kyori.adventure.audience.MessageType</li>
|
||||
* <li>net.kyori.adventure.identity.Identified</li>
|
||||
* <li>net.kyori.adventure.identity.Identity</li>
|
||||
* <li>net.kyori.adventure.chat.ChatType.Bound</li>
|
||||
* <li>net.kyori.adventure.chat.SignedMessage</li>
|
||||
* <li>net.kyori.adventure.chat.SignedMessage.Signature</li>
|
||||
* <li>net.kyori.adventure.title.Title</li>
|
||||
* <li>net.kyori.adventure.title.TitlePart</li>
|
||||
* </ul>
|
||||
*
|
||||
* These are not implemented and these functionalities will not work as a result:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.bossbar.BossBar</li>
|
||||
* <li>net.kyori.adventure.sound.Sound</li>
|
||||
* <li>net.kyori.adventure.sound.SoundStop</li>
|
||||
* <li>net.kyori.adventure.sound.Sound.Emitter</li>
|
||||
* <li>net.kyori.adventure.inventory.Book.Builder</li>
|
||||
* <li>net.kyori.adventure.inventory.Book</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackInfoLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequestLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequest</li>
|
||||
* <li>net.kyori.adventure.dialog.DialogLike</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <A> Type we know
|
||||
* @param <B> Unknown type
|
||||
*/
|
||||
public interface AudienceTypeAdapter<A, B> {
|
||||
/**
|
||||
* Adapts the type we know into the unknown type
|
||||
*
|
||||
* @param value Known type
|
||||
* @return Unknown type
|
||||
*/
|
||||
B adapt(A value);
|
||||
/**
|
||||
* Restores the unknown type back into a type we know (reverse)
|
||||
*
|
||||
* @param value Unknown type
|
||||
* @return Known type
|
||||
*/
|
||||
A restore(B value);
|
||||
}
|
||||
+691
@@ -0,0 +1,691 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
import com.bergerkiller.mountiplex.reflection.declarations.Template;
|
||||
import com.bergerkiller.mountiplex.reflection.util.BoxedType;
|
||||
import com.bergerkiller.mountiplex.reflection.util.ExtendedClassWriter;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.CHECKCAST;
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||
|
||||
/**
|
||||
* Converts types from Adventure between the BKCommonLib shaded types and the
|
||||
* types declared by Paper in the server.<br>
|
||||
* <br>
|
||||
* These Adventure types can be adapted:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.key.audience.Audience</li>
|
||||
* <li>net.kyori.adventure.key.Key</li>
|
||||
* <li>net.kyori.adventure.text.Component</li>
|
||||
* <li>net.kyori.adventure.audience.MessageType</li>
|
||||
* <li>net.kyori.adventure.identity.Identity</li>
|
||||
* <li>net.kyori.adventure.chat.ChatType.Bound</li>
|
||||
* <li>net.kyori.adventure.chat.SignedMessage</li>
|
||||
* <li>net.kyori.adventure.title.TitlePart</li>
|
||||
* </ul>
|
||||
*
|
||||
* These are not implemented and these functionalities will not work as a result:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.bossbar.BossBar</li>
|
||||
* <li>net.kyori.adventure.sound.Sound</li>
|
||||
* <li>net.kyori.adventure.sound.SoundStop</li>
|
||||
* <li>net.kyori.adventure.sound.Sound.Emitter</li>
|
||||
* <li>net.kyori.adventure.inventory.Book.Builder</li>
|
||||
* <li>net.kyori.adventure.inventory.Book</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackInfoLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequestLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequest</li>
|
||||
* <li>net.kyori.adventure.dialog.DialogLike</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Template.Import("com.bergerkiller.bukkit.common.cloud.audiences.PaperAdventureAdapter")
|
||||
@Template.InstanceType("net.kyori.adventure.audience.Audience")
|
||||
public abstract class PaperAdventureAdapter extends Template.Class<Template.Handle> {
|
||||
private final Function<String, Class<?>> adventureClassLoader = getAdventureClassLoader();
|
||||
private final Map<Class<?>, TypeAdapter> typeAdapters = new HashMap<>();
|
||||
|
||||
public final SignedMessageFactory<Object> adaptSignedMessageFactory =
|
||||
new SignedMessageFactoryImpl<>(getAdventureClass(
|
||||
/* String join to avoid the gradle remapper changing it */
|
||||
String.join(".", "net", "kyori", "adventure", "chat", "SignedMessage")));
|
||||
public final SignedMessageFactory<net.kyori.adventure.chat.SignedMessage> reverseSignedMessageFactory =
|
||||
new SignedMessageFactoryImpl<>(net.kyori.adventure.chat.SignedMessage.class);
|
||||
public final AudienceAdapter adaptAudience = new AudienceAdapterImpl(this);
|
||||
public final AudienceProviderAdapter adaptAudienceProvider = new AudienceProviderAdapterImpl(this);
|
||||
|
||||
public PaperAdventureAdapter() {
|
||||
// Register all the pass-through (no adapting) types that can be safely used
|
||||
// When these types are encountered, it is assumed the adapted method will use the same type
|
||||
BoxedType.getUnboxedTypes().forEach(this::registerPassThroughAdapter);
|
||||
BoxedType.getBoxedTypes().forEach(this::registerPassThroughAdapter);
|
||||
registerPassThroughAdapter(UUID.class);
|
||||
registerPassThroughAdapter(String.class);
|
||||
registerPassThroughAdapter(Predicate.class);
|
||||
registerPassThroughAdapter(Object.class);
|
||||
|
||||
// Register all the type adapters that this class supports
|
||||
registerStandardAdapter(
|
||||
net.kyori.adventure.key.Key.class,
|
||||
String.join(".", "net", "kyori", "adventure", "key", "Key"),
|
||||
"adaptKey", "reverseKey");
|
||||
registerStandardAdapter(
|
||||
net.kyori.adventure.identity.Identity.class,
|
||||
String.join(".", "net", "kyori", "adventure", "identity", "Identity"),
|
||||
"adaptIdentity", "reverseIdentity");
|
||||
registerStandardAdapter(
|
||||
net.kyori.adventure.text.Component.class,
|
||||
String.join(".", "net", "kyori", "adventure", "text", "Component"),
|
||||
"adaptComponent", "reverseComponent");
|
||||
registerStandardAdapter(
|
||||
net.kyori.adventure.audience.Audience.class,
|
||||
String.join(".", "net", "kyori", "adventure", "audience", "Audience"),
|
||||
"adaptAudience", "reverseAudience");
|
||||
registerStandardAdapter(
|
||||
net.kyori.adventure.platform.AudienceProvider.class,
|
||||
String.join(".", "net", "kyori", "adventure", "platform", "AudienceProvider"),
|
||||
"adaptAudienceProvider", "reverseAudienceProvider");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a (foreign) Adventure library class by name
|
||||
*
|
||||
* @param name Name of the class
|
||||
* @return Class
|
||||
* @throws UnsupportedOperationException If this type does not exist (somehow?)
|
||||
*/
|
||||
public final Class<?> getAdventureClass(String name) {
|
||||
return adventureClassLoader.apply(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type adapter information for an API Type.
|
||||
* Returns null if the type is unknown and not supported for adapting.
|
||||
*
|
||||
* @param type API Type
|
||||
* @return TypeAdapter
|
||||
*/
|
||||
public final TypeAdapter getTypeAdapter(Class<?> type) {
|
||||
return typeAdapters.get(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* <ADAPT_KEY>
|
||||
* public static net.kyori.adventure.key.Key adaptKey(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key key) {
|
||||
* return net.kyori.adventure.key.Key.key(key.namespace(), key.value());
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_KEY%")
|
||||
public abstract Object adaptKey(net.kyori.adventure.key.Key key);
|
||||
|
||||
/*
|
||||
* <REVERSE_KEY>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key reverseKey(net.kyori.adventure.key.Key key) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key.key(key.namespace(), key.value());
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_KEY%")
|
||||
public abstract net.kyori.adventure.key.Key reverseKey(Object key);
|
||||
|
||||
/*
|
||||
* <ADAPT_MESSAGE_TYPE>
|
||||
* public static net.kyori.adventure.audience.MessageType adaptMessageType(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.audience.MessageType messageType) {
|
||||
* if (messageType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.audience.MessageType.SYSTEM) {
|
||||
* return net.kyori.adventure.audience.MessageType.SYSTEM;
|
||||
* } else {
|
||||
* return net.kyori.adventure.audience.MessageType.CHAT;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_MESSAGE_TYPE%")
|
||||
public abstract Object adaptMessageType(net.kyori.adventure.key.Key messageType);
|
||||
|
||||
/*
|
||||
* <REVERSE_MESSAGE_TYPE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.audience.MessageType reverseMessageType(net.kyori.adventure.audience.MessageType messageType) {
|
||||
* if (messageType == net.kyori.adventure.audience.MessageType.SYSTEM) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.audience.MessageType.SYSTEM;
|
||||
* } else {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.audience.MessageType.CHAT;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_MESSAGE_TYPE%")
|
||||
public abstract net.kyori.adventure.key.Key reverseMessageType(Object messageType);
|
||||
|
||||
/*
|
||||
* <ADAPT_IDENTITY>
|
||||
* public static net.kyori.adventure.identity.Identity adaptIdentity(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity identity) {
|
||||
* if (identity == null) {
|
||||
* return null;
|
||||
* } else if (identity == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity.nil()) {
|
||||
* return net.kyori.adventure.identity.Identity.nil();
|
||||
* } else {
|
||||
* return net.kyori.adventure.identity.Identity.identity(identity.uuid());
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_IDENTITY%")
|
||||
public abstract Object adaptIdentity(net.kyori.adventure.identity.Identity identity);
|
||||
|
||||
/*
|
||||
* <REVERSE_IDENTITY>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity reverseIdentity(net.kyori.adventure.identity.Identity identity) {
|
||||
* if (identity == null) {
|
||||
* return null;
|
||||
* } else if (identity == net.kyori.adventure.identity.Identity.nil()) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity.nil();
|
||||
* } else {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity.identity(identity.uuid());
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_IDENTITY%")
|
||||
public abstract net.kyori.adventure.identity.Identity reverseIdentity(Object identity);
|
||||
|
||||
/*
|
||||
* <ADAPT_COMPONENT>
|
||||
* public static net.kyori.adventure.text.Component adaptComponent(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component component) {
|
||||
* if (component == null)
|
||||
* return null;
|
||||
* if (component == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component.empty())
|
||||
* return net.kyori.adventure.text.Component.empty();
|
||||
*
|
||||
* String json = (String) com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(component);
|
||||
*
|
||||
* return (net.kyori.adventure.text.Component)
|
||||
* net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(json);
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_COMPONENT%")
|
||||
public abstract Object adaptComponent(net.kyori.adventure.text.Component component);
|
||||
|
||||
/*
|
||||
* <REVERSE_COMPONENT>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component reverseComponent(net.kyori.adventure.text.Component component) {
|
||||
* if (component == null)
|
||||
* return null;
|
||||
* if (component == net.kyori.adventure.text.Component.empty())
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component.empty();
|
||||
*
|
||||
* String json = (String) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(component);
|
||||
*
|
||||
* return (com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component)
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(json);
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_COMPONENT%")
|
||||
public abstract net.kyori.adventure.text.Component reverseComponent(Object component);
|
||||
|
||||
/*
|
||||
* <ADAPT_CHAT_TYPE>
|
||||
* public static net.kyori.adventure.chat.ChatType adaptChatType(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType chatType) {
|
||||
* #if version >= 1.19
|
||||
* if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.CHAT) {
|
||||
* return net.kyori.adventure.chat.ChatType.CHAT;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.SAY_COMMAND) {
|
||||
* return net.kyori.adventure.chat.ChatType.SAY_COMMAND;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.MSG_COMMAND_INCOMING) {
|
||||
* return net.kyori.adventure.chat.ChatType.MSG_COMMAND_INCOMING;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.MSG_COMMAND_OUTGOING) {
|
||||
* return net.kyori.adventure.chat.ChatType.MSG_COMMAND_OUTGOING;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_INCOMING) {
|
||||
* return net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_INCOMING;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_OUTGOING) {
|
||||
* return net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_OUTGOING;
|
||||
* } else if (chatType == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.EMOTE_COMMAND) {
|
||||
* return net.kyori.adventure.chat.ChatType.EMOTE_COMMAND;
|
||||
* } else {
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key key = chatType.key();
|
||||
* net.kyori.adventure.key.Key adaptedKey =
|
||||
* net.kyori.adventure.key.Key.key(key.namespace(), key.value());
|
||||
* return net.kyori.adventure.chat.ChatType.chatType(adaptedKey);
|
||||
* }
|
||||
* #else
|
||||
* return null;
|
||||
* #endif
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_CHAT_TYPE%")
|
||||
public abstract Object adaptChatType(net.kyori.adventure.chat.ChatType chatType);
|
||||
|
||||
/*
|
||||
* <REVERSE_CHAT_TYPE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType reverseChatType(net.kyori.adventure.chat.ChatType chatType) {
|
||||
* #if version >= 1.19
|
||||
* if (chatType == net.kyori.adventure.chat.ChatType.CHAT) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.CHAT;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.SAY_COMMAND) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.SAY_COMMAND;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.MSG_COMMAND_INCOMING) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.MSG_COMMAND_INCOMING;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.MSG_COMMAND_OUTGOING) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.MSG_COMMAND_OUTGOING;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_INCOMING) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_INCOMING;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_OUTGOING) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.TEAM_MSG_COMMAND_OUTGOING;
|
||||
* } else if (chatType == net.kyori.adventure.chat.ChatType.EMOTE_COMMAND) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.EMOTE_COMMAND;
|
||||
* } else {
|
||||
* net.kyori.adventure.key.Key key = chatType.key();
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key reversedKey =
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.key.Key.key(key.namespace(), key.value());
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.chatType(reversedKey);
|
||||
* }
|
||||
* #else
|
||||
* return null;
|
||||
* #endif
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_CHAT_TYPE%")
|
||||
public abstract net.kyori.adventure.chat.ChatType reverseChatType(Object chatType);
|
||||
|
||||
/*
|
||||
* <ADAPT_BOUND_CHAT_TYPE>
|
||||
* public static net.kyori.adventure.chat.ChatType.Bound reverseChatType(PaperAdventureAdapter adapter, com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.Bound boundChatType) {
|
||||
* #if version >= 1.19
|
||||
* net.kyori.adventure.chat.ChatType type = (net.kyori.adventure.chat.ChatType) adapter.adaptChatType(boundChatType.type());
|
||||
* net.kyori.adventure.text.Component name = (net.kyori.adventure.text.Component) adapter.adaptComponent(boundChatType.name());
|
||||
* net.kyori.adventure.text.Component target = (net.kyori.adventure.text.Component) adapter.adaptComponent(boundChatType.target());
|
||||
* return type.bind(name, target);
|
||||
* #else
|
||||
* return null;
|
||||
* #endif
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_BOUND_CHAT_TYPE%")
|
||||
public abstract Object adaptBoundChatType(PaperAdventureAdapter adapter, net.kyori.adventure.chat.ChatType.Bound boundChatType);
|
||||
|
||||
public final Object adaptBoundChatType(net.kyori.adventure.chat.ChatType.Bound boundChatType) {
|
||||
return adaptBoundChatType(this, boundChatType);
|
||||
}
|
||||
|
||||
/*
|
||||
* <REVERSE_BOUND_CHAT_TYPE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType.Bound reverseChatType(PaperAdventureAdapter adapter, net.kyori.adventure.chat.ChatType.Bound boundChatType) {
|
||||
* #if version >= 1.19
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.ChatType type = adapter.reverseChatType(boundChatType.type());
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component name = adapter.reverseComponent(boundChatType.name());
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component target = adapter.reverseComponent(boundChatType.target());
|
||||
* return type.bind(name, target);
|
||||
* #else
|
||||
* return null;
|
||||
* #endif
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_BOUND_CHAT_TYPE%")
|
||||
public abstract net.kyori.adventure.chat.ChatType.Bound reverseBoundChatType(PaperAdventureAdapter adapter, Object boundChatType);
|
||||
|
||||
public final net.kyori.adventure.chat.ChatType.Bound reverseBoundChatType(Object boundChatType) {
|
||||
return reverseBoundChatType(this, boundChatType);
|
||||
}
|
||||
|
||||
/*
|
||||
* <ADAPT_SIGNED_MESSAGE_SIGNATURE>
|
||||
* public static net.kyori.adventure.chat.SignedMessage.Signature adaptSignedMessageSignature(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage.Signature signature) {
|
||||
* if (signature == null)
|
||||
* return null;
|
||||
* return net.kyori.adventure.chat.SignedMessage.signature(signature.bytes());
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_SIGNED_MESSAGE_SIGNATURE%")
|
||||
public abstract Object adaptSignedMessageSignature(net.kyori.adventure.chat.SignedMessage.Signature signature);
|
||||
|
||||
/*
|
||||
* <REVERSE_SIGNED_MESSAGE_SIGNATURE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage.Signature reverseSignedMessageSignature(net.kyori.adventure.chat.SignedMessage.Signature signature) {
|
||||
* if (signature == null)
|
||||
* return null;
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage.signature(signature.bytes());
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_SIGNED_MESSAGE_SIGNATURE%")
|
||||
public abstract net.kyori.adventure.chat.SignedMessage.Signature reverseSignedMessageSignature(Object signature);
|
||||
|
||||
/*
|
||||
* <ADAPT_SIGNED_MESSAGE>
|
||||
* public static net.kyori.adventure.chat.SignedMessage adaptSignedMessage(PaperAdventureAdapter adapter, com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage signedMessage) {
|
||||
* if (signedMessage == null)
|
||||
* return null;
|
||||
*
|
||||
* java.time.Instant timestamp = signedMessage.timestamp();
|
||||
* long salt = signedMessage.salt();
|
||||
* String message = signedMessage.message();
|
||||
*
|
||||
* net.kyori.adventure.chat.SignedMessage$Signature signature =
|
||||
* (net.kyori.adventure.chat.SignedMessage$Signature) adapter.adaptSignedMessageSignature(signedMessage.signature());
|
||||
* net.kyori.adventure.text.Component unsignedContent =
|
||||
* (net.kyori.adventure.text.Component) adapter.adaptComponent(signedMessage.unsignedContent());
|
||||
* net.kyori.adventure.identity.Identity identity =
|
||||
* (net.kyori.adventure.identity.Identity) adapter.adaptIdentity(signedMessage.identity());
|
||||
*
|
||||
* return (net.kyori.adventure.chat.SignedMessage) adapter.adaptSignedMessageFactory.create(
|
||||
* timestamp, salt, message, signature, unsignedContent, identity );
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_SIGNED_MESSAGE%")
|
||||
public abstract Object adaptSignedMessage(PaperAdventureAdapter adapter, net.kyori.adventure.chat.SignedMessage signedMessage);
|
||||
|
||||
public final Object adaptSignedMessage(net.kyori.adventure.chat.SignedMessage signedMessage) {
|
||||
return adaptSignedMessage(this, signedMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* <REVERSE_SIGNED_MESSAGE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage reverseSignedMessage(PaperAdventureAdapter adapter, net.kyori.adventure.chat.SignedMessage signedMessage) {
|
||||
* if (signedMessage == null)
|
||||
* return null;
|
||||
*
|
||||
* java.time.Instant timestamp = signedMessage.timestamp();
|
||||
* long salt = signedMessage.salt();
|
||||
* String message = signedMessage.message();
|
||||
*
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage$Signature signature =
|
||||
* adapter.reverseSignedMessageSignature(signedMessage.signature());
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component unsignedContent =
|
||||
* adapter.reverseComponent(signedMessage.unsignedContent());
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.identity.Identity identity =
|
||||
* adapter.reverseIdentity(signedMessage.identity());
|
||||
*
|
||||
* return (com.bergerkiller.bukkit.common.dep.net.kyori.adventure.chat.SignedMessage) adapter.reverseSignedMessageFactory.create(
|
||||
* timestamp, salt, message, signature, unsignedContent, identity );
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_SIGNED_MESSAGE%")
|
||||
public abstract net.kyori.adventure.chat.SignedMessage reverseSignedMessage(PaperAdventureAdapter adapter, Object signedMessage);
|
||||
|
||||
public final net.kyori.adventure.chat.SignedMessage reverseSignedMessage(Object signedMessage) {
|
||||
return reverseSignedMessage(this, signedMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* <ADAPT_TITLE>
|
||||
* public static net.kyori.adventure.title.Title adaptTitle(PaperAdventureAdapter adapter, com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title title) {
|
||||
* if (title == null)
|
||||
* return null;
|
||||
*
|
||||
* // Adapt times
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title$Times origTimes = title.times();
|
||||
* net.kyori.adventure.title.Title$Times times;
|
||||
* if (origTimes == null) {
|
||||
* times = null;
|
||||
* } else if (origTimes == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title.DEFAULT_TIMES) {
|
||||
* times = net.kyori.adventure.title.Title.DEFAULT_TIMES;
|
||||
* } else {
|
||||
* times = net.kyori.adventure.title.Title$Times.times(
|
||||
* origTimes.fadeIn(), origTimes.stay(), origTimes.fadeOut());
|
||||
* }
|
||||
*
|
||||
* // Adapt the other elements
|
||||
* net.kyori.adventure.text.Component titleText =
|
||||
* (net.kyori.adventure.text.Component) adapter.adaptComponent(title.title());
|
||||
* net.kyori.adventure.text.Component subTitleText =
|
||||
* (net.kyori.adventure.text.Component) adapter.adaptComponent(title.subtitle());
|
||||
*
|
||||
* // Build
|
||||
* return net.kyori.adventure.title.Title.title(titleText, subTitleText, times);
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_TITLE%")
|
||||
public abstract Object adaptTitle(PaperAdventureAdapter adapter, net.kyori.adventure.title.Title title);
|
||||
|
||||
public final Object adaptTitle(net.kyori.adventure.title.Title title) {
|
||||
return adaptTitle(this, title);
|
||||
}
|
||||
|
||||
/*
|
||||
* <REVERSE_TITLE>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title reverseTitle(PaperAdventureAdapter adapter, net.kyori.adventure.title.Title title) {
|
||||
* if (title == null)
|
||||
* return null;
|
||||
*
|
||||
* // Reverse times
|
||||
* net.kyori.adventure.title.Title$Times origTimes = title.times();
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title$Times times;
|
||||
* if (origTimes == null) {
|
||||
* times = null;
|
||||
* } else if (origTimes == net.kyori.adventure.title.Title.DEFAULT_TIMES) {
|
||||
* times = com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title.DEFAULT_TIMES;
|
||||
* } else {
|
||||
* times = com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title$Times.times(
|
||||
* origTimes.fadeIn(), origTimes.stay(), origTimes.fadeOut());
|
||||
* }
|
||||
*
|
||||
* // Reverse the other elements
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component titleText =
|
||||
* adapter.reverseComponent(title.title());
|
||||
* com.bergerkiller.bukkit.common.dep.net.kyori.adventure.text.Component subTitleText =
|
||||
* adapter.reverseComponent(title.subtitle());
|
||||
*
|
||||
* // Build
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.Title.title(titleText, subTitleText, times);
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_TITLE%")
|
||||
public abstract net.kyori.adventure.title.Title reverseTitle(PaperAdventureAdapter adapter, Object title);
|
||||
|
||||
public final net.kyori.adventure.title.Title reverseTitle(Object title) {
|
||||
return reverseTitle(this, title);
|
||||
}
|
||||
|
||||
/*
|
||||
* <ADAPT_TITLE_PART>
|
||||
* public static net.kyori.adventure.title.TitlePart<?> adaptMessageType(com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart<?> titlePart) {
|
||||
* if (titlePart == null) {
|
||||
* return null;
|
||||
* } else if (titlePart == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.TITLE) {
|
||||
* return net.kyori.adventure.title.TitlePart.TITLE;
|
||||
* } else if (titlePart == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.SUBTITLE) {
|
||||
* return net.kyori.adventure.title.TitlePart.SUBTITLE;
|
||||
* } else if (titlePart == com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.TIMES) {
|
||||
* return net.kyori.adventure.title.TitlePart.TIMES;
|
||||
* } else {
|
||||
* throw new IllegalArgumentException("Unknown title part: " + titlePart);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%ADAPT_TITLE_PART%")
|
||||
public abstract Object adaptTitlePart(net.kyori.adventure.title.TitlePart<?> titlePart);
|
||||
|
||||
/*
|
||||
* <REVERSE_TITLE_PART>
|
||||
* public static com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart<?> reverseMessageType(net.kyori.adventure.title.TitlePart<?> titlePart) {
|
||||
* if (titlePart == null) {
|
||||
* return null;
|
||||
* } else if (titlePart == net.kyori.adventure.title.TitlePart.TITLE) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.TITLE;
|
||||
* } else if (titlePart == net.kyori.adventure.title.TitlePart.SUBTITLE) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.SUBTITLE;
|
||||
* } else if (titlePart == net.kyori.adventure.title.TitlePart.TIMES) {
|
||||
* return com.bergerkiller.bukkit.common.dep.net.kyori.adventure.title.TitlePart.TIMES;
|
||||
* } else {
|
||||
* throw new IllegalArgumentException("Unknown title part: " + titlePart);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Template.Generated("%REVERSE_TITLE_PART%")
|
||||
public abstract <T> net.kyori.adventure.title.TitlePart<T> reverseTitlePart(Object titlePart);
|
||||
|
||||
public final net.kyori.adventure.audience.Audience reverseAudience(Object audience) {
|
||||
return adaptAudience.reverseAudience(audience);
|
||||
}
|
||||
|
||||
public final net.kyori.adventure.platform.AudienceProvider reverseAudienceProvider(Object audienceProvider) {
|
||||
return adaptAudienceProvider.reverseAudienceProvider(audienceProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a Type Adapter that performs no adapting at all, passing it through.
|
||||
*
|
||||
* @param type Type
|
||||
*/
|
||||
private void registerPassThroughAdapter(
|
||||
final Class<?> type
|
||||
) {
|
||||
registerTypeAdapter(new TypeAdapter() {
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAdaptedType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int applyParameter(ExtendedClassWriter<?> cw, MethodVisitor mv, int register) {
|
||||
return MPLType.visitVarILoad(mv, register, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyReturn(ExtendedClassWriter<?> cw, MethodVisitor mv) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerStandardAdapter(
|
||||
final Class<?> type, /* For example: net.kyori.adventure.title.TitlePart.class */
|
||||
final String adaptedTypeName, /* For example: "net.kyori.adventure.title.TitlePart" */
|
||||
final String adaptMethodName, /* For example: "adaptTitlePart" */
|
||||
final String reverseMethodName /* For example: "reverseTitlePart" */
|
||||
) {
|
||||
final Class<?> adaptedType = getAdventureClass(adaptedTypeName);
|
||||
registerTypeAdapter(new TypeAdapter() {
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAdaptedType() {
|
||||
return adaptedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int applyParameter(ExtendedClassWriter<?> cw, MethodVisitor mv, int register) {
|
||||
// Access 'adapter' field of the adapter class we generate
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, cw.getInternalName(), "adapter", MPLType.getDescriptor(PaperAdventureAdapter.class));
|
||||
|
||||
// Load the parameter from the stack, and adapt it
|
||||
int nextRegister = MPLType.visitVarILoad(mv, register, type);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MPLType.getInternalName(PaperAdventureAdapter.class),
|
||||
adaptMethodName, "(" + MPLType.getDescriptor(type) + ")Ljava/lang/Object;", false);
|
||||
mv.visitTypeInsn(CHECKCAST, MPLType.getInternalName(adaptedType));
|
||||
return nextRegister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyReturn(ExtendedClassWriter<?> cw, MethodVisitor mv) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MPLType.getInternalName(PaperAdventureAdapter.class), reverseMethodName,
|
||||
"(Ljava/lang/Object;)" + MPLType.getDescriptor(type), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerTypeAdapter(TypeAdapter typeAdapter) {
|
||||
typeAdapters.put(typeAdapter.getType(), typeAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the (foreign) Adventure library Class and then initializes a loader for other
|
||||
* types in the Adventure library.
|
||||
*
|
||||
* @return Loader
|
||||
*/
|
||||
private static Function<String, Class<?>> getAdventureClassLoader() {
|
||||
final String prefix;
|
||||
final ClassLoader classLoader;
|
||||
try {
|
||||
String audienceName = String.join(".", "net", "kyori", "adventure", "audience", "Audience");
|
||||
Class<?> audienceType = Class.forName(audienceName);
|
||||
prefix = audienceType.getName().endsWith(audienceName)
|
||||
? audienceType.getName().substring(0, audienceType.getName().length() - audienceName.length())
|
||||
: "";
|
||||
classLoader = audienceType.getClassLoader();
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UnsupportedOperationException("Native Adventure library could not be found on the server");
|
||||
}
|
||||
|
||||
return name -> {
|
||||
try {
|
||||
return Class.forName(prefix + name, false, classLoader);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UnsupportedOperationException("Adventure library type not found: " + name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface SignedMessageFactory<T> {
|
||||
T create(
|
||||
final java.time.Instant timestamp,
|
||||
final long salt,
|
||||
final String message,
|
||||
final Object /* net.kyori.adventure.chat.SignedMessage$Signature */ signature,
|
||||
final Object /* net.kyori.adventure.text.Component */ unsignedContent,
|
||||
final Object /* net.kyori.adventure.identity.Identity */ identity
|
||||
);
|
||||
}
|
||||
|
||||
public interface AudienceAdapter {
|
||||
net.kyori.adventure.audience.Audience reverseAudience(
|
||||
final Object /* net.kyori.adventure.audience.Audience */ audience
|
||||
);
|
||||
}
|
||||
|
||||
public interface AudienceProviderAdapter {
|
||||
net.kyori.adventure.platform.AudienceProvider reverseAudienceProvider(
|
||||
final Object /* net.kyori.adventure.platform.AudienceProvider */ audienceProvider
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A single type adapter responsible for converting from a public API Type to an adapted
|
||||
* (foreign) Adventure type. Handles generating the required ASM for converting
|
||||
* parameter types before calling the foreign method and converting the method result
|
||||
* back into API types.
|
||||
*/
|
||||
public interface TypeAdapter {
|
||||
/**
|
||||
* Gets the API type (known to BKCommonLib at compile time)
|
||||
*
|
||||
* @return API Type
|
||||
*/
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Gets the adapted type (not known to BKCommonLib at compile time)
|
||||
*
|
||||
* @return Adapted Type
|
||||
*/
|
||||
Class<?> getAdaptedType();
|
||||
|
||||
/**
|
||||
* Adapts the type from API type to Adapted Type for a method parameter
|
||||
*
|
||||
* @param cw ExtendedClassWriter
|
||||
* @param mv MethodVisitor
|
||||
* @param register Parameter register position
|
||||
* @return Parameter register position for the next parameter (register + size)
|
||||
*/
|
||||
int applyParameter(ExtendedClassWriter<?> cw, MethodVisitor mv, int register);
|
||||
|
||||
/**
|
||||
* Adapts the type from Adapted Type to API type for a return value
|
||||
*
|
||||
* @param cw ExtendedClassWriter
|
||||
* @param mv MethodVisitor
|
||||
*/
|
||||
void applyReturn(ExtendedClassWriter<?> cw, MethodVisitor mv);
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
import com.bergerkiller.mountiplex.reflection.util.ExtendedClassWriter;
|
||||
import com.bergerkiller.mountiplex.reflection.util.FastConstructor;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* Because we shade in the Adventure library at a path different than Paper, we cannot
|
||||
* make use of Paper's own Audience implementation. This class generates an adapter
|
||||
* class that calls into Paper's Audience methods from (remapped) our own.<br>
|
||||
* <br>
|
||||
* To avoid making this a nightmare to maintain, it generates most of the adapter code.
|
||||
*/
|
||||
public class PaperAudienceAdapterFactoryOld {
|
||||
private final FastConstructor<Audience> audienceAdapterCtor = new FastConstructor<>();
|
||||
|
||||
public PaperAudienceAdapterFactoryOld() throws Throwable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* <li>net.kyori.adventure.key.Key</li>
|
||||
* <li>net.kyori.adventure.text.ComponentLike</li> Don't implement, use default implementation
|
||||
* <li>net.kyori.adventure.text.Component</li> Implement, with GSON String as intermediate
|
||||
* <li>net.kyori.adventure.audience.MessageType</li> Implement, just CHAT or SYSTEM
|
||||
* <li>net.kyori.adventure.identity.Identified</li> Don't implement, use default implementation
|
||||
* <li>net.kyori.adventure.identity.Identity</li> Implement, just has UUID field
|
||||
* <li>net.kyori.adventure.chat.ChatType.Bound</li> Implement, and ChatType too
|
||||
* <li>net.kyori.adventure.chat.SignedMessage</li> Implement, has simple types (+Component)
|
||||
* <li>net.kyori.adventure.chat.SignedMessage.Signature</li> Implement, is just byte[]
|
||||
* <li>net.kyori.adventure.title.Title</li> Implement, has Times (Duration) and some components
|
||||
* <li>net.kyori.adventure.title.TitlePart</li> Implements, it's like an enum
|
||||
*/
|
||||
|
||||
private static Class<? extends Audience> createAudienceAdapterClass(Class<?> paperAudienceType) {
|
||||
ExtendedClassWriter<? extends Audience> cw = ExtendedClassWriter.builder(Audience.class)
|
||||
.setFlags(ClassWriter.COMPUTE_MAXS)
|
||||
.setAccess(ACC_FINAL)
|
||||
.setExactName("com.bergerkiller.bukkit.common.cloud.audiences.PaperAudienceAdapterFactoryOld$AudienceAdapter")
|
||||
.build();
|
||||
|
||||
FieldVisitor fieldVisitor;
|
||||
MethodVisitor methodVisitor;
|
||||
|
||||
// Add field storing the Paper audience implementation type
|
||||
{
|
||||
fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, "aud",
|
||||
MPLType.getDescriptor(paperAudienceType), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Generate a constructor that assigns this Paper audience field
|
||||
{
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC, "<init>", "(" + MPLType.getDescriptor(paperAudienceType) + ")V", null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 1);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), "aud", MPLType.getDescriptor(paperAudienceType));
|
||||
methodVisitor.visitInsn(RETURN);
|
||||
methodVisitor.visitMaxs(2, 2);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Go by all methods that exist in the Audience class, and implement them by calling
|
||||
// the same method on the 'aud' field. If the method is not available, and the method
|
||||
// is abstract (no default implementation), implements it to throw an UnsupportedOperationException
|
||||
|
||||
|
||||
|
||||
{
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC, "doThing", "()V", null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitLdcInsn("Not Supported");
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V", false);
|
||||
methodVisitor.visitInsn(ATHROW);
|
||||
methodVisitor.visitMaxs(3, 1);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
//return cw.toByteArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type Adapter. These implementations exist:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.key.Key</li>
|
||||
* <li>net.kyori.adventure.text.ComponentLike</li>
|
||||
* <li>net.kyori.adventure.text.Component</li>
|
||||
* <li>net.kyori.adventure.audience.MessageType</li>
|
||||
* <li>net.kyori.adventure.identity.Identified</li>
|
||||
* <li>net.kyori.adventure.identity.Identity</li>
|
||||
* <li>net.kyori.adventure.chat.ChatType.Bound</li>
|
||||
* <li>net.kyori.adventure.chat.SignedMessage</li>
|
||||
* <li>net.kyori.adventure.chat.SignedMessage.Signature</li>
|
||||
* <li>net.kyori.adventure.title.Title</li>
|
||||
* <li>net.kyori.adventure.title.TitlePart</li>
|
||||
* </ul>
|
||||
*
|
||||
* These are not implemented and these functionalities will not work as a result:
|
||||
* <ul>
|
||||
* <li>net.kyori.adventure.bossbar.BossBar</li>
|
||||
* <li>net.kyori.adventure.sound.Sound</li>
|
||||
* <li>net.kyori.adventure.sound.SoundStop</li>
|
||||
* <li>net.kyori.adventure.sound.Sound.Emitter</li>
|
||||
* <li>net.kyori.adventure.inventory.Book.Builder</li>
|
||||
* <li>net.kyori.adventure.inventory.Book</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackInfoLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequestLike</li>
|
||||
* <li>net.kyori.adventure.resource.ResourcePackRequest</li>
|
||||
* <li>net.kyori.adventure.dialog.DialogLike</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <A> Type we know
|
||||
* @param <B> Unknown type
|
||||
*/
|
||||
public interface TypeAdapter<A, B> {
|
||||
/** Adapts the type we know into the unknown type */
|
||||
B adapt(A value);
|
||||
/** Restores the unknown type back into a type we know (reverse) */
|
||||
A restore(B value);
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package com.bergerkiller.bukkit.common.cloud.audiences;
|
||||
|
||||
import com.bergerkiller.mountiplex.reflection.util.ExtendedClassWriter;
|
||||
import com.bergerkiller.mountiplex.reflection.util.FastConstructor;
|
||||
import com.bergerkiller.mountiplex.reflection.util.UniqueHash;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* Generates implementation types for net.kyori.adventure.chat.SignedMessage.
|
||||
*/
|
||||
final class SignedMessageFactoryImpl<T> implements PaperAdventureAdapter.SignedMessageFactory<T> {
|
||||
private static final UniqueHash generatedClassCtr = new UniqueHash();
|
||||
private final FastConstructor<T> ctor;
|
||||
|
||||
public SignedMessageFactoryImpl(Class<?> signatureClass) {
|
||||
this.ctor = new FastConstructor<>(generateConstructor(signatureClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T create(
|
||||
final java.time.Instant timestamp,
|
||||
final long salt,
|
||||
final String message,
|
||||
final Object /* net.kyori.adventure.chat.SignedMessage$Signature */ signature,
|
||||
final Object /* net.kyori.adventure.text.Component */ unsignedContent,
|
||||
final Object /* net.kyori.adventure.identity.Identity */ identity
|
||||
) {
|
||||
return ctor.newInstanceVA(timestamp, salt, message, signature, unsignedContent, identity);
|
||||
}
|
||||
|
||||
private static <T> Constructor<? extends T> generateConstructor(Class<?> signatureClass) {
|
||||
ExtendedClassWriter<? extends T> cw = ExtendedClassWriter.builder(signatureClass)
|
||||
.setFlags(ClassWriter.COMPUTE_MAXS)
|
||||
.setAccess(ACC_FINAL)
|
||||
.setExactName(SignedMessageFactoryImpl.class.getName() + "$SignedMessageImpl" + generatedClassCtr.nextHex())
|
||||
.build();
|
||||
|
||||
MethodVisitor methodVisitor;
|
||||
|
||||
// We need these types
|
||||
Class<?> signedMessageSignatureType = findAdventureType(signatureClass, "chat.SignedMessage$Signature");
|
||||
Class<?> componentType = findAdventureType(signatureClass, "text.Component");
|
||||
Class<?> identityType = findAdventureType(signatureClass, "identity.Identity");
|
||||
|
||||
// Declare all fields in our type that will also be set as constructor parameters
|
||||
List<FieldInfo> fields = Arrays.asList(
|
||||
new FieldInfo("timestamp", "timestamp", java.time.Instant.class),
|
||||
new FieldInfo("salt", "salt", long.class),
|
||||
new FieldInfo("message", "message", String.class),
|
||||
new FieldInfo("signature", "signature", signedMessageSignatureType),
|
||||
new FieldInfo("unsignedContent", "unsignedContent", componentType),
|
||||
new FieldInfo("identity", "identity", identityType)
|
||||
);
|
||||
|
||||
// Add fields as private final fields
|
||||
for (FieldInfo field : fields) {
|
||||
FieldVisitor fieldVisitor = cw.visitField(ACC_PRIVATE | ACC_FINAL, field.name,
|
||||
MPLType.getDescriptor(field.type), null, null);
|
||||
fieldVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Generate a constructor that assigns all these fields
|
||||
{
|
||||
String ctorDesc = "(" + fields.stream().map(f -> MPLType.getDescriptor(f.type)).collect(Collectors.joining()) + ")V";
|
||||
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC, "<init>", ctorDesc, null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
int register = 1;
|
||||
for (FieldInfo field : fields) {
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
register = MPLType.visitVarILoad(methodVisitor, register, field.type);
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, cw.getInternalName(), field.name, MPLType.getDescriptor(field.type));
|
||||
}
|
||||
|
||||
methodVisitor.visitInsn(RETURN);
|
||||
methodVisitor.visitMaxs(2, 2);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Implement all the getter methods that return our fields
|
||||
for (FieldInfo field : fields) {
|
||||
methodVisitor = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, field.getterName,
|
||||
"()" + MPLType.getDescriptor(field.type), null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(GETFIELD, cw.getInternalName(), field.name, MPLType.getDescriptor(field.type));
|
||||
methodVisitor.visitInsn(MPLType.getOpcode(field.type, IRETURN));
|
||||
methodVisitor.visitMaxs(1, 1);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
// Generate the class and retrieve its constructor
|
||||
return cw.generateConstructor(fields.stream().map(f -> f.type).toArray(Class<?>[]::new));
|
||||
}
|
||||
|
||||
private static Class<?> findAdventureType(Class<?> signedMessageType, String adventureTypeName) {
|
||||
// Extract package from signedMessageType (net.kyori.adventure.chat.SignedMessage -> net.kyori.adventure)
|
||||
String prefix = signedMessageType.getName().substring(0, signedMessageType.getName().length() - 18);
|
||||
String fullTypeName = prefix + adventureTypeName;
|
||||
try {
|
||||
return Class.forName(fullTypeName, false, signedMessageType.getClassLoader());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UnsupportedOperationException("Adventure library type not found: " + fullTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
private static class FieldInfo {
|
||||
public final String name;
|
||||
public final Class<?> type;
|
||||
public final String getterName;
|
||||
|
||||
public FieldInfo(String name, String getterName, Class<?> type) {
|
||||
this.name = name;
|
||||
this.getterName = getterName;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,8 @@ import com.bergerkiller.mountiplex.MountiplexUtil;
|
||||
import com.bergerkiller.mountiplex.reflection.SafeField;
|
||||
import com.bergerkiller.mountiplex.reflection.util.asm.ASMUtil;
|
||||
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Chunk;
|
||||
@@ -74,6 +76,7 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.cloud.minecraft.extras.AudienceProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.SoftReference;
|
||||
@@ -676,6 +679,18 @@ public class CommonPlugin extends PluginBase {
|
||||
return;
|
||||
}
|
||||
|
||||
new Task(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
try (BukkitAudiences aud = BukkitAudiences.create(this.getPlugin())) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
player.sendMessage("OLD STYLE HELLO");
|
||||
aud.player(player).sendMessage(Component.text("Hello!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start(20, 20);
|
||||
|
||||
// Welcome message
|
||||
final List<String> welcomeMessages = Arrays.asList(
|
||||
"This library is written with stability in mind.",
|
||||
|
||||
Reference in new issue
Block a user