add WrappedComponentStyle

This commit is contained in:
vytskalt 2024-03-02 16:26:59 +02:00
parent 0cd4de972c
commit 7aa5f3b47f
4 changed files with 156 additions and 4 deletions

View File

@ -668,6 +668,16 @@ public final class MinecraftReflection {
return getMinecraftClass("network.chat.IChatBaseComponent$ChatSerializer", "network.chat.Component$Serializer", "IChatBaseComponent$ChatSerializer");
}
/**
* Retrieve the component style serializer class.
*
* @return The serializer class.
*/
public static Class<?> getStyleSerializerClass() {
return getMinecraftClass("network.chat.ChatModifier$ChatModifierSerializer", "ChatModifier$ChatModifierSerializer");
}
/**
* Retrieve the ServerPing class.
*
@ -1018,6 +1028,15 @@ public final class MinecraftReflection {
return getOptionalNMS("network.protocol.game.PacketPlayOutScoreboardTeam$b");
}
/**
* Retrieve the NMS component style class.
*
* @return The component style class.
*/
public static Class<?> getComponentStyleClass() {
return getMinecraftClass("network.chat.ChatModifier", "ChatModifier");
}
/**
* Retrieve the Gson class used by Minecraft.
*

View File

@ -16,7 +16,10 @@
*/
package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.gson.JsonObject;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
/**
@ -25,7 +28,16 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
* Note: The Adventure API Component is not included in CraftBukkit, Bukkit or Spigot and but is present in PaperMC.
*/
public class AdventureComponentConverter {
private static final GsonComponentSerializer SERIALIZER;
static {
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
SERIALIZER = GsonComponentSerializer.gson();
} else {
SERIALIZER = GsonComponentSerializer.colorDownsamplingGson();
}
}
private AdventureComponentConverter() {
}
@ -35,7 +47,7 @@ public class AdventureComponentConverter {
* @return Component
*/
public static Component fromWrapper(WrappedChatComponent wrapper) {
return GsonComponentSerializer.gson().deserialize(wrapper.getJson());
return SERIALIZER.deserialize(wrapper.getJson());
}
/**
@ -44,11 +56,29 @@ public class AdventureComponentConverter {
* @return ProtocolLib wrapper
*/
public static WrappedChatComponent fromComponent(Component component) {
return WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component));
return WrappedChatComponent.fromJson(SERIALIZER.serialize(component));
}
/**
* Converts a {@link WrappedComponentStyle} into a {@link Style}
* @param wrapper ProtocolLib wrapper
* @return Style
*/
public static Style fromWrapper(WrappedComponentStyle wrapper) {
return SERIALIZER.serializer().fromJson(wrapper.getJson(), Style.class);
}
/**
* Converts a {@link Style} into a ProtocolLib wrapper
* @param style Style
* @return ProtocolLib wrapper
*/
public static WrappedComponentStyle fromStyle(Style style) {
return WrappedComponentStyle.fromJson((JsonObject) SERIALIZER.serializer().toJsonTree(style));
}
public static Class<?> getComponentClass() {
return Component.class;
return Component.class;
}
public static Component clone(Object component) {

View File

@ -0,0 +1,63 @@
package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.codecs.WrappedCodec;
import com.comphenix.protocol.wrappers.codecs.WrappedDynamicOps;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/**
* A wrapper around the component style NMS class.
*
* @author vytskalt
*/
public class WrappedComponentStyle extends AbstractWrapper {
private static final WrappedCodec CODEC; // 1.20.4+
private static final Gson GSON; // Below 1.20.4
static {
if (MinecraftVersion.v1_20_4.atOrAbove()) {
FuzzyReflection fuzzySerializer = FuzzyReflection.fromClass(MinecraftReflection.getStyleSerializerClass(), true);
Object codec = Accessors.getFieldAccessor(fuzzySerializer.getFieldByType("CODEC", MinecraftReflection.getCodecClass())).get(null);
CODEC = WrappedCodec.fromHandle(codec);
GSON = null;
} else {
FuzzyReflection fuzzySerializer = FuzzyReflection.fromClass(MinecraftReflection.getChatSerializerClass(), true);
CODEC = null;
GSON = (Gson) Accessors.getFieldAccessor(fuzzySerializer.getFieldByType("gson", Gson.class)).get(null);
}
}
public WrappedComponentStyle(Object handle) {
super(MinecraftReflection.getComponentStyleClass());
setHandle(handle);
}
public JsonObject getJson() {
if (CODEC != null) {
return (JsonObject) CODEC.encode(handle, WrappedDynamicOps.json(false))
.getOrThrow(JsonParseException::new);
} else {
return (JsonObject) GSON.toJsonTree(handle);
}
}
public static WrappedComponentStyle fromHandle(Object handle) {
return new WrappedComponentStyle(handle);
}
public static WrappedComponentStyle fromJson(JsonObject json) {
Object handle;
if (CODEC != null) {
handle = CODEC.parse(json, WrappedDynamicOps.json(false))
.getOrThrow(JsonParseException::new);
} else {
handle = GSON.fromJson(json, MinecraftReflection.getComponentStyleClass());
}
return new WrappedComponentStyle(handle);
}
}

View File

@ -0,0 +1,40 @@
package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.BukkitInitialization;
import com.google.gson.JsonObject;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import net.minecraft.EnumChatFormat;
import net.minecraft.network.chat.ChatModifier;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class WrappedComponentStyleTest {
@BeforeAll
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
}
@Test
public void testComponentStyle() {
ChatModifier style = ChatModifier.a.b(EnumChatFormat.m).a(true);
WrappedComponentStyle wrapped = new WrappedComponentStyle(style);
JsonObject json = wrapped.getJson();
assertEquals("{\"color\":\"red\",\"bold\":true}", json.toString());
assertEquals(style, WrappedComponentStyle.fromJson(json).getHandle());
}
@Test
public void testStyleAdventureConversion() {
Style adventureStyle = Style.style(NamedTextColor.GREEN, TextDecoration.BOLD)
.clickEvent(ClickEvent.changePage(10));
WrappedComponentStyle wrapped = AdventureComponentConverter.fromStyle(adventureStyle);
assertEquals(adventureStyle, AdventureComponentConverter.fromWrapper(wrapped));
}
}