diff --git a/pom.xml b/pom.xml index 6d8bd01c..6adc9921 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.9.0 4.6.1 4.1.77.Final - 1.19.3-R0.1-SNAPSHOT + 1.19.4-R0.1-SNAPSHOT diff --git a/src/main/java/com/comphenix/protocol/PacketType.java b/src/main/java/com/comphenix/protocol/PacketType.java index 02e71b88..29956062 100644 --- a/src/main/java/com/comphenix/protocol/PacketType.java +++ b/src/main/java/com/comphenix/protocol/PacketType.java @@ -102,113 +102,117 @@ public class PacketType implements Serializable, Cloneable, Comparable structureModifier) { + public InternalStructure(Object handle, StructureModifier structureModifier) { super(handle, structureModifier); } diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java b/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java index 3b5bb6d1..beb78491 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java @@ -85,6 +85,7 @@ public final class MinecraftProtocolVersion { map.put(new MinecraftVersion(1, 19, 1), 760); map.put(new MinecraftVersion(1, 19, 2), 760); map.put(new MinecraftVersion(1, 19, 3), 761); + map.put(new MinecraftVersion(1, 19, 4), 762); return map; } diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftVersion.java b/src/main/java/com/comphenix/protocol/utility/MinecraftVersion.java index a358b269..99ff0f2f 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftVersion.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftVersion.java @@ -37,6 +37,11 @@ import org.bukkit.Server; */ public final class MinecraftVersion implements Comparable, Serializable { + /** + * Version 1.19.4 - the rest of the feature preview + */ + public static final MinecraftVersion FEATURE_PREVIEW_2 = new MinecraftVersion("1.19.4"); + /** * Version 1.19.3 - introducing feature preview */ @@ -117,7 +122,7 @@ public final class MinecraftVersion implements Comparable, Ser /** * The latest release version of minecraft. */ - public static final MinecraftVersion LATEST = FEATURE_PREVIEW_UPDATE; + public static final MinecraftVersion LATEST = FEATURE_PREVIEW_2; // used when serializing private static final long serialVersionUID = -8695133558996459770L; diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedServerPing.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedServerPing.java index 52bcff88..d9398334 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedServerPing.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedServerPing.java @@ -4,22 +4,21 @@ import com.comphenix.protocol.PacketType; import com.comphenix.protocol.injector.BukkitUnwrapper; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.accessors.Accessors; -import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor; -import com.comphenix.protocol.utility.MinecraftProtocolVersion; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftVersion; -import com.comphenix.protocol.utility.Util; +import com.comphenix.protocol.wrappers.ping.LegacyServerPing; +import com.comphenix.protocol.wrappers.ping.ServerPingImpl; +import com.comphenix.protocol.wrappers.ping.ServerPingRecord; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.io.ByteStreams; + import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.base64.Base64; -import org.bukkit.Bukkit; -import org.bukkit.Server; import org.bukkit.entity.Player; import javax.imageio.ImageIO; @@ -37,52 +36,21 @@ import java.util.List; * Represents a server ping packet data. * @author Kristian */ -public class WrappedServerPing extends AbstractWrapper implements ClonableWrapper { - private static Class GAME_PROFILE = MinecraftReflection.getGameProfileClass(); - private static Class GAME_PROFILE_ARRAY = MinecraftReflection.getArrayClass(GAME_PROFILE); - - // Server ping fields - private static Class SERVER_PING = MinecraftReflection.getServerPingClass(); - private static ConstructorAccessor SERVER_PING_CONSTRUCTOR = Accessors.getConstructorAccessor(SERVER_PING); - private static FieldAccessor DESCRIPTION = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getIChatBaseComponentClass(), true); - private static FieldAccessor PLAYERS = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getServerPingPlayerSampleClass(), true); - private static FieldAccessor VERSION = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getServerPingServerDataClass(), true); - private static FieldAccessor FAVICON = Accessors.getFieldAccessor(SERVER_PING, String.class, true); - private static FieldAccessor[] BOOLEAN_ACCESSORS = Accessors.getFieldAccessorArray(SERVER_PING, boolean.class, true); +public class WrappedServerPing implements ClonableWrapper { + private static final Class GAME_PROFILE = MinecraftReflection.getGameProfileClass(); // For converting to the underlying array - private static EquivalentConverter> PROFILE_CONVERT = - BukkitConverters.getArrayConverter(GAME_PROFILE, BukkitConverters.getWrappedGameProfileConverter()); - - // Server ping player sample fields - private static Class PLAYERS_CLASS = MinecraftReflection.getServerPingPlayerSampleClass(); - private static ConstructorAccessor PLAYERS_CONSTRUCTOR = Accessors.getConstructorAccessor(PLAYERS_CLASS, int.class, int.class); - private static FieldAccessor[] PLAYERS_INTS = Accessors.getFieldAccessorArray(PLAYERS_CLASS, int.class, true); - private static FieldAccessor PLAYERS_PROFILES = Accessors.getFieldAccessor(PLAYERS_CLASS, GAME_PROFILE_ARRAY, true); - private static FieldAccessor PLAYERS_MAXIMUM = PLAYERS_INTS[0]; - private static FieldAccessor PLAYERS_ONLINE = PLAYERS_INTS[1]; - - // Server ping serialization - private static Class GSON_CLASS = MinecraftReflection.getMinecraftGsonClass(); - private static MethodAccessor GSON_TO_JSON = Accessors.getMethodAccessor(GSON_CLASS, "toJson", Object.class); - private static MethodAccessor GSON_FROM_JSON = Accessors.getMethodAccessor(GSON_CLASS, "fromJson", String.class, Class.class); - private static FieldAccessor PING_GSON = Accessors.getMemorizing(Accessors.getFieldAccessor( - PacketType.Status.Server.SERVER_INFO.getPacketClass(), GSON_CLASS, true - )); - - // Server data fields - private static Class VERSION_CLASS = MinecraftReflection.getServerPingServerDataClass(); - private static ConstructorAccessor VERSION_CONSTRUCTOR = Accessors.getConstructorAccessor(VERSION_CLASS, String.class, int.class); - private static FieldAccessor VERSION_NAME = Accessors.getFieldAccessor(VERSION_CLASS, String.class, true); - private static FieldAccessor VERSION_PROTOCOL = Accessors.getFieldAccessor(VERSION_CLASS, int.class, true); + private static final EquivalentConverter> PROFILE_CONVERT = + BukkitConverters.getArrayConverter(GAME_PROFILE, BukkitConverters.getWrappedGameProfileConverter()); // Get profile from player - private static FieldAccessor ENTITY_HUMAN_PROFILE = Accessors.getFieldAccessor( - MinecraftReflection.getEntityPlayerClass().getSuperclass(), GAME_PROFILE, true); + private static final FieldAccessor ENTITY_HUMAN_PROFILE = Accessors.getFieldAccessor( + MinecraftReflection.getEntityPlayerClass().getSuperclass(), GAME_PROFILE, true); - // Inner class - private Object players; // may be NULL - private Object version; + // Server ping fields + private static final Class SERVER_PING = MinecraftReflection.getServerPingClass(); + + private final ServerPingImpl impl; /** * Construct a new server ping initialized with a zero player count, and zero maximum. @@ -90,34 +58,44 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * Note that the version string is set to 1.9.4. */ public WrappedServerPing() { - super(MinecraftReflection.getServerPingClass()); - setHandle(SERVER_PING_CONSTRUCTOR.invoke()); + this.impl = newImpl(); + resetPlayers(); resetVersion(); } private WrappedServerPing(Object handle) { - super(MinecraftReflection.getServerPingClass()); - setHandle(handle); - this.players = PLAYERS.get(handle); - this.version = VERSION.get(handle); + this.impl = newImpl(handle); + } + + private ServerPingImpl newImpl() { + if (MinecraftVersion.FEATURE_PREVIEW_2.atOrAbove()) { + return new ServerPingRecord(); + } + + return new LegacyServerPing(); + } + + private ServerPingImpl newImpl(Object handle) { + if (MinecraftVersion.FEATURE_PREVIEW_2.atOrAbove()) { + return new ServerPingRecord(); + } + + return new LegacyServerPing(handle); } /** * Set the player count and player maximum to the default values. */ protected void resetPlayers() { - players = PLAYERS_CONSTRUCTOR.invoke(0, 0); - PLAYERS.set(handle, players); + impl.resetPlayers(); } /** * Reset the version string to the default state. */ protected void resetVersion() { - MinecraftVersion minecraftVersion = MinecraftVersion.getCurrentVersion(); - version = VERSION_CONSTRUCTOR.invoke(minecraftVersion.toString(), MinecraftProtocolVersion.getCurrentVersion()); - VERSION.set(handle, version); + impl.resetVersion(); } /** @@ -135,7 +113,8 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The wrapped server ping. */ public static WrappedServerPing fromJson(String json) { - return fromHandle(GSON_FROM_JSON.invoke(PING_GSON.get(null), json, SERVER_PING)); + // return fromHandle(GSON_FROM_JSON.invoke(PING_GSON.get(null), json, SERVER_PING)); + return null; } /** @@ -143,7 +122,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The messge of the day. */ public WrappedChatComponent getMotD() { - return WrappedChatComponent.fromHandle(DESCRIPTION.get(handle)); + return WrappedChatComponent.fromHandle(impl.getMotD()); } /** @@ -151,7 +130,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param description - message of the day. */ public void setMotD(WrappedChatComponent description) { - DESCRIPTION.set(handle, description.getHandle()); + impl.setMotD(description.getHandle()); } /** @@ -167,7 +146,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The favicon, or NULL if no favicon will be displayed. */ public CompressedImage getFavicon() { - String favicon = (String) FAVICON.get(handle); + String favicon = impl.getFavicon(); return (favicon != null) ? CompressedImage.fromEncodedText(favicon) : null; } @@ -176,7 +155,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param image - the new compressed image or NULL if no favicon should be displayed. */ public void setFavicon(CompressedImage image) { - FAVICON.set(handle, (image != null) ? image.toEncodedText() : null); + impl.setFavicon((image != null) ? image.toEncodedText() : null); } /** @@ -187,7 +166,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe */ @Deprecated public boolean isChatPreviewEnabled() { - return (Boolean) BOOLEAN_ACCESSORS[0].get(handle); + return impl.isChatPreviewEnabled(); } /** @@ -198,7 +177,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe */ @Deprecated public void setChatPreviewEnabled(boolean chatPreviewEnabled) { - BOOLEAN_ACCESSORS[0].set(handle, chatPreviewEnabled); + impl.setChatPreviewEnabled(chatPreviewEnabled); } /** @@ -207,8 +186,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @since 1.19.1 */ public boolean isEnforceSecureChat() { - int index = MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove() ? 0 : 1; - return (Boolean) BOOLEAN_ACCESSORS[index].get(handle); + return impl.isEnforceSecureChat(); } /** @@ -217,8 +195,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @since 1.19.1 */ public void setEnforceSecureChat(boolean enforceSecureChat) { - int index = MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove() ? 0 : 1; - BOOLEAN_ACCESSORS[index].set(handle, enforceSecureChat); + impl.setEnforceSecureChat(enforceSecureChat); } /** @@ -228,9 +205,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @see #setPlayersOnline(int) */ public int getPlayersOnline() { - if (players == null) - throw new IllegalStateException("The player count has been hidden."); - return (Integer) PLAYERS_ONLINE.get(players); + return impl.getPlayersOnline(); } /** @@ -241,9 +216,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param online - online players. */ public void setPlayersOnline(int online) { - if (players == null) - resetPlayers(); - PLAYERS_ONLINE.set(players, online); + impl.setPlayersOnline(online); } /** @@ -253,9 +226,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @see #setPlayersMaximum(int) */ public int getPlayersMaximum() { - if (players == null) - throw new IllegalStateException("The player maximum has been hidden."); - return (Integer) PLAYERS_MAXIMUM.get(players); + return impl.getPlayersMaximum(); } /** @@ -266,9 +237,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param maximum - maximum player count. */ public void setPlayersMaximum(int maximum) { - if (players == null) - resetPlayers(); - PLAYERS_MAXIMUM.set(players, maximum); + impl.setPlayersMaximum(maximum); } /** @@ -279,14 +248,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe */ public void setPlayersVisible(boolean visible) { if (isPlayersVisible() != visible) { - if (visible) { - // Recreate the count and maximum - Server server = Bukkit.getServer(); - setPlayersMaximum(server.getMaxPlayers()); - setPlayersOnline(Bukkit.getOnlinePlayers().size()); - } else { - PLAYERS.set(handle, players = null); - } + impl.setPlayersVisible(visible); } } @@ -297,7 +259,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return TRUE if the player statistics is visible, FALSE otherwise. */ public boolean isPlayersVisible() { - return players != null; + return impl.arePlayersVisible(); } /** @@ -305,9 +267,9 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return Logged in players or an empty list if no player names will be displayed. */ public ImmutableList getPlayers() { - if (players == null) + if (!isPlayersVisible()) return ImmutableList.of(); - Object playerProfiles = PLAYERS_PROFILES.get(players); + Object playerProfiles = impl.getPlayers(); if (playerProfiles == null) return ImmutableList.of(); return ImmutableList.copyOf(PROFILE_CONVERT.getSpecific(playerProfiles)); @@ -318,9 +280,9 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param profile - every logged in player. */ public void setPlayers(Iterable profile) { - if (players == null) + if (!isPlayersVisible()) resetPlayers(); - PLAYERS_PROFILES.set(players, (profile != null) ? PROFILE_CONVERT.getGeneric(profile) : null); + impl.setPlayers((profile != null) ? PROFILE_CONVERT.getGeneric(profile) : null); } /** @@ -343,7 +305,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The version name. */ public String getVersionName() { - return (String) VERSION_NAME.get(version); + return impl.getVersionName(); } /** @@ -351,7 +313,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param name - the new version name. */ public void setVersionName(String name) { - VERSION_NAME.set(version, name); + impl.setVersionName(name); } /** @@ -359,7 +321,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The protocol. */ public int getVersionProtocol() { - return (Integer) VERSION_PROTOCOL.get(version); + return impl.getVersionProtocol(); } /** @@ -367,7 +329,12 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @param protocol - the protocol number. */ public void setVersionProtocol(int protocol) { - VERSION_PROTOCOL.set(version, protocol); + impl.setVersionProtocol(protocol); + } + + @Override + public Object getHandle() { + return impl.getHandle(); } /** @@ -398,7 +365,8 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe * @return The JSON representation. */ public String toJson() { - return (String) GSON_TO_JSON.invoke(PING_GSON.get(null), handle); + return null; + // return (String) GSON_TO_JSON.invoke(PING_GSON.get(null), getHandle()); } @Override diff --git a/src/main/java/com/comphenix/protocol/wrappers/ping/LegacyServerPing.java b/src/main/java/com/comphenix/protocol/wrappers/ping/LegacyServerPing.java new file mode 100644 index 00000000..85e28c5f --- /dev/null +++ b/src/main/java/com/comphenix/protocol/wrappers/ping/LegacyServerPing.java @@ -0,0 +1,399 @@ +package com.comphenix.protocol.wrappers.ping; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.injector.BukkitUnwrapper; +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; +import com.comphenix.protocol.reflect.accessors.FieldAccessor; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.utility.MinecraftProtocolVersion; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.MinecraftVersion; +import com.comphenix.protocol.wrappers.AbstractWrapper; +import com.comphenix.protocol.wrappers.BukkitConverters; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.google.common.collect.ImmutableList; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a server ping packet data. + * @author Kristian + */ +public class LegacyServerPing extends AbstractWrapper implements ServerPingImpl { + private static final Class GAME_PROFILE = MinecraftReflection.getGameProfileClass(); + + // For converting to the underlying array + private static final EquivalentConverter> PROFILE_CONVERT = + BukkitConverters.getArrayConverter(GAME_PROFILE, BukkitConverters.getWrappedGameProfileConverter()); + + // Get profile from player + private static final FieldAccessor ENTITY_HUMAN_PROFILE = Accessors.getFieldAccessor( + MinecraftReflection.getEntityPlayerClass().getSuperclass(), GAME_PROFILE, true); + + private static final Class GAME_PROFILE_ARRAY = MinecraftReflection.getArrayClass(GAME_PROFILE); + + // Server ping fields + private static final Class SERVER_PING = MinecraftReflection.getServerPingClass(); + private static final ConstructorAccessor SERVER_PING_CONSTRUCTOR = Accessors.getConstructorAccessor(SERVER_PING); + private static final FieldAccessor DESCRIPTION = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getIChatBaseComponentClass(), true); + private static final FieldAccessor PLAYERS = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getServerPingPlayerSampleClass(), true); + private static final FieldAccessor VERSION = Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getServerPingServerDataClass(), true); + private static final FieldAccessor FAVICON = Accessors.getFieldAccessor(SERVER_PING, String.class, true); + private static final FieldAccessor[] BOOLEAN_ACCESSORS = Accessors.getFieldAccessorArray(SERVER_PING, boolean.class, true); + + // Server ping player sample fields + private static final Class PLAYERS_CLASS = MinecraftReflection.getServerPingPlayerSampleClass(); + private static final ConstructorAccessor PLAYERS_CONSTRUCTOR = Accessors.getConstructorAccessor(PLAYERS_CLASS, int.class, int.class); + private static final FieldAccessor[] PLAYERS_INTS = Accessors.getFieldAccessorArray(PLAYERS_CLASS, int.class, true); + private static final FieldAccessor PLAYERS_PROFILES = Accessors.getFieldAccessor(PLAYERS_CLASS, GAME_PROFILE_ARRAY, true); + private static final FieldAccessor PLAYERS_MAXIMUM = PLAYERS_INTS[0]; + private static final FieldAccessor PLAYERS_ONLINE = PLAYERS_INTS[1]; + + // Server ping serialization + private static final Class GSON_CLASS = MinecraftReflection.getMinecraftGsonClass(); + private static final MethodAccessor GSON_TO_JSON = Accessors.getMethodAccessor(GSON_CLASS, "toJson", Object.class); + private static final MethodAccessor GSON_FROM_JSON = Accessors.getMethodAccessor(GSON_CLASS, "fromJson", String.class, Class.class); + private static final FieldAccessor PING_GSON = Accessors.getMemorizing(Accessors.getFieldAccessor( + PacketType.Status.Server.SERVER_INFO.getPacketClass(), GSON_CLASS, true + )); + + // Server data fields + private static final Class VERSION_CLASS = MinecraftReflection.getServerPingServerDataClass(); + private static final ConstructorAccessor VERSION_CONSTRUCTOR = Accessors.getConstructorAccessor(VERSION_CLASS, String.class, int.class); + private static final FieldAccessor VERSION_NAME = Accessors.getFieldAccessor(VERSION_CLASS, String.class, true); + private static final FieldAccessor VERSION_PROTOCOL = Accessors.getFieldAccessor(VERSION_CLASS, int.class, true); + + + // Inner class + private Object players; // may be NULL + private Object version; + + /** + * Construct a new server ping initialized with a zero player count, and zero maximum. + *

+ * Note that the version string is set to 1.9.4. + */ + public LegacyServerPing() { + super(MinecraftReflection.getServerPingClass()); + setHandle(SERVER_PING_CONSTRUCTOR.invoke()); + resetPlayers(); + resetVersion(); + } + + public LegacyServerPing(Object handle) { + super(MinecraftReflection.getServerPingClass()); + setHandle(handle); + this.players = PLAYERS.get(handle); + this.version = VERSION.get(handle); + } + + /** + * Set the player count and player maximum to the default values. + */ + public void resetPlayers() { + players = PLAYERS_CONSTRUCTOR.invoke(0, 0); + PLAYERS.set(handle, players); + } + + /** + * Reset the version string to the default state. + */ + public void resetVersion() { + MinecraftVersion minecraftVersion = MinecraftVersion.getCurrentVersion(); + version = VERSION_CONSTRUCTOR.invoke(minecraftVersion.toString(), MinecraftProtocolVersion.getCurrentVersion()); + VERSION.set(handle, version); + } + + /** + * Construct a wrapped server ping from a native NMS object. + * @param handle - the native object. + * @return The wrapped server ping object. + */ + public static LegacyServerPing fromHandle(Object handle) { + return new LegacyServerPing(handle); + } + + /** + * Construct a wrapper server ping from an encoded JSON string. + * @param json - the JSON string. + * @return The wrapped server ping. + */ + public static LegacyServerPing fromJson(String json) { + return fromHandle(GSON_FROM_JSON.invoke(PING_GSON.get(null), json, SERVER_PING)); + } + + /** + * Retrieve the message of the day. + * @return The messge of the day. + */ + public WrappedChatComponent getMotD() { + return WrappedChatComponent.fromHandle(DESCRIPTION.get(handle)); + } + + /** + * Set the message of the day. + * @param description - message of the day. + */ + public void setMotD(Object description) { + DESCRIPTION.set(handle, description); + } + + /** + * Set the message of the day. + * @param message - the message. + */ + public void setMotD(String message) { + setMotD(WrappedChatComponent.fromLegacyText(message)); + } + + /** + * Retrieve the compressed PNG file that is being displayed as a favicon. + * @return The favicon, or NULL if no favicon will be displayed. + */ + public String getFavicon() { + return (String) FAVICON.get(handle); + } + + /** + * Set the compressed PNG file that is being displayed. + * @param image - the new compressed image or NULL if no favicon should be displayed. + */ + public void setFavicon(String image) { + FAVICON.set(handle, image); + } + + /** + * Retrieve whether chat preview is enabled on the server. + * @return whether chat preview is enabled on the server. + * @since 1.19 + * @deprecated Removed in 1.19.3 + */ + @Deprecated + public boolean isChatPreviewEnabled() { + return (Boolean) BOOLEAN_ACCESSORS[0].get(handle); + } + + /** + * Sets whether chat preview is enabled on the server. + * @param chatPreviewEnabled true if enabled, false otherwise. + * @since 1.19 + * @deprecated Removed in 1.19.3 + */ + @Deprecated + public void setChatPreviewEnabled(boolean chatPreviewEnabled) { + BOOLEAN_ACCESSORS[0].set(handle, chatPreviewEnabled); + } + + /** + * Sets whether the server enforces secure chat. + * @return whether the server enforces secure chat. + * @since 1.19.1 + */ + public boolean isEnforceSecureChat() { + int index = MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove() ? 0 : 1; + return (Boolean) BOOLEAN_ACCESSORS[index].get(handle); + } + + /** + * Sets whether the server enforces secure chat. + * @param enforceSecureChat true if enabled, false otherwise. + * @since 1.19.1 + */ + public void setEnforceSecureChat(boolean enforceSecureChat) { + int index = MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove() ? 0 : 1; + BOOLEAN_ACCESSORS[index].set(handle, enforceSecureChat); + } + + /** + * Retrieve the displayed number of online players. + * @return The displayed number. + * @throws IllegalStateException If the player count has been hidden via {@link #setPlayersVisible(boolean)}. + * @see #setPlayersOnline(int) + */ + public int getPlayersOnline() { + if (players == null) + throw new IllegalStateException("The player count has been hidden."); + return (Integer) PLAYERS_ONLINE.get(players); + } + + /** + * Set the displayed number of online players. + *

+ * As of 1.7.2, this is completely unrestricted, and can be both positive and + * negative, as well as higher than the player maximum. + * @param online - online players. + */ + public void setPlayersOnline(int online) { + if (players == null) + resetPlayers(); + PLAYERS_ONLINE.set(players, online); + } + + /** + * Retrieve the displayed maximum number of players. + * @return The maximum number. + * @throws IllegalStateException If the player maximum has been hidden via {@link #setPlayersVisible(boolean)}. + * @see #setPlayersMaximum(int) + */ + public int getPlayersMaximum() { + if (players == null) + throw new IllegalStateException("The player maximum has been hidden."); + return (Integer) PLAYERS_MAXIMUM.get(players); + } + + /** + * Set the displayed maximum number of players. + *

+ * The 1.7.2 accepts any value as a player maximum, positive or negative. It even permits a player maximum that + * is less than the player count. + * @param maximum - maximum player count. + */ + public void setPlayersMaximum(int maximum) { + if (players == null) + resetPlayers(); + PLAYERS_MAXIMUM.set(players, maximum); + } + + /** + * Set whether or not the player count and player maximum is visible. + *

+ * Note that this may set the current player count and maximum to their respective real values. + * @param visible - TRUE if it should be visible, FALSE otherwise. + */ + public void setPlayersVisible(boolean visible) { + if (arePlayersVisible() != visible) { + if (visible) { + // Recreate the count and maximum + Server server = Bukkit.getServer(); + setPlayersMaximum(server.getMaxPlayers()); + setPlayersOnline(Bukkit.getOnlinePlayers().size()); + } else { + PLAYERS.set(handle, players = null); + } + } + } + + /** + * Determine if the player count and maximum is visible. + *

+ * If not, the client will display ??? in the same location. + * @return TRUE if the player statistics is visible, FALSE otherwise. + */ + public boolean arePlayersVisible() { + return players != null; + } + + /** + * Retrieve a copy of all the logged in players. + * @return Logged in players or an empty list if no player names will be displayed. + */ + public ImmutableList getPlayers() { + if (players == null) + return ImmutableList.of(); + Object playerProfiles = PLAYERS_PROFILES.get(players); + if (playerProfiles == null) + return ImmutableList.of(); + return ImmutableList.copyOf(PROFILE_CONVERT.getSpecific(playerProfiles)); + } + + /** + * Set the displayed list of logged in players. + * @param profile - every logged in player. + */ + public void setPlayers(Object profile) { + if (players == null) + resetPlayers(); + PLAYERS_PROFILES.set(players, profile); + } + + /** + * Set the displayed lst of logged in players. + * @param players - the players to display. + */ + public void setBukkitPlayers(Iterable players) { + final List profiles = new ArrayList<>(); + + for (Player player : players) { + Object profile = ENTITY_HUMAN_PROFILE.get(BukkitUnwrapper.getInstance().unwrapItem(player)); + profiles.add(WrappedGameProfile.fromHandle(profile)); + } + + setPlayers(profiles); + } + + /** + * Retrieve the version name of the current server. + * @return The version name. + */ + public String getVersionName() { + return (String) VERSION_NAME.get(version); + } + + /** + * Set the version name of the current server. + * @param name - the new version name. + */ + public void setVersionName(String name) { + VERSION_NAME.set(version, name); + } + + /** + * Retrieve the protocol number. + * @return The protocol. + */ + public int getVersionProtocol() { + return (Integer) VERSION_PROTOCOL.get(version); + } + + /** + * Set the version protocol + * @param protocol - the protocol number. + */ + public void setVersionProtocol(int protocol) { + VERSION_PROTOCOL.set(version, protocol); + } + + /** + * Retrieve a deep copy of the current wrapper object. + * @return The current object. + */ + public LegacyServerPing deepClone() { + LegacyServerPing copy = new LegacyServerPing(); + WrappedChatComponent motd = getMotD(); + + copy.setPlayers(getPlayers()); + copy.setFavicon(getFavicon()); + copy.setMotD(motd != null ? motd.deepClone() : null); + copy.setVersionName(getVersionName()); + copy.setVersionProtocol(getVersionProtocol()); + + if (arePlayersVisible()) { + copy.setPlayersMaximum(getPlayersMaximum()); + copy.setPlayersOnline(getPlayersOnline()); + } else { + copy.setPlayersVisible(false); + } + return copy; + } + + /** + * Retrieve the underlying JSON representation of this server ping. + * @return The JSON representation. + */ + public String toJson() { + return (String) GSON_TO_JSON.invoke(PING_GSON.get(null), handle); + } + + @Override + public String toString() { + return "WrappedServerPing< " + toJson() + ">"; + } +} diff --git a/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingImpl.java b/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingImpl.java new file mode 100644 index 00000000..7606c3f3 --- /dev/null +++ b/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingImpl.java @@ -0,0 +1,42 @@ +package com.comphenix.protocol.wrappers.ping; + +import java.util.List; + +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage; + +public interface ServerPingImpl { + Object getMotD(); + void setMotD(Object description); + int getPlayersMaximum(); + void setPlayersMaximum(int maxPlayers); + int getPlayersOnline(); + void setPlayersOnline(int onlineCount); + Object getPlayers(); + void setPlayers(Object playerSample); + String getVersionName(); + void setVersionName(String versionName); + int getVersionProtocol(); + void setVersionProtocol(int protocolVersion); + String getFavicon(); + void setFavicon(String favicon); + boolean isEnforceSecureChat(); + void setEnforceSecureChat(boolean safeChat); + + void resetPlayers(); + void resetVersion(); + + default boolean isChatPreviewEnabled() { + return false; + } + + default void setChatPreviewEnabled(boolean enabled) { + + } + + boolean arePlayersVisible(); + void setPlayersVisible(boolean visible); + + Object getHandle(); +} \ No newline at end of file diff --git a/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingRecord.java b/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingRecord.java new file mode 100644 index 00000000..da15146d --- /dev/null +++ b/src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingRecord.java @@ -0,0 +1,264 @@ +package com.comphenix.protocol.wrappers.ping; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; +import java.util.Optional; + +import com.comphenix.protocol.events.AbstractStructure; +import com.comphenix.protocol.events.InternalStructure; +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.MinecraftProtocolVersion; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.MinecraftVersion; +import com.comphenix.protocol.wrappers.*; + +import org.bukkit.Bukkit; + +public class ServerPingRecord implements ServerPingImpl { + private static Class SERVER_PING; + private static Class PLAYER_SAMPLE_CLASS; + private static Class SERVER_DATA_CLASS; + + private static WrappedChatComponent DEFAULT_DESCRIPTION; + + private static ConstructorAccessor PING_CTOR; + + private static boolean initialized; + + private static void initialize() { + if (initialized) { + return; + } + + initialized = true; + + try { + SERVER_PING = MinecraftReflection.getServerPingClass(); + PLAYER_SAMPLE_CLASS = MinecraftReflection.getServerPingPlayerSampleClass(); + SERVER_DATA_CLASS = MinecraftReflection.getServerPingServerDataClass(); + + PING_CTOR = Accessors.getConstructorAccessor(SERVER_PING.getConstructors()[0]); + + DATA_WRAPPER = AutoWrapper + .wrap(ServerData.class, SERVER_DATA_CLASS) + .field(0, Converters.passthrough(String.class)) + .field(1, Converters.passthrough(int.class)); + + SAMPLE_WRAPPER = AutoWrapper + .wrap(PlayerSample.class, PLAYER_SAMPLE_CLASS) + .field(0, Converters.passthrough(int.class)) + .field(1, Converters.passthrough(int.class)) + .field(2, Converters.passthrough(Object.class)); + + FAVICON_WRAPPER = AutoWrapper + .wrap(Favicon.class, MinecraftReflection.getMinecraftClass("network.protocol.status.ServerPing$a")) + .field(0, Converters.passthrough(byte[].class)); + + DEFAULT_DESCRIPTION = WrappedChatComponent.fromLegacyText("A Minecraft Server"); + } catch (Exception ex) { + ex.printStackTrace(); // TODO + } + } + + private static class PlayerSample { + public int max; + public int online; + public Object sample; + } + + private static class ServerData { + public String name; + public int protocol; + } + + private static class Favicon { + public byte[] iconBytes; + } + + private static AutoWrapper SAMPLE_WRAPPER; + + private static AutoWrapper DATA_WRAPPER; + + private static AutoWrapper FAVICON_WRAPPER; + + private Object description; + private PlayerSample playerSample; + private ServerData serverData; + private Favicon favicon; + private boolean enforceSafeChat; + private boolean playersVisible = true; + + private static ServerData defaultData() { + ServerData data = new ServerData(); + data.name = MinecraftVersion.getCurrentVersion().toString(); + data.protocol = MinecraftProtocolVersion.getCurrentVersion(); + return data; + } + + private static PlayerSample defaultSample() { + PlayerSample sample = new PlayerSample(); + sample.max = Bukkit.getMaxPlayers(); + sample.online = Bukkit.getOnlinePlayers().size(); + sample.sample = null; + return sample; + } + + private static Favicon defaultFavicon() { + Favicon favicon = new Favicon(); + favicon.iconBytes = new byte[0]; + return favicon; + } + + public ServerPingRecord(Object handle) { + initialize(); + + StructureModifier modifier = new StructureModifier<>(handle.getClass()).withTarget(handle); + InternalStructure structure = new InternalStructure(handle, modifier); + + this.description = structure.getChatComponents().readSafely(0); + + StructureModifier> optionals = structure.getOptionals(Converters.passthrough(Object.class)); + + Optional sampleHandle = optionals.readSafely(0); + if (sampleHandle.isPresent()) { + this.playerSample = SAMPLE_WRAPPER.wrap(sampleHandle.get()); + } else { + this.playerSample = defaultSample(); + } + + Optional dataHandle = optionals.readSafely(1); + if (dataHandle.isPresent()) { + this.serverData = DATA_WRAPPER.wrap(dataHandle.get()); + } else { + this.serverData = defaultData(); + } + + Optional faviconHandle = optionals.readSafely(2); + if (faviconHandle.isPresent()) { + this.favicon = FAVICON_WRAPPER.wrap(faviconHandle.get()); + } else { + this.favicon = defaultFavicon(); + } + + this.enforceSafeChat = structure.getBooleans().readSafely(0); + } + + public ServerPingRecord() { + initialize(); + + this.description = DEFAULT_DESCRIPTION; + this.favicon = defaultFavicon(); + } + + @Override + public Object getMotD() { + return description; + } + + @Override + public void setMotD(Object description) { + this.description = description; + } + + @Override + public int getPlayersMaximum() { + return playerSample.max; + } + + @Override + public void setPlayersMaximum(int maxPlayers) { + playerSample.max = maxPlayers; + } + + @Override + public int getPlayersOnline() { + return playerSample.online; + } + + @Override + public void setPlayersOnline(int onlineCount) { + playerSample.online = onlineCount; + } + + @Override + public Object getPlayers() { + return playerSample; + } + + @Override + public void setPlayers(Object playerSample) { + this.playerSample.sample = playerSample; + } + + @Override + public String getVersionName() { + return serverData.name; + } + + @Override + public void setVersionName(String versionName) { + serverData.name = versionName; + } + + @Override + public int getVersionProtocol() { + return serverData.protocol; + } + + @Override + public void setVersionProtocol(int protocolVersion) { + serverData.protocol = protocolVersion; + } + + @Override + public String getFavicon() { + return new String(favicon.iconBytes, StandardCharsets.UTF_8); + } + + @Override + public void setFavicon(String favicon) { + this.favicon.iconBytes = favicon.getBytes(StandardCharsets.UTF_8); + } + + @Override + public boolean isEnforceSecureChat() { + return enforceSafeChat; + } + + @Override + public void setEnforceSecureChat(boolean safeChat) { + this.enforceSafeChat = safeChat; + } + + @Override + public void resetPlayers() { + this.playerSample = defaultSample(); + } + + @Override + public void resetVersion() { + this.serverData = defaultData(); + } + + @Override + public boolean arePlayersVisible() { + return playersVisible; + } + + @Override + public void setPlayersVisible(boolean visible) { + this.playersVisible = visible; + } + + @Override + public Object getHandle() { + Optional players = Optional.of(SAMPLE_WRAPPER.unwrap(playerSample)); + Optional version = Optional.of(DATA_WRAPPER.unwrap(serverData)); + Optional favHandle = Optional.of(FAVICON_WRAPPER.unwrap(favicon)); + + return PING_CTOR.invoke(description, players, version, favHandle, enforceSafeChat); + } +} diff --git a/src/test/java/com/comphenix/protocol/BukkitInitialization.java b/src/test/java/com/comphenix/protocol/BukkitInitialization.java index 843a95ab..0f00d6b9 100644 --- a/src/test/java/com/comphenix/protocol/BukkitInitialization.java +++ b/src/test/java/com/comphenix/protocol/BukkitInitialization.java @@ -14,10 +14,10 @@ import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R2.CraftServer; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemFactory; -import org.bukkit.craftbukkit.v1_19_R2.util.Versioning; +import org.bukkit.craftbukkit.v1_19_R3.CraftServer; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemFactory; +import org.bukkit.craftbukkit.v1_19_R3.util.Versioning; import org.spigotmc.SpigotWorldConfig; import static org.mockito.Mockito.mock; diff --git a/src/test/java/com/comphenix/protocol/PacketTypeTest.java b/src/test/java/com/comphenix/protocol/PacketTypeTest.java index 2fa60808..de342b68 100644 --- a/src/test/java/com/comphenix/protocol/PacketTypeTest.java +++ b/src/test/java/com/comphenix/protocol/PacketTypeTest.java @@ -61,7 +61,9 @@ public class PacketTypeTest { } @SuppressWarnings("unchecked") - public static void main(String[] args) throws Exception { + // @Test + // public static void main(String[] args) throws Exception { + public void generateNewPackets() throws Exception { MinecraftReflectionTestUtil.init(); Set> allTypes = new HashSet<>(); @@ -71,7 +73,7 @@ public class PacketTypeTest { for (EnumProtocol protocol : protocols) { System.out.println(WordUtils.capitalize(protocol.name().toLowerCase())); - Field field = EnumProtocol.class.getDeclaredField("j"); + Field field = EnumProtocol.class.getDeclaredField("k"); field.setAccessible(true); Map map = (Map) field.get(protocol); @@ -173,18 +175,35 @@ public class PacketTypeTest { className = classNames.get(classNames.size() - 1); - // Format it like SET_PROTOCOL - StringBuilder fieldName = new StringBuilder(); - char[] chars = className.toCharArray(); - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (i != 0 && Character.isUpperCase(c)) { - fieldName.append("_"); + PacketType existing = null; + try { + existing = PacketType.fromClass(clazz); + if (existing.isDynamic()) { + existing = null; } - fieldName.append(Character.toUpperCase(c)); + } catch (Exception ignored) { + // doesn't exist } - builder.append(fieldName.toString().replace("N_B_T", "NBT")); + String fieldName; + if (existing == null) { + // Format it like SET_PROTOCOL + StringBuilder fieldNameBuilder = new StringBuilder(); + char[] chars = className.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (i != 0 && Character.isUpperCase(c)) { + fieldNameBuilder.append("_"); + } + fieldNameBuilder.append(Character.toUpperCase(c)); + } + + fieldName = fieldNameBuilder.toString().replace("N_B_T", "NBT"); + } else { + fieldName = existing.name(); + } + + builder.append(fieldName); builder.append(" = "); // Add spacing @@ -282,7 +301,7 @@ public class PacketTypeTest { EnumProtocol[] protocols = EnumProtocol.values(); for (EnumProtocol protocol : protocols) { - Field field = EnumProtocol.class.getDeclaredField("j"); + Field field = EnumProtocol.class.getDeclaredField("k"); field.setAccessible(true); Map map = (Map) field.get(protocol); diff --git a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java index b09f1fe4..bbebadea 100644 --- a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java +++ b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -827,7 +827,8 @@ public class PacketContainerTest { // Try constructing all the packets for (PacketType type : PacketType.values()) { // TODO: try to support chat - for now chat contains to many sub classes to properly clone it - if (type.isDeprecated() || !type.isSupported() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("CHAT")) { + if (type.isDeprecated() || !type.isSupported() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("CHAT") + || type.name().contains("DELIMITER")) { continue; } diff --git a/src/test/java/com/comphenix/protocol/injector/EntityUtilitiesTest.java b/src/test/java/com/comphenix/protocol/injector/EntityUtilitiesTest.java index 8a750065..62d72eaa 100644 --- a/src/test/java/com/comphenix/protocol/injector/EntityUtilitiesTest.java +++ b/src/test/java/com/comphenix/protocol/injector/EntityUtilitiesTest.java @@ -12,8 +12,8 @@ import net.minecraft.server.level.PlayerChunkMap; import net.minecraft.server.level.PlayerChunkMap.EntityTracker; import net.minecraft.server.level.WorldServer; import net.minecraft.world.entity.Entity; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java b/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java index dc9a4253..047537d7 100644 --- a/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -13,7 +13,7 @@ import net.minecraft.world.level.ChunkCoordIntPair; import net.minecraft.world.level.block.state.IBlockData; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import org.junit.jupiter.api.AfterAll; diff --git a/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTestUtil.java b/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTestUtil.java index 1579f3fc..2bce7db0 100644 --- a/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTestUtil.java +++ b/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTestUtil.java @@ -3,7 +3,7 @@ package com.comphenix.protocol.utility; public class MinecraftReflectionTestUtil { public static final String RELEASE_TARGET = "1.19.3"; - public static final String PACKAGE_VERSION = "v1_19_R2"; + public static final String PACKAGE_VERSION = "v1_19_R3"; public static final String NMS = "net.minecraft"; public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION; diff --git a/src/test/java/com/comphenix/protocol/wrappers/AutoWrapperTest.java b/src/test/java/com/comphenix/protocol/wrappers/AutoWrapperTest.java index 7a97782e..d49093a6 100644 --- a/src/test/java/com/comphenix/protocol/wrappers/AutoWrapperTest.java +++ b/src/test/java/com/comphenix/protocol/wrappers/AutoWrapperTest.java @@ -8,6 +8,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; import com.comphenix.protocol.BukkitInitialization; +import com.comphenix.protocol.utility.MinecraftReflection; + import net.minecraft.advancements.AdvancementDisplay; import net.minecraft.advancements.AdvancementFrameType; import net.minecraft.network.chat.IChatBaseComponent; @@ -20,100 +22,100 @@ import org.junit.jupiter.api.Test; public class AutoWrapperTest { - @BeforeAll - public static void initializeBukkit() { - BukkitInitialization.initializeAll(); - } + @BeforeAll + public static void initializeBukkit() { + BukkitInitialization.initializeAll(); + } - @Test - public void testToNms() { - WrappedAdvancementDisplay display = new WrappedAdvancementDisplay(); - display.title = WrappedChatComponent.fromText("Test123"); - display.description = WrappedChatComponent.fromText("Test567"); - display.item = new ItemStack(Material.GOLD_INGOT); - display.background = new MinecraftKey("test"); - display.frameType = WrappedFrameType.CHALLENGE; - display.announceChat = false; - display.showToast = true; - display.hidden = true; - display.x = 5f; - display.y = 67f; + @Test + public void testToNms() { + WrappedAdvancementDisplay display = new WrappedAdvancementDisplay(); + display.title = WrappedChatComponent.fromText("Test123"); + display.description = WrappedChatComponent.fromText("Test567"); + display.item = new ItemStack(Material.GOLD_INGOT); + display.background = new MinecraftKey("test"); + display.frameType = WrappedFrameType.CHALLENGE; + display.announceChat = false; + display.showToast = true; + display.hidden = true; + display.x = 5f; + display.y = 67f; - AdvancementDisplay nms = (AdvancementDisplay) displayWrapper().unwrap(display); + AdvancementDisplay nms = (AdvancementDisplay) displayWrapper().unwrap(display); - assertTrue(nms.h()); - assertTrue(nms.j()); - assertFalse(nms.i()); - assertEquals("test", nms.d().a()); - validateRawText(nms.a(), "Test123"); - validateRawText(nms.b(), "Test567"); - assertSame(AdvancementFrameType.b, nms.e()); - assertSame(Items.nv, nms.c().c()); - assertEquals(5f, nms.f(), 0f); - assertEquals(67f, nms.g(), 0f); - } + assertTrue(nms.h()); + assertTrue(nms.j()); + assertFalse(nms.i()); + assertEquals("test", nms.d().a()); + validateRawText(nms.a(), "Test123"); + validateRawText(nms.b(), "Test567"); + assertSame(AdvancementFrameType.b, nms.e()); + assertSame(MinecraftReflection.getBukkitItemStack(nms.c()).getType(), Material.GOLD_INGOT); + assertEquals(5f, nms.f(), 0f); + assertEquals(67f, nms.g(), 0f); + } - @Test - public void testFromNms() { - AdvancementDisplay display = new AdvancementDisplay( - new net.minecraft.world.item.ItemStack(Items.rc), - IChatBaseComponent.b("Test123"), - IChatBaseComponent.b("Test567"), - new net.minecraft.resources.MinecraftKey("minecraft", "test"), - AdvancementFrameType.b, - true, - false, - true - ); - display.a(5f, 67f); + @Test + public void testFromNms() { + AdvancementDisplay display = new AdvancementDisplay( + (net.minecraft.world.item.ItemStack)MinecraftReflection.getMinecraftItemStack(new ItemStack(Material.ENDER_EYE)), + IChatBaseComponent.b("Test123"), + IChatBaseComponent.b("Test567"), + new net.minecraft.resources.MinecraftKey("minecraft", "test"), + AdvancementFrameType.b, + true, + false, + true + ); + display.a(5f, 67f); - WrappedAdvancementDisplay wrapped = displayWrapper().wrap(display); + WrappedAdvancementDisplay wrapped = displayWrapper().wrap(display); - assertTrue(wrapped.showToast); - assertTrue(wrapped.hidden); - assertFalse(wrapped.announceChat); - assertEquals("test", wrapped.background.getKey()); - assertEquals("{\"text\":\"Test123\"}", wrapped.title.getJson()); - assertEquals("{\"text\":\"Test567\"}", wrapped.description.getJson()); - assertSame(WrappedFrameType.CHALLENGE, wrapped.frameType); - assertSame(Material.ENDER_EYE, wrapped.item.getType()); - assertEquals(5f, wrapped.x, 0f); - assertEquals(67f, wrapped.y, 0f); - } + assertTrue(wrapped.showToast); + assertTrue(wrapped.hidden); + assertFalse(wrapped.announceChat); + assertEquals("test", wrapped.background.getKey()); + assertEquals("{\"text\":\"Test123\"}", wrapped.title.getJson()); + assertEquals("{\"text\":\"Test567\"}", wrapped.description.getJson()); + assertSame(WrappedFrameType.CHALLENGE, wrapped.frameType); + assertSame(Material.ENDER_EYE, wrapped.item.getType()); + assertEquals(5f, wrapped.x, 0f); + assertEquals(67f, wrapped.y, 0f); + } - private AutoWrapper displayWrapper() { - return AutoWrapper - .wrap(WrappedAdvancementDisplay.class, "advancements.AdvancementDisplay", "advancements.DisplayInfo") - .field(0, BukkitConverters.getWrappedChatComponentConverter()) - .field(1, BukkitConverters.getWrappedChatComponentConverter()) - .field(2, BukkitConverters.getItemStackConverter()) - .field(3, MinecraftKey.getConverter()) - .field(4, EnumWrappers.getGenericConverter(getMinecraftClass("advancements.AdvancementFrameType", "advancements.FrameType"), - WrappedFrameType.class)); - } + private AutoWrapper displayWrapper() { + return AutoWrapper + .wrap(WrappedAdvancementDisplay.class, "advancements.AdvancementDisplay", "advancements.DisplayInfo") + .field(0, BukkitConverters.getWrappedChatComponentConverter()) + .field(1, BukkitConverters.getWrappedChatComponentConverter()) + .field(2, BukkitConverters.getItemStackConverter()) + .field(3, MinecraftKey.getConverter()) + .field(4, EnumWrappers.getGenericConverter(getMinecraftClass("advancements.AdvancementFrameType", "advancements.FrameType"), + WrappedFrameType.class)); + } - private void validateRawText(IChatBaseComponent component, String expected) { - LiteralContents content = assertInstanceOf(LiteralContents.class, component.b()); - assertEquals(expected, content.a()); - } + private void validateRawText(IChatBaseComponent component, String expected) { + LiteralContents content = assertInstanceOf(LiteralContents.class, component.b()); + assertEquals(expected, content.a()); + } - public enum WrappedFrameType { - TASK, - CHALLENGE, - GOAL - } + public enum WrappedFrameType { + TASK, + CHALLENGE, + GOAL + } - public static final class WrappedAdvancementDisplay { + public static final class WrappedAdvancementDisplay { - public WrappedChatComponent title; - public WrappedChatComponent description; - public ItemStack item; - public MinecraftKey background; - public WrappedFrameType frameType; - public boolean showToast; - public boolean announceChat; - public boolean hidden; - public float x; - public float y; - } + public WrappedChatComponent title; + public WrappedChatComponent description; + public ItemStack item; + public MinecraftKey background; + public WrappedFrameType frameType; + public boolean showToast; + public boolean announceChat; + public boolean hidden; + public float x; + public float y; + } } diff --git a/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java b/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java index bc016bf5..3102b5a3 100644 --- a/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java +++ b/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java @@ -19,9 +19,9 @@ import net.minecraft.world.level.block.state.IBlockData; import org.bukkit.Material; import org.bukkit.block.BlockFace; import org.bukkit.block.data.type.GlassPane; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R2.block.impl.CraftStainedGlassPane; -import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_19_R3.block.impl.CraftStainedGlassPane; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -56,7 +56,7 @@ public class WrappedBlockDataTest { @Test public void testDataCreation() { - IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).n(); + IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).o(); GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData); data.setFace(BlockFace.EAST, true); diff --git a/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java b/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java index 09de0a1a..07c8e9ff 100644 --- a/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java +++ b/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java @@ -21,8 +21,8 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import net.minecraft.world.entity.projectile.EntityEgg; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEgg; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEgg; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/comphenix/protocol/wrappers/WrappedLevelChunkDataTest.java b/src/test/java/com/comphenix/protocol/wrappers/WrappedLevelChunkDataTest.java index 9c17698d..9da6382f 100644 --- a/src/test/java/com/comphenix/protocol/wrappers/WrappedLevelChunkDataTest.java +++ b/src/test/java/com/comphenix/protocol/wrappers/WrappedLevelChunkDataTest.java @@ -25,7 +25,7 @@ import net.minecraft.world.level.chunk.ILightAccess; import net.minecraft.world.level.lighting.LightEngine; import org.apache.commons.lang3.builder.EqualsBuilder; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -58,7 +58,7 @@ public class WrappedLevelChunkDataTest { when(nmsWorld.v_()).thenReturn(256); when(nmsWorld.ai()).thenReturn(16); // LevelHeightAccessor is mocked and therefore always returns 0, there are further methods like this which might cause errors in the future - when(nmsWorld.m_()).thenReturn(engine); + when(nmsWorld.l_()).thenReturn(engine); } private final WorldServer nmsWorld; @@ -69,7 +69,7 @@ public class WrappedLevelChunkDataTest { this.nmsWorld = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle(); this.chunk = new Chunk(nmsWorld, new ChunkCoordIntPair(5, 5)); - IBlockData bellData = BuiltInRegistries.f.a(new MinecraftKey("bell")).n(); + IBlockData bellData = BuiltInRegistries.f.a(new MinecraftKey("bell")).o(); chunk.b(0).a(0, 0, 0, bellData); chunk.a(new TileEntityBell(BlockPosition.b, bellData)); @@ -77,7 +77,7 @@ public class WrappedLevelChunkDataTest { @Test public void testChunkData() { - ClientboundLevelChunkWithLightPacket packet = new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.m_(), null, null, false); + ClientboundLevelChunkWithLightPacket packet = new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.l_(), null, null, false); PacketContainer container = PacketContainer.fromPacket(packet); Object rawInstance = container.getSpecificModifier(MinecraftReflection.getLevelChunkPacketDataClass()).read(0); Object virtualInstance = BukkitConverters.getWrappedChunkDataConverter().getGeneric(container.getLevelChunkData().read(0)); @@ -117,7 +117,7 @@ public class WrappedLevelChunkDataTest { @Test public void testLightData() { - ClientboundLevelChunkWithLightPacket packet = new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.m_(), null, null, false); + ClientboundLevelChunkWithLightPacket packet = new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.l_(), null, null, false); PacketContainer container = PacketContainer.fromPacket(packet); randomizeBitSets(container.getSpecificModifier(MinecraftReflection.getLightUpdatePacketDataClass()).read(0));