From d63776ac6d2be9499a78765128f0366ec6fdfdb2 Mon Sep 17 00:00:00 2001 From: Lukas Alt Date: Sat, 26 Aug 2023 12:08:06 +0200 Subject: [PATCH 1/5] Added factory method for initializing WrappedDataValue with wrapped value and update documentation --- .../protocol/events/AbstractStructure.java | 15 +++--- .../protocol/wrappers/WrappedDataValue.java | 51 +++++++++++++++++++ .../wrappers/WrappedWatchableObject.java | 17 +++++-- 3 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java index e7ebb6a2..43746ebd 100644 --- a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java +++ b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java @@ -1,10 +1,5 @@ package com.comphenix.protocol.events; -import javax.annotation.Nonnull; -import java.lang.reflect.Array; -import java.time.Instant; -import java.util.*; - import com.comphenix.protocol.PacketType; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.StructureModifier; @@ -17,7 +12,6 @@ import com.comphenix.protocol.wrappers.nbt.NbtBase; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.google.common.base.Preconditions; - import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.Sound; @@ -31,6 +25,11 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; +import java.lang.reflect.Array; +import java.time.Instant; +import java.util.*; + public abstract class AbstractStructure { protected transient Object handle; protected transient StructureModifier structureModifier; @@ -410,7 +409,7 @@ public abstract class AbstractStructure { } /** - * Retrieves a read/write structure for collections of watchable objects. + * Retrieves a read/write structure for collections of watchable objects before Minecraft 1.19.3. *

* This modifier will automatically marshal between the visible WrappedWatchableObject and the * internal Minecraft WatchableObject. @@ -424,7 +423,7 @@ public abstract class AbstractStructure { } /** - * Retrieves a read/write structure for collections of data values. + * Retrieves a read/write structure for collections of data values for Minecraft 1.19.3 or later. * @return A modifier for data values. */ public StructureModifier> getDataValueCollectionModifier() { diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedDataValue.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedDataValue.java index f87c9010..a4421be2 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedDataValue.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedDataValue.java @@ -9,6 +9,7 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; /** * Represents a DataValue in 1.19.3+. + * Use {@link WrappedWatchableObject} before 1.19.3. */ public class WrappedDataValue extends AbstractWrapper { @@ -29,10 +30,28 @@ public class WrappedDataValue extends AbstractWrapper { this.modifier = new StructureModifier<>(this.handleType).withTarget(handle); } + /** + * Creates a new WrappedDataValue from a NMS value. + * ProtocolLib wrappers are not supported as arguments. + * If implicit unwrapping of wrappers is required, use {@link WrappedDataValue#fromWrappedValue(int, Serializer, Object)}. + * @param index the index of the metadata value + * @param serializer the serializer corresponding for serializing. Can be null. + * @param value The raw value for the DataValue. Can be null. + */ public WrappedDataValue(int index, Serializer serializer, Object value) { this(newHandle(index, serializer, value)); } + /** + * Creates a new WrappedDataValue from a possibly wrapped value and implicitly unwrap value if possible. + * @param index the index of the metadata value + * @param serializer the serializer corresponding for serializing. Can be null. + * @param value The value for the DataValue. Can be null. + */ + public static WrappedDataValue fromWrappedValue(int index, Serializer serializer, Object value) { + return new WrappedDataValue(index, serializer, value == null ? null : WrappedWatchableObject.getUnwrapped(value)); + } + private static Object newHandle(int index, Serializer serializer, Object value) { if (constructor == null) { constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]); @@ -41,14 +60,26 @@ public class WrappedDataValue extends AbstractWrapper { return constructor.invoke(index, serializer.getHandle(), value); } + /** + * Returns the entity-type specific index of this DataValue + * @return index of the DataValue + */ public int getIndex() { return this.modifier.withType(int.class).read(0); } + /** + * Sets the entity-type specific index of this DataValue + * @param index New index of the DataValue + */ public void setIndex(int index) { this.modifier.withType(int.class).write(0, index); } + /** + * Returns the current serializer for this DataValue. + * @return serializer + */ public Serializer getSerializer() { Object serializer = this.modifier.readSafely(1); if (serializer != null) { @@ -63,22 +94,42 @@ public class WrappedDataValue extends AbstractWrapper { } } + /** + * Changes the serializer for this DataValue + * @param serializer serializer + */ public void setSerializer(Serializer serializer) { this.modifier.writeSafely(1, serializer == null ? null : serializer.getHandle()); } + /** + * Returns the current value associated and implicitly wraps it to corresponding ProtocolLib wrappers if possible. + * @return Current value + */ public Object getValue() { return WrappedWatchableObject.getWrapped(getRawValue()); } + /** + * Sets the current value associated and implicitly unwraps it to NMS types if a ProtocolLib wrapper is provided. + * @param value New value for this DataValue + */ public void setValue(Object value) { setRawValue(WrappedWatchableObject.getUnwrapped(value)); } + /** + * Returns the current, raw value. + * @return Raw value (not wrapped) + */ public Object getRawValue() { return this.modifier.readSafely(2); } + /** + * Updates the raw value for this DataValue. No unwrapping will be applied. + * @param value NMS value + */ public void setRawValue(Object value) { this.modifier.writeSafely(2, value); } diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java index d4f66277..bc42bda3 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java @@ -14,8 +14,6 @@ */ package com.comphenix.protocol.wrappers; -import static com.comphenix.protocol.utility.MinecraftReflection.is; - import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; @@ -25,12 +23,15 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; -import java.util.Optional; import org.bukkit.inventory.ItemStack; +import java.util.Optional; + +import static com.comphenix.protocol.utility.MinecraftReflection.is; + /** - * Represents a DataWatcher Item in 1.8 to 1.10. - * + * Represents a DataWatcher Item in 1.8 to 1.19.2. + * Use {@link WrappedDataValue} for 1.19.3 or later. * @author dmulloy2 */ public class WrappedWatchableObject extends AbstractWrapper { @@ -97,6 +98,9 @@ public class WrappedWatchableObject extends AbstractWrapper { * @return The wrapped object. */ static Object getWrapped(Object value) { + if(value == null) { + return null; + } // Handle watcher items first if (is(MinecraftReflection.getDataWatcherItemClass(), value)) { return getWrapped(new WrappedWatchableObject(value).getRawValue()); @@ -135,6 +139,9 @@ public class WrappedWatchableObject extends AbstractWrapper { */ // Must be kept in sync with getWrapped! static Object getUnwrapped(Object wrapped) { + if(wrapped == null) { + return null; + } if (wrapped instanceof Optional) { return ((Optional) wrapped).map(WrappedWatchableObject::getUnwrapped); } From 1dbee3585ed2dd24e4caf1ca020a4d46747340fb Mon Sep 17 00:00:00 2001 From: Lukas Alt Date: Wed, 3 Jan 2024 18:53:03 +0100 Subject: [PATCH 2/5] Improve version checks and skip loading of ProtocolLib for unsupported versions by default --- .../com/comphenix/protocol/ProtocolLib.java | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java index 6909c160..d0ba7391 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -16,12 +16,7 @@ package com.comphenix.protocol; import com.comphenix.protocol.async.AsyncFilterManager; -import com.comphenix.protocol.error.BasicErrorReporter; -import com.comphenix.protocol.error.DelegatedErrorReporter; -import com.comphenix.protocol.error.DetailedErrorReporter; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; +import com.comphenix.protocol.error.*; import com.comphenix.protocol.injector.InternalManager; import com.comphenix.protocol.injector.PacketFilterManager; import com.comphenix.protocol.metrics.Statistics; @@ -31,14 +26,22 @@ import com.comphenix.protocol.scheduler.ProtocolScheduler; import com.comphenix.protocol.scheduler.Task; import com.comphenix.protocol.updater.Updater; import com.comphenix.protocol.updater.Updater.UpdateType; -import com.comphenix.protocol.utility.*; +import com.comphenix.protocol.utility.ByteBuddyFactory; +import com.comphenix.protocol.utility.ChatExtensions; +import com.comphenix.protocol.utility.MinecraftVersion; +import com.comphenix.protocol.utility.Util; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; +import org.bukkit.Server; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; import java.io.File; import java.io.IOException; import java.util.HashSet; -import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.logging.Handler; @@ -48,13 +51,6 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.bukkit.Server; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.PluginCommand; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - /** * The main entry point for ProtocolLib. * @@ -170,6 +166,10 @@ public class ProtocolLib extends JavaPlugin { // Handle unexpected Minecraft versions MinecraftVersion version = this.verifyMinecraftVersion(); + if(version == null) { + this.disablePlugin(); + return; + } // Set updater - this will not perform any update automatically this.updater = Updater.create(this, 0, this.getFile(), UpdateType.NO_DOWNLOAD, true); @@ -395,14 +395,29 @@ public class ProtocolLib extends JavaPlugin { try { MinecraftVersion current = new MinecraftVersion(this.getServer()); - // Skip certain versions - if (!config.getIgnoreVersionCheck().equals(current.getVersion())) { - // We'll just warn the user for now - if (current.compareTo(minimum) < 0) { - logger.warning("Version " + current + " is lower than the minimum " + minimum); + + String line = "============================================================"; + // We'll just warn the user for now + if (current.compareTo(minimum) < 0) { + logger.warning(line + "\nThis version of ProtocolLib has only been tested with Minecraft " + minimum.getVersion() + " or newer.\n" + line); + } + if (current.compareTo(maximum) > 0) { + boolean ignore = config.getIgnoreVersionCheck().equals(current.getVersion()); + Level level = ignore ? Level.WARNING : Level.SEVERE; + logger.log(level, line); + logger.log(level, ""); + logger.log(level, "This version of ProtocolLib (" + getDescription().getVersion() + ") has not been tested with Minecraft " + current + " and is likely not work as expected."); + if(ignore) { + logger.log(level, "As you configured ProtocolLib to ignore this, ProtocolLib will attempt to continue initialization. Proceed with caution!"); + } else { + logger.log(level, "ProtocolLib will be **DISABLED** now. If you want to ignore this error, set \"ignore version check: '" + current.getVersion() + "'\" in 'plugins/ProtocolLib/config.yml' and restart the server. Proceed with caution and expect errors!"); } - if (current.compareTo(maximum) > 0) { - logger.warning("Version " + current + " has not yet been tested! Proceed with caution."); + logger.log(level, "Check https://github.com/dmulloy2/ProtocolLib/releases for new releases of ProtocolLib and https://ci.dmulloy2.net/job/ProtocolLib/ for the latest development builds, which might support minecraft " + current.getVersion()); + logger.log(level, ""); + logger.log(level, line); + + if(!ignore) { + return null; } } From f4612cfd60a2da2d967cd5e1be7bf94c5daf285a Mon Sep 17 00:00:00 2001 From: Lukas Alt Date: Wed, 3 Jan 2024 19:01:08 +0100 Subject: [PATCH 3/5] add jvm vendor to protocol dump --- .../comphenix/protocol/CommandProtocol.java | 29 +++++++++---------- .../com/comphenix/protocol/ProtocolLib.java | 4 +-- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/comphenix/protocol/CommandProtocol.java b/src/main/java/com/comphenix/protocol/CommandProtocol.java index 2de1aaf3..70923283 100644 --- a/src/main/java/com/comphenix/protocol/CommandProtocol.java +++ b/src/main/java/com/comphenix/protocol/CommandProtocol.java @@ -16,6 +16,19 @@ */ package com.comphenix.protocol; +import com.comphenix.protocol.error.DetailedErrorReporter; +import com.comphenix.protocol.error.ErrorReporter; +import com.comphenix.protocol.events.PacketListener; +import com.comphenix.protocol.timing.TimedListenerManager; +import com.comphenix.protocol.timing.TimingReportGenerator; +import com.comphenix.protocol.updater.Updater; +import com.comphenix.protocol.updater.Updater.UpdateType; +import com.comphenix.protocol.utility.Closer; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -27,20 +40,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; - -import com.comphenix.protocol.error.DetailedErrorReporter; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.timing.TimedListenerManager; -import com.comphenix.protocol.timing.TimingReportGenerator; -import com.comphenix.protocol.updater.Updater; -import com.comphenix.protocol.updater.Updater.UpdateType; -import com.comphenix.protocol.utility.Closer; - /** * Handles the "protocol" administration command. * @@ -243,7 +242,7 @@ class CommandProtocol extends CommandBase { pw.println("ProtocolLib Version: " + plugin.toString()); pw.println("Bukkit Version: " + plugin.getServer().getBukkitVersion()); pw.println("Server Version: " + plugin.getServer().getVersion()); - pw.println("Java Version: " + System.getProperty("java.version")); + pw.println("Java Version: " + System.getProperty("java.version") + " - " + System.getProperty("java.vm.vendor", "N/A") + " (" + System.getProperty("java.vendor.version", "N/A") + ")"); pw.println(); ProtocolManager manager = ProtocolLibrary.getProtocolManager(); diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java index d0ba7391..c185b034 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -165,7 +165,7 @@ public class ProtocolLib extends JavaPlugin { this.checkConflictingVersions(); // Handle unexpected Minecraft versions - MinecraftVersion version = this.verifyMinecraftVersion(); + MinecraftVersion version = this.verifyMinecraftVersion(); // returns the current version or null if a version mismatch was detected if(version == null) { this.disablePlugin(); return; @@ -385,8 +385,6 @@ public class ProtocolLib extends JavaPlugin { } } - // Plugin authors: Notify me to remove these - // Used to check Minecraft version private MinecraftVersion verifyMinecraftVersion() { MinecraftVersion minimum = new MinecraftVersion(ProtocolLibrary.MINIMUM_MINECRAFT_VERSION); From bc5391c987ae0e06265752b9ea95acbc9b503e02 Mon Sep 17 00:00:00 2001 From: Lukas Alt Date: Wed, 3 Jan 2024 19:03:50 +0100 Subject: [PATCH 4/5] add operating system to protocol dump --- src/main/java/com/comphenix/protocol/CommandProtocol.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/comphenix/protocol/CommandProtocol.java b/src/main/java/com/comphenix/protocol/CommandProtocol.java index 70923283..f14745d1 100644 --- a/src/main/java/com/comphenix/protocol/CommandProtocol.java +++ b/src/main/java/com/comphenix/protocol/CommandProtocol.java @@ -242,7 +242,8 @@ class CommandProtocol extends CommandBase { pw.println("ProtocolLib Version: " + plugin.toString()); pw.println("Bukkit Version: " + plugin.getServer().getBukkitVersion()); pw.println("Server Version: " + plugin.getServer().getVersion()); - pw.println("Java Version: " + System.getProperty("java.version") + " - " + System.getProperty("java.vm.vendor", "N/A") + " (" + System.getProperty("java.vendor.version", "N/A") + ")"); + pw.println("Java Version: " + System.getProperty("java.version", "N/A") + " - " + System.getProperty("java.vm.vendor", "N/A") + " (" + System.getProperty("java.vendor.version", "N/A") + ")"); + pw.println("Operating System: " + System.getProperty("os.name", "N/A")); pw.println(); ProtocolManager manager = ProtocolLibrary.getProtocolManager(); From ebb3bea464c404b1fe2c635b8eebc7ac8e2c52ba Mon Sep 17 00:00:00 2001 From: Lukas Alt Date: Wed, 3 Jan 2024 19:51:18 +0100 Subject: [PATCH 5/5] improved load error handling --- .../java/com/comphenix/protocol/ProtocolLib.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java index c185b034..2302e6f5 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -114,6 +114,7 @@ public class ProtocolLib extends JavaPlugin { // Whether disabling field resetting is needed private boolean skipDisable; + private boolean loadingFailed = false; @Override public void onLoad() { @@ -167,7 +168,7 @@ public class ProtocolLib extends JavaPlugin { // Handle unexpected Minecraft versions MinecraftVersion version = this.verifyMinecraftVersion(); // returns the current version or null if a version mismatch was detected if(version == null) { - this.disablePlugin(); + loadingFailed = true; return; } @@ -192,7 +193,7 @@ public class ProtocolLib extends JavaPlugin { } catch (Exception e) { reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager)); - this.disablePlugin(); + loadingFailed = true; } } @@ -311,6 +312,11 @@ public class ProtocolLib extends JavaPlugin { @Override public void onEnable() { + if(loadingFailed) { + this.getLogger().log(Level.SEVERE, "Loading of ProtocolLib failed (see log above). ProtocolLib will be disabled."); + this.disablePlugin(); + return; + } try { Server server = this.getServer(); PluginManager manager = server.getPluginManager(); @@ -404,7 +410,7 @@ public class ProtocolLib extends JavaPlugin { Level level = ignore ? Level.WARNING : Level.SEVERE; logger.log(level, line); logger.log(level, ""); - logger.log(level, "This version of ProtocolLib (" + getDescription().getVersion() + ") has not been tested with Minecraft " + current + " and is likely not work as expected."); + logger.log(level, "This version of ProtocolLib (" + getDescription().getVersion() + ") has not been tested with Minecraft " + current.getVersion() + " and is likely not work as expected."); if(ignore) { logger.log(level, "As you configured ProtocolLib to ignore this, ProtocolLib will attempt to continue initialization. Proceed with caution!"); } else {