mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-23 11:05:46 +01:00
Add several scoreboard type wrappers (#2819)
This commit is contained in:
parent
77ada09c11
commit
616431cc33
@ -870,6 +870,55 @@ public abstract class AbstractStructure {
|
||||
EnumWrappers.getChatTypeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the DisplaySlot enum in 1.20.2.
|
||||
* @return A modifier for DisplaySlot enum fields.
|
||||
*/
|
||||
public StructureModifier<EnumWrappers.DisplaySlot> getDisplaySlots() {
|
||||
return structureModifier.withType(
|
||||
EnumWrappers.getDisplaySlotClass(),
|
||||
EnumWrappers.getDisplaySlotConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the RenderType enum.
|
||||
* @return A modifier for RenderType enum fields.
|
||||
*/
|
||||
public StructureModifier<EnumWrappers.RenderType> getRenderTypes() {
|
||||
return structureModifier.withType(
|
||||
EnumWrappers.getRenderTypeClass(),
|
||||
EnumWrappers.getRenderTypeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the ChatFormatting enum.
|
||||
* @return A modifier for ChatFormatting enum fields.
|
||||
*/
|
||||
public StructureModifier<EnumWrappers.ChatFormatting> getChatFormattings() {
|
||||
return structureModifier.withType(
|
||||
EnumWrappers.getChatFormattingClass(),
|
||||
EnumWrappers.getChatFormattingConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for optional team parameters in 1.17+.
|
||||
* @return A modifier for optional team parameters fields.
|
||||
*/
|
||||
public StructureModifier<Optional<WrappedTeamParameters>> getOptionalTeamParameters() {
|
||||
return getOptionals(BukkitConverters.getWrappedTeamParametersConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the NumberFormat class in 1.20.4+.
|
||||
* @return A modifier for NumberFormat fields.
|
||||
*/
|
||||
public StructureModifier<WrappedNumberFormat> getNumberFormats() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getNumberFormatClass().orElse(null),
|
||||
BukkitConverters.getWrappedNumberFormatConverter());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the MinecraftKey class.
|
||||
* @return A modifier for MinecraftKey fields.
|
||||
|
@ -17,10 +17,25 @@
|
||||
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
|
||||
import net.bytebuddy.description.ByteCodeElement;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
@ -35,27 +50,19 @@ import net.bytebuddy.implementation.bind.annotation.Origin;
|
||||
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Represents a player object that can be serialized by Java.
|
||||
*
|
||||
|
@ -69,9 +69,12 @@ public class StructureCache {
|
||||
|
||||
public static Object newPacket(Class<?> packetClass) {
|
||||
Supplier<Object> packetConstructor = PACKET_INSTANCE_CREATORS.computeIfAbsent(packetClass, packetClassKey -> {
|
||||
PacketCreator creator = PacketCreator.forPacket(packetClassKey);
|
||||
if (creator.get() != null) {
|
||||
return creator;
|
||||
try {
|
||||
PacketCreator creator = PacketCreator.forPacket(packetClassKey);
|
||||
if (creator.get() != null) {
|
||||
return creator;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
WrappedStreamCodec streamCodec = PacketRegistry.getStreamCodec(packetClassKey);
|
||||
|
@ -679,6 +679,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.
|
||||
*
|
||||
@ -1020,6 +1030,60 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("world.level.block.entity.TileEntity", "world.level.block.entity.BlockEntity", "TileEntity");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NMS team parameters class.
|
||||
*
|
||||
* @return The team parameters class.
|
||||
*/
|
||||
public static Optional<Class<?>> getTeamParametersClass() {
|
||||
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 NMS NumberFormat class.
|
||||
*
|
||||
* @return The NumberFormat class.
|
||||
*/
|
||||
public static Optional<Class<?>> getNumberFormatClass() {
|
||||
return getOptionalNMS("network.chat.numbers.NumberFormat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NMS BlankFormat class.
|
||||
*
|
||||
* @return The FixedFormat class.
|
||||
*/
|
||||
public static Optional<Class<?>> getBlankFormatClass() {
|
||||
return getOptionalNMS("network.chat.numbers.BlankFormat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NMS FixedFormat class.
|
||||
*
|
||||
* @return The FixedFormat class.
|
||||
*/
|
||||
public static Optional<Class<?>> getFixedFormatClass() {
|
||||
return getOptionalNMS("network.chat.numbers.FixedFormat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NMS StyledFormat class.
|
||||
*
|
||||
* @return The StyledFormat class.
|
||||
*/
|
||||
public static Optional<Class<?>> getStyledFormatClass() {
|
||||
return getOptionalNMS("network.chat.numbers.StyledFormat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Gson class used by Minecraft.
|
||||
*
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,11 +83,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) {
|
||||
|
@ -640,6 +640,14 @@ public class BukkitConverters {
|
||||
return ignoreNull(handle(WrappedLevelChunkData.LightData::getHandle, WrappedLevelChunkData.LightData::new, WrappedLevelChunkData.LightData.class));
|
||||
}
|
||||
|
||||
public static EquivalentConverter<WrappedTeamParameters> getWrappedTeamParametersConverter() {
|
||||
return ignoreNull(handle(WrappedTeamParameters::getHandle, WrappedTeamParameters::new, WrappedTeamParameters.class));
|
||||
}
|
||||
|
||||
public static EquivalentConverter<WrappedNumberFormat> getWrappedNumberFormatConverter() {
|
||||
return ignoreNull(handle(WrappedNumberFormat::getHandle, WrappedNumberFormat::fromHandle, WrappedNumberFormat.class));
|
||||
}
|
||||
|
||||
public static EquivalentConverter<PacketContainer> getPacketContainerConverter() {
|
||||
return ignoreNull(handle(PacketContainer::getHandle, PacketContainer::fromPacket, PacketContainer.class));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -464,6 +465,163 @@ public abstract class EnumWrappers {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.20.2
|
||||
*/
|
||||
public enum DisplaySlot {
|
||||
LIST,
|
||||
SIDEBAR,
|
||||
BELOW_NAME,
|
||||
TEAM_BLACK,
|
||||
TEAM_DARK_BLUE,
|
||||
TEAM_DARK_GREEN,
|
||||
TEAM_DARK_AQUA,
|
||||
TEAM_DARK_RED,
|
||||
TEAM_DARK_PURPLE,
|
||||
TEAM_GOLD,
|
||||
TEAM_GRAY,
|
||||
TEAM_DARK_GRAY,
|
||||
TEAM_BLUE,
|
||||
TEAM_GREEN,
|
||||
TEAM_AQUA,
|
||||
TEAM_RED,
|
||||
TEAM_LIGHT_PURPLE,
|
||||
TEAM_YELLOW,
|
||||
TEAM_WHITE;
|
||||
}
|
||||
|
||||
public enum RenderType {
|
||||
INTEGER,
|
||||
HEARTS
|
||||
}
|
||||
|
||||
public enum ChatFormatting {
|
||||
BLACK,
|
||||
DARK_BLUE,
|
||||
DARK_GREEN,
|
||||
DARK_AQUA,
|
||||
DARK_RED,
|
||||
DARK_PURPLE,
|
||||
GOLD,
|
||||
GRAY,
|
||||
DARK_GRAY,
|
||||
BLUE,
|
||||
GREEN,
|
||||
AQUA,
|
||||
RED,
|
||||
LIGHT_PURPLE,
|
||||
YELLOW,
|
||||
WHITE,
|
||||
OBFUSCATED,
|
||||
BOLD,
|
||||
STRIKETHROUGH,
|
||||
UNDERLINE,
|
||||
ITALIC,
|
||||
RESET;
|
||||
|
||||
public ChatColor toBukkit() {
|
||||
switch (this){
|
||||
case BLACK:
|
||||
return ChatColor.BLACK;
|
||||
case DARK_BLUE:
|
||||
return ChatColor.DARK_BLUE;
|
||||
case DARK_GREEN:
|
||||
return ChatColor.DARK_GREEN;
|
||||
case DARK_AQUA:
|
||||
return ChatColor.DARK_AQUA;
|
||||
case DARK_RED:
|
||||
return ChatColor.DARK_RED;
|
||||
case DARK_PURPLE:
|
||||
return ChatColor.DARK_PURPLE;
|
||||
case GOLD:
|
||||
return ChatColor.GOLD;
|
||||
case GRAY:
|
||||
return ChatColor.GRAY;
|
||||
case DARK_GRAY:
|
||||
return ChatColor.DARK_GRAY;
|
||||
case BLUE:
|
||||
return ChatColor.BLUE;
|
||||
case GREEN:
|
||||
return ChatColor.GREEN;
|
||||
case AQUA:
|
||||
return ChatColor.AQUA;
|
||||
case RED:
|
||||
return ChatColor.RED;
|
||||
case LIGHT_PURPLE:
|
||||
return ChatColor.LIGHT_PURPLE;
|
||||
case YELLOW:
|
||||
return ChatColor.YELLOW;
|
||||
case WHITE:
|
||||
return ChatColor.WHITE;
|
||||
case OBFUSCATED:
|
||||
return ChatColor.MAGIC;
|
||||
case BOLD:
|
||||
return ChatColor.BOLD;
|
||||
case STRIKETHROUGH:
|
||||
return ChatColor.STRIKETHROUGH;
|
||||
case UNDERLINE:
|
||||
return ChatColor.UNDERLINE;
|
||||
case ITALIC:
|
||||
return ChatColor.ITALIC;
|
||||
case RESET:
|
||||
return ChatColor.RESET;
|
||||
default:
|
||||
throw new IllegalStateException("Unimplemented Bukkit equivalent for " + name());
|
||||
}
|
||||
}
|
||||
|
||||
public static ChatFormatting fromBukkit(ChatColor color) {
|
||||
switch (color){
|
||||
case BLACK:
|
||||
return ChatFormatting.BLACK;
|
||||
case DARK_BLUE:
|
||||
return ChatFormatting.DARK_BLUE;
|
||||
case DARK_GREEN:
|
||||
return ChatFormatting.DARK_GREEN;
|
||||
case DARK_AQUA:
|
||||
return ChatFormatting.DARK_AQUA;
|
||||
case DARK_RED:
|
||||
return ChatFormatting.DARK_RED;
|
||||
case DARK_PURPLE:
|
||||
return ChatFormatting.DARK_PURPLE;
|
||||
case GOLD:
|
||||
return ChatFormatting.GOLD;
|
||||
case GRAY:
|
||||
return ChatFormatting.GRAY;
|
||||
case DARK_GRAY:
|
||||
return ChatFormatting.DARK_GRAY;
|
||||
case BLUE:
|
||||
return ChatFormatting.BLUE;
|
||||
case GREEN:
|
||||
return ChatFormatting.GREEN;
|
||||
case AQUA:
|
||||
return ChatFormatting.AQUA;
|
||||
case RED:
|
||||
return ChatFormatting.RED;
|
||||
case LIGHT_PURPLE:
|
||||
return ChatFormatting.LIGHT_PURPLE;
|
||||
case YELLOW:
|
||||
return ChatFormatting.YELLOW;
|
||||
case WHITE:
|
||||
return ChatFormatting.WHITE;
|
||||
case MAGIC:
|
||||
return ChatFormatting.OBFUSCATED;
|
||||
case BOLD:
|
||||
return ChatFormatting.BOLD;
|
||||
case STRIKETHROUGH:
|
||||
return ChatFormatting.STRIKETHROUGH;
|
||||
case UNDERLINE:
|
||||
return ChatFormatting.UNDERLINE;
|
||||
case ITALIC:
|
||||
return ChatFormatting.ITALIC;
|
||||
case RESET:
|
||||
return ChatFormatting.RESET;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown ChatColor " + color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> PROTOCOL_CLASS = null;
|
||||
private static Class<?> CLIENT_COMMAND_CLASS = null;
|
||||
private static Class<?> CHAT_VISIBILITY_CLASS = null;
|
||||
@ -485,6 +643,9 @@ public abstract class EnumWrappers {
|
||||
private static Class<?> DIRECTION_CLASS = null;
|
||||
private static Class<?> CHAT_TYPE_CLASS = null;
|
||||
private static Class<?> ENTITY_POSE_CLASS = null;
|
||||
private static Class<?> DISPLAY_SLOT_CLASS = null;
|
||||
private static Class<?> RENDER_TYPE_CLASS = null;
|
||||
private static Class<?> CHAT_FORMATTING_CLASS = null;
|
||||
|
||||
private static boolean INITIALIZED = false;
|
||||
private static Map<Class<?>, EquivalentConverter<?>> FROM_NATIVE = new HashMap<>();
|
||||
@ -574,6 +735,9 @@ public abstract class EnumWrappers {
|
||||
|
||||
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
|
||||
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("world.entity.EntityPose", "world.entity.Pose", "EntityPose");
|
||||
DISPLAY_SLOT_CLASS = MinecraftReflection.getNullableNMS("world.scores.DisplaySlot");
|
||||
RENDER_TYPE_CLASS = MinecraftReflection.getNullableNMS("world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay", "IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
CHAT_FORMATTING_CLASS = MinecraftReflection.getNullableNMS("EnumChatFormat");
|
||||
|
||||
associate(PROTOCOL_CLASS, Protocol.class, getProtocolConverter());
|
||||
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
|
||||
@ -595,6 +759,9 @@ public abstract class EnumWrappers {
|
||||
associate(CHAT_TYPE_CLASS, ChatType.class, getChatTypeConverter());
|
||||
associate(HAND_CLASS, Hand.class, getHandConverter());
|
||||
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
|
||||
associate(DISPLAY_SLOT_CLASS, DisplaySlot.class, getDisplaySlotConverter());
|
||||
associate(RENDER_TYPE_CLASS, RenderType.class, getRenderTypeConverter());
|
||||
associate(CHAT_FORMATTING_CLASS, ChatFormatting.class, getChatFormattingConverter());
|
||||
|
||||
if (ENTITY_POSE_CLASS != null) {
|
||||
associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter());
|
||||
@ -746,6 +913,21 @@ public abstract class EnumWrappers {
|
||||
return ENTITY_POSE_CLASS;
|
||||
}
|
||||
|
||||
public static Class<?> getDisplaySlotClass() {
|
||||
initialize();
|
||||
return DISPLAY_SLOT_CLASS;
|
||||
}
|
||||
|
||||
public static Class<?> getRenderTypeClass() {
|
||||
initialize();
|
||||
return RENDER_TYPE_CLASS;
|
||||
}
|
||||
|
||||
public static Class<?> getChatFormattingClass() {
|
||||
initialize();
|
||||
return CHAT_FORMATTING_CLASS;
|
||||
}
|
||||
|
||||
// Get the converters
|
||||
public static EquivalentConverter<Protocol> getProtocolConverter() {
|
||||
return new EnumConverter<>(getProtocolClass(), Protocol.class);
|
||||
@ -826,7 +1008,19 @@ public abstract class EnumWrappers {
|
||||
public static EquivalentConverter<ChatType> getChatTypeConverter() {
|
||||
return new EnumConverter<>(getChatTypeClass(), ChatType.class);
|
||||
}
|
||||
|
||||
|
||||
public static EquivalentConverter<DisplaySlot> getDisplaySlotConverter() {
|
||||
return new EnumConverter<>(getDisplaySlotClass(), DisplaySlot.class);
|
||||
}
|
||||
|
||||
public static EquivalentConverter<RenderType> getRenderTypeConverter() {
|
||||
return new EnumConverter<>(getRenderTypeClass(), RenderType.class);
|
||||
}
|
||||
|
||||
public static EquivalentConverter<ChatFormatting> getChatFormattingConverter() {
|
||||
return new EnumConverter<>(getChatFormattingClass(), ChatFormatting.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.13+
|
||||
* @return {@link EnumConverter} or null (if bellow 1.13 / nms EnumPose class cannot be found)
|
||||
|
@ -0,0 +1,59 @@
|
||||
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.JsonElement;
|
||||
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 JsonElement getJson() {
|
||||
if (CODEC != null) {
|
||||
return (JsonElement) CODEC.encode(handle, WrappedDynamicOps.json(false))
|
||||
.getOrThrow(JsonParseException::new);
|
||||
} else {
|
||||
return GSON.toJsonTree(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static WrappedComponentStyle fromJson(JsonElement 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);
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A wrapper around the NumberFormat NMS classes.
|
||||
*
|
||||
* @author vytskalt
|
||||
* @since 1.20.4
|
||||
*/
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
public class WrappedNumberFormat extends AbstractWrapper {
|
||||
private static final Object BLANK;
|
||||
private static final ConstructorAccessor FIXED_CONSTRUCTOR, STYLED_CONSTRUCTOR;
|
||||
|
||||
static {
|
||||
if (!isSupported()) {
|
||||
BLANK = null;
|
||||
FIXED_CONSTRUCTOR = null;
|
||||
STYLED_CONSTRUCTOR = null;
|
||||
} else {
|
||||
Class<?> blankClass = MinecraftReflection.getBlankFormatClass().get();
|
||||
FuzzyReflection fuzzyBlank = FuzzyReflection.fromClass(blankClass, true);
|
||||
BLANK = Accessors.getFieldAccessor(fuzzyBlank.getFieldByType("INSTANCE", blankClass)).get(null);
|
||||
|
||||
FIXED_CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
MinecraftReflection.getFixedFormatClass().get(),
|
||||
MinecraftReflection.getIChatBaseComponentClass()
|
||||
);
|
||||
|
||||
STYLED_CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
MinecraftReflection.getStyledFormatClass().get(),
|
||||
MinecraftReflection.getComponentStyleClass()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the NumberFormat classes exist on the current server version
|
||||
*/
|
||||
public static boolean isSupported() {
|
||||
return MinecraftReflection.getNumberFormatClass().isPresent();
|
||||
}
|
||||
|
||||
public static WrappedNumberFormat fromHandle(Object handle) {
|
||||
throwIfUnsupported();
|
||||
if (MinecraftReflection.getBlankFormatClass().get().isInstance(handle)) {
|
||||
return new Blank(handle);
|
||||
} else if (MinecraftReflection.getFixedFormatClass().get().isInstance(handle)) {
|
||||
return new Fixed(handle);
|
||||
} else if (MinecraftReflection.getStyledFormatClass().get().isInstance(handle)) {
|
||||
return new Styled(handle);
|
||||
} else {
|
||||
throw new IllegalArgumentException("handle is not a NumberFormat instance, but " + handle.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public static Blank blank() {
|
||||
throwIfUnsupported();
|
||||
return new Blank(WrappedNumberFormat.BLANK);
|
||||
}
|
||||
|
||||
public static Fixed fixed(@NotNull WrappedChatComponent content) {
|
||||
throwIfUnsupported();
|
||||
Object handle = FIXED_CONSTRUCTOR.invoke(content.getHandle());
|
||||
return new Fixed(handle);
|
||||
}
|
||||
|
||||
public static Styled styled(@NotNull WrappedComponentStyle style) {
|
||||
throwIfUnsupported();
|
||||
Object handle = STYLED_CONSTRUCTOR.invoke(style.getHandle());
|
||||
return new Styled(handle);
|
||||
}
|
||||
|
||||
private static void throwIfUnsupported() {
|
||||
if (!isSupported()) {
|
||||
throw new IllegalStateException("NumberFormat classes don't exist on this server version");
|
||||
}
|
||||
}
|
||||
|
||||
private WrappedNumberFormat(Class<?> handleType) {
|
||||
super(handleType);
|
||||
}
|
||||
|
||||
public static class Blank extends WrappedNumberFormat {
|
||||
private Blank(Object handle) {
|
||||
super(MinecraftReflection.getBlankFormatClass().get());
|
||||
setHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Fixed extends WrappedNumberFormat {
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
private Fixed(Object handle) {
|
||||
super(MinecraftReflection.getFixedFormatClass().get());
|
||||
setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
}
|
||||
|
||||
public WrappedChatComponent getContent() {
|
||||
Object handle = modifier.withType(MinecraftReflection.getIChatBaseComponentClass()).read(0);
|
||||
return WrappedChatComponent.fromHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Styled extends WrappedNumberFormat {
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
private Styled(Object handle) {
|
||||
super(MinecraftReflection.getStyledFormatClass().get());
|
||||
setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
}
|
||||
|
||||
public WrappedComponentStyle getStyle() {
|
||||
Object handle = modifier.withType(MinecraftReflection.getComponentStyleClass()).read(0);
|
||||
return new WrappedComponentStyle(handle);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A wrapper around the team parameters NMS class.
|
||||
*
|
||||
* @author vytskalt
|
||||
* @since 1.17
|
||||
*/
|
||||
public class WrappedTeamParameters extends AbstractWrapper {
|
||||
public static Class<?> getNmsClassOrThrow() {
|
||||
return MinecraftReflection.getTeamParametersClass()
|
||||
.orElseThrow(() -> new IllegalStateException("Team parameters class doesn't exist on this server version"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the team parameters class exists on the current server version
|
||||
*/
|
||||
public static boolean isSupported() {
|
||||
return MinecraftReflection.getTeamParametersClass().isPresent();
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return newBuilder(null);
|
||||
}
|
||||
|
||||
public static Builder newBuilder(@Nullable WrappedTeamParameters template) {
|
||||
return new Builder(template);
|
||||
}
|
||||
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
public WrappedTeamParameters(Object handle) {
|
||||
super(getNmsClassOrThrow());
|
||||
setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(getNmsClassOrThrow()).withTarget(handle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WrappedChatComponent getDisplayName() {
|
||||
return readComponent(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WrappedChatComponent getPrefix() {
|
||||
return readComponent(1);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WrappedChatComponent getSuffix() {
|
||||
return readComponent(2);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNametagVisibility() {
|
||||
return modifier.<String>withType(String.class).read(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getCollisionRule() {
|
||||
return modifier.<String>withType(String.class).read(1);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnumWrappers.ChatFormatting getColor() {
|
||||
Object handle = modifier.withType(EnumWrappers.getChatFormattingClass()).read(0);
|
||||
return EnumWrappers.getChatFormattingConverter().getSpecific(handle);
|
||||
}
|
||||
|
||||
public int getOptions() {
|
||||
return (int) modifier.withType(int.class).read(0);
|
||||
}
|
||||
|
||||
private WrappedChatComponent readComponent(int index) {
|
||||
Object handle = modifier.withType(MinecraftReflection.getIChatBaseComponentClass()).read(index);
|
||||
return WrappedChatComponent.fromHandle(handle);
|
||||
}
|
||||
|
||||
private void writeComponent(int index, WrappedChatComponent component) {
|
||||
modifier.withType(MinecraftReflection.getIChatBaseComponentClass()).write(index, component.getHandle());
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private WrappedChatComponent displayName, prefix, suffix;
|
||||
private String nametagVisibility, collisionRule;
|
||||
private EnumWrappers.ChatFormatting color;
|
||||
private int options;
|
||||
|
||||
private Builder(@Nullable WrappedTeamParameters template) {
|
||||
if (template != null) {
|
||||
this.displayName = template.getDisplayName();
|
||||
this.prefix = template.getDisplayName();
|
||||
this.suffix = template.getDisplayName();
|
||||
this.nametagVisibility = template.getNametagVisibility();
|
||||
this.collisionRule = template.getCollisionRule();
|
||||
this.color = template.getColor();
|
||||
this.options = template.getOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public Builder displayName(@NotNull WrappedChatComponent displayName) {
|
||||
Preconditions.checkNotNull(displayName);
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder prefix(@NotNull WrappedChatComponent prefix) {
|
||||
Preconditions.checkNotNull(prefix);
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder suffix(@NotNull WrappedChatComponent suffix) {
|
||||
Preconditions.checkNotNull(suffix);
|
||||
this.suffix = suffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nametagVisibility(@NotNull String nametagVisibility) {
|
||||
Preconditions.checkNotNull(nametagVisibility);
|
||||
this.nametagVisibility = nametagVisibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder collisionRule(@NotNull String collisionRule) {
|
||||
Preconditions.checkNotNull(collisionRule);
|
||||
this.collisionRule = collisionRule;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder color(@NotNull EnumWrappers.ChatFormatting color) {
|
||||
Preconditions.checkNotNull(color);
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder options(int options) {
|
||||
Preconditions.checkNotNull(collisionRule);
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WrappedTeamParameters build() {
|
||||
Preconditions.checkNotNull(displayName, "Display name not set");
|
||||
Preconditions.checkNotNull(prefix, "Prefix not set");
|
||||
Preconditions.checkNotNull(suffix, "Suffix not set");
|
||||
Preconditions.checkNotNull(nametagVisibility, "Nametag visibility not set");
|
||||
Preconditions.checkNotNull(collisionRule, "Collision rule not set");
|
||||
Preconditions.checkNotNull(color, "Color not set");
|
||||
|
||||
// Not technically a packet, but it has a PacketDataSerializer constructor, so it works fine
|
||||
Object handle = StructureCache.newPacket(getNmsClassOrThrow());
|
||||
|
||||
WrappedTeamParameters wrapped = new WrappedTeamParameters(handle);
|
||||
wrapped.writeComponent(0, displayName);
|
||||
wrapped.writeComponent(1, prefix);
|
||||
wrapped.writeComponent(2, suffix);
|
||||
wrapped.modifier.withType(String.class).write(0, nametagVisibility);
|
||||
wrapped.modifier.withType(String.class).write(1, collisionRule);
|
||||
wrapped.modifier.withType(EnumWrappers.getChatFormattingClass()).write(0, EnumWrappers.getChatFormattingConverter().getGeneric(color));
|
||||
wrapped.modifier.withType(int.class).write(0, options);
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.google.gson.JsonElement;
|
||||
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);
|
||||
JsonElement 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));
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.EnumChatFormat;
|
||||
import net.minecraft.network.chat.ChatModifier;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.chat.numbers.BlankFormat;
|
||||
import net.minecraft.network.chat.numbers.FixedFormat;
|
||||
import net.minecraft.network.chat.numbers.StyledFormat;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
|
||||
public class WrappedNumberFormatTest {
|
||||
|
||||
@BeforeAll
|
||||
static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBlankFormat() {
|
||||
assertInstanceOf(WrappedNumberFormat.Blank.class, WrappedNumberFormat.fromHandle(BlankFormat.a));
|
||||
assertEquals(BlankFormat.a, WrappedNumberFormat.blank().getHandle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFixedFormat() {
|
||||
IChatBaseComponent content = IChatBaseComponent.a("Fixed");
|
||||
WrappedNumberFormat wrappedHandle = WrappedNumberFormat.fromHandle(new FixedFormat(content));
|
||||
assertInstanceOf(WrappedNumberFormat.Fixed.class, wrappedHandle);
|
||||
assertEquals(content, ((WrappedNumberFormat.Fixed) wrappedHandle).getContent().getHandle());
|
||||
|
||||
WrappedNumberFormat.Fixed wrapped = WrappedNumberFormat.fixed(WrappedChatComponent.fromHandle(content));
|
||||
assertEquals(content, wrapped.getContent().getHandle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStyledFormat() {
|
||||
ChatModifier style = ChatModifier.a.b(EnumChatFormat.g);
|
||||
WrappedNumberFormat wrappedHandle = WrappedNumberFormat.fromHandle(new StyledFormat(style));
|
||||
assertInstanceOf(WrappedNumberFormat.Styled.class, wrappedHandle);
|
||||
assertEquals(style, ((WrappedNumberFormat.Styled) wrappedHandle).getStyle().getHandle());
|
||||
|
||||
WrappedNumberFormat.Styled newWrapper = WrappedNumberFormat.styled(new WrappedComponentStyle(style));
|
||||
assertEquals(style, newWrapper.getStyle().getHandle());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.EnumChatFormat;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class WrappedTeamParametersTest {
|
||||
@BeforeAll
|
||||
static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTeamParameters() {
|
||||
IChatBaseComponent displayName = IChatBaseComponent.b("display name");
|
||||
IChatBaseComponent prefix = IChatBaseComponent.b("prefix");
|
||||
IChatBaseComponent suffix = IChatBaseComponent.b("suffix");
|
||||
String nametagVisibility = "always";
|
||||
String collisionRule = "never";
|
||||
|
||||
WrappedTeamParameters wrapped = WrappedTeamParameters.newBuilder()
|
||||
.displayName(WrappedChatComponent.fromHandle(displayName))
|
||||
.prefix(WrappedChatComponent.fromHandle(prefix))
|
||||
.suffix(WrappedChatComponent.fromHandle(suffix))
|
||||
.nametagVisibility(nametagVisibility)
|
||||
.collisionRule(collisionRule)
|
||||
.color(EnumWrappers.ChatFormatting.RED)
|
||||
.options(1)
|
||||
.build();
|
||||
|
||||
assertEquals(displayName, wrapped.getDisplayName().getHandle());
|
||||
assertEquals(prefix, wrapped.getPrefix().getHandle());
|
||||
assertEquals(suffix, wrapped.getSuffix().getHandle());
|
||||
assertEquals(nametagVisibility, wrapped.getNametagVisibility());
|
||||
assertEquals(collisionRule, wrapped.getCollisionRule());
|
||||
assertEquals(EnumWrappers.ChatFormatting.RED, wrapped.getColor());
|
||||
assertEquals(1, wrapped.getOptions());
|
||||
|
||||
PacketPlayOutScoreboardTeam.b handle = (PacketPlayOutScoreboardTeam.b) wrapped.getHandle();
|
||||
assertEquals(handle.a(), displayName);
|
||||
assertEquals(handle.f(), prefix);
|
||||
assertEquals(handle.g(), suffix);
|
||||
assertEquals(handle.d(), nametagVisibility);
|
||||
assertEquals(handle.e(), collisionRule);
|
||||
assertEquals(handle.c(), EnumChatFormat.m);
|
||||
assertEquals(handle.b(), 1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user