From 018ef2a8fa949009d3fa57a4019eff66b1ee6200 Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 17 Feb 2026 10:31:56 -0700 Subject: [PATCH] Fix logging, add config, fix UnsafeValues --- java/patchbukkit/build.gradle.kts | 1 + .../org/patchbukkit/PatchBukkitLegacy.java | 30 + .../org/patchbukkit/PatchBukkitServer.java | 4 +- .../patchbukkit/PatchBukkitUnsafeValues.java | 595 +++++++++--------- .../command/PatchBukkitCommandSender.java | 15 +- .../PatchBukkitLifecycleEventManager.java | 44 ++ .../patchbukkit/versioning/ApiVersion.java | 130 ++++ .../{ => versioning}/Versioning.java | 2 +- proto/patchbukkit/bridge.proto | 3 + proto/patchbukkit/common/types.proto | 2 + proto/patchbukkit/config.proto | 12 + proto/patchbukkit/itemstack.proto | 17 + rust/Cargo.lock | 141 +++-- rust/Cargo.toml | 3 + rust/src/config/mod.rs | 1 + rust/src/config/patchbukkit.rs | 37 ++ rust/src/java/jvm/commands.rs | 5 +- rust/src/java/jvm/worker.rs | 2 + rust/src/java/native_callbacks/config.rs | 21 + rust/src/java/native_callbacks/itemstack.rs | 5 + rust/src/java/native_callbacks/mod.rs | 14 +- rust/src/java/resources.rs | 1 + rust/src/lib.rs | 19 +- rust/src/proto/mod.rs | 8 + 24 files changed, 748 insertions(+), 364 deletions(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitLifecycleEventManager.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/versioning/ApiVersion.java rename java/patchbukkit/src/main/java/org/patchbukkit/{ => versioning}/Versioning.java (97%) create mode 100644 proto/patchbukkit/config.proto create mode 100644 proto/patchbukkit/itemstack.proto create mode 100644 rust/src/config/patchbukkit.rs create mode 100644 rust/src/java/native_callbacks/config.rs create mode 100644 rust/src/java/native_callbacks/itemstack.rs diff --git a/java/patchbukkit/build.gradle.kts b/java/patchbukkit/build.gradle.kts index 45e306c..901b1df 100644 --- a/java/patchbukkit/build.gradle.kts +++ b/java/patchbukkit/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { implementation("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") implementation("org.apache.maven.resolver:maven-resolver-util:1.9.18") implementation("com.google.protobuf:protobuf-java:$protobufVersion") + implementation("org.slf4j:slf4j-jdk14:2.0.16") } java { diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java new file mode 100644 index 0000000..3e0b0f2 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java @@ -0,0 +1,30 @@ +package org.patchbukkit; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +@SuppressWarnings({ "deprecation", "removal" }) +public final class PatchBukkitLegacy { + private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(PatchBukkitLegacy.class); + + public static Material fromLegacy(Material material) { + if (material == null || !material.isLegacy()) { + return material; + } + + return PatchBukkitLegacy.fromLegacy(new MaterialData(material)); + } + + public static Material fromLegacy(MaterialData materialData) { + return PatchBukkitLegacy.fromLegacy(materialData, false); + } + + public static Material fromLegacy(MaterialData materialData, boolean itemPriority) { + Material material = materialData.getItemType(); + if (material == null || !material.isLegacy()) { + return material; + } + + throw new UnsupportedOperationException("Cannot convert from legacy to new Material"); + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java index ab631d2..8f7ab86 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java @@ -90,6 +90,8 @@ import org.patchbukkit.command.PatchBukkitCommandMap; import org.patchbukkit.command.PatchBukkitConsoleCommandSender; import org.patchbukkit.events.PatchBukkitEventManager; import org.patchbukkit.scheduler.PatchBukkitScheduler; +import org.patchbukkit.versioning.Versioning; + import patchbukkit.bridge.NativeBridgeFfi; import patchbukkit.log.LogLevel; import patchbukkit.log.SendLogRequest; @@ -114,7 +116,7 @@ public class PatchBukkitServer implements Server { configureRootLogger(); } - private static final Map LEVEL_MAP = Map.of( + public static final Map LEVEL_MAP = Map.of( Level.SEVERE, LogLevel.SEVERE, Level.WARNING, LogLevel.WARNING, Level.INFO, LogLevel.INFO, diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitUnsafeValues.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitUnsafeValues.java index 26edbc3..53a254c 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitUnsafeValues.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitUnsafeValues.java @@ -12,11 +12,14 @@ import java.util.Map; import java.util.function.BooleanSupplier; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.event.HoverEvent.ShowItem; import net.kyori.adventure.text.flattener.ComponentFlattener; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import patchbukkit.bridge.NativeBridgeFfi; + import org.bukkit.*; import org.bukkit.advancement.Advancement; import org.bukkit.attribute.Attributable; @@ -25,6 +28,7 @@ import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.BlockData; import org.bukkit.command.CommandSender; import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageSource.Builder; import org.bukkit.damage.DamageType; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -38,9 +42,14 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.potion.PotionType; +import org.bukkit.potion.PotionType.InternalPotionData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; +import org.patchbukkit.events.PatchBukkitLifecycleEventManager; +import org.patchbukkit.versioning.ApiVersion; +import org.patchbukkit.versioning.Versioning; +import patchbukkit.common.EmptyRequest; @SuppressWarnings("removal") public class PatchBukkitUnsafeValues implements UnsafeValues { @@ -48,342 +57,334 @@ public class PatchBukkitUnsafeValues implements UnsafeValues { public static final PatchBukkitUnsafeValues INSTANCE = new PatchBukkitUnsafeValues(); - // These are commonly used - implement first - @Override - public int getDataVersion() { - return 4189; // 1.21.4 data version - match your server - } - - @Override - public ItemStack modifyItemStack(ItemStack stack, String arguments) { - return null; - } - @Override public boolean isSupportedApiVersion(String apiVersion) { - // Accept common API versions - return ( - apiVersion != null && - (apiVersion.equals("1.21") || apiVersion.equals("1.20")) - ); - } + if (apiVersion == null) return false; + final ApiVersion toCheck = ApiVersion.getOrCreateVersion(apiVersion); + var minimumApi = NativeBridgeFfi.getPatchBukkitConfig(EmptyRequest.newBuilder().build()).getMinimumSupportedPluginApi(); + final ApiVersion minimumVersion = ApiVersion.getOrCreateVersion(minimumApi); - @Override - public byte[] serializeItem(ItemStack item) { - return new byte[0]; - } - - @Override - public ItemStack deserializeItem(byte[] data) { - return null; - } - - @Override - public @NotNull JsonObject serializeItemAsJson( - @NotNull ItemStack itemStack - ) { - return null; - } - - @Override - public @NotNull ItemStack deserializeItemFromJson(@NotNull JsonObject data) - throws IllegalArgumentException { - return null; - } - - @Override - public byte@NotNull [] serializeEntity( - @NotNull Entity entity, - @NonNull @NotNull EntitySerializationFlag... serializationFlags - ) { - return new byte[0]; - } - - @Override - public @NotNull Entity deserializeEntity( - byte@NotNull [] data, - @NotNull World world, - boolean preserveUUID, - boolean preservePassengers - ) { - return null; - } - - @Override - public int nextEntityId() { - return 0; - } - - @Override - public @NotNull String getMainLevelName() { - return ""; - } - - @Override - public int getProtocolVersion() { - return 0; - } - - @Override - public boolean isValidRepairItemStack( - @NotNull ItemStack itemToBeRepaired, - @NotNull ItemStack repairMaterial - ) { - return false; - } - - @Override - public boolean hasDefaultEntityAttributes( - @NotNull NamespacedKey entityKey - ) { - return false; - } - - @Override - public @NotNull Attributable getDefaultEntityAttributes( - @NotNull NamespacedKey entityKey - ) { - return null; - } - - @Override - public @NotNull NamespacedKey getBiomeKey( - RegionAccessor accessor, - int x, - int y, - int z - ) { - return null; - } - - @Override - public void setBiomeKey( - RegionAccessor accessor, - int x, - int y, - int z, - NamespacedKey biomeKey - ) {} - - @Override - public String getStatisticCriteriaKey(@NotNull Statistic statistic) { - return ""; - } - - @Override - public @Nullable Color getSpawnEggLayerColor( - EntityType entityType, - int layer - ) { - return null; - } - - @Override - public LifecycleEventManager createPluginLifecycleEventManager( - JavaPlugin plugin, - BooleanSupplier registrationCheck - ) { - return null; - } - - @Override - public @NotNull List computeTooltipLines( - @NotNull ItemStack itemStack, - @NotNull TooltipContext tooltipContext, - @Nullable Player player - ) { - return List.of(); - } - - @Override - public ItemStack createEmptyStack() { - return null; - } - - @Override - public @NotNull Map serializeStack(ItemStack itemStack) { - return Map.of(); - } - - @Override - public @NotNull ItemStack deserializeStack( - @NotNull Map args - ) { - return null; - } - - @Override - public @NotNull ItemStack deserializeItemHover( - HoverEvent.@NotNull ShowItem itemHover - ) { - return null; + return !toCheck.isNewerThan(ApiVersion.CURRENT) && !toCheck.isOlderThan(minimumVersion); } @Override public void checkSupported(PluginDescriptionFile pdf) throws InvalidPluginException { - // Be lenient during development - accept most plugins String api = pdf.getAPIVersion(); if (api != null && !isSupportedApiVersion(api)) { throw new InvalidPluginException("Unsupported API: " + api); } } - @Override - public byte[] processClass( - PluginDescriptionFile pdf, - String path, - byte[] clazz - ) { - // Return unchanged - skip Commodore remapping for now - return clazz; - } + @Override + public ComponentFlattener componentFlattener() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'componentFlattener'"); + } - @Override - public Advancement loadAdvancement(NamespacedKey key, String advancement) { - return null; - } + @Override + public PlainComponentSerializer plainComponentSerializer() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'plainComponentSerializer'"); + } - @Override - public boolean removeAdvancement(NamespacedKey key) { - return false; - } + @Override + public PlainTextComponentSerializer plainTextSerializer() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'plainTextSerializer'"); + } - @Override - public Multimap getDefaultAttributeModifiers( - Material material, - EquipmentSlot slot - ) { - return null; - } + @Override + public GsonComponentSerializer gsonComponentSerializer() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'gsonComponentSerializer'"); + } - @Override - public CreativeCategory getCreativeCategory(Material material) { - return null; - } + @Override + public GsonComponentSerializer colorDownsamplingGsonComponentSerializer() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'colorDownsamplingGsonComponentSerializer'"); + } - @Override - public String getBlockTranslationKey(Material material) { - return ""; - } + @Override + public LegacyComponentSerializer legacyComponentSerializer() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'legacyComponentSerializer'"); + } - @Override - public String getItemTranslationKey(Material material) { - return ""; - } + @Override + public Component resolveWithContext(Component component, CommandSender context, Entity scoreboardSubject, + boolean bypassPermissions) throws IOException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'resolveWithContext'"); + } - @Override - public String getTranslationKey(EntityType entityType) { - return ""; - } + @Override + public Material toLegacy(Material material) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'toLegacy'"); + } - @Override - public String getTranslationKey(ItemStack itemStack) { - return ""; - } + @Override + public Material fromLegacy(Material material) { + return PatchBukkitLegacy.fromLegacy(material); + } - @Override - public String getTranslationKey(Attribute attribute) { - return ""; - } + @Override + public Material fromLegacy(MaterialData material) { + return PatchBukkitLegacy.fromLegacy(material); + } - @Override - public PotionType.InternalPotionData getInternalPotionData( - NamespacedKey key - ) { - return null; - } + @Override + public Material fromLegacy(MaterialData material, boolean itemPriority) { + return PatchBukkitLegacy.fromLegacy(material, itemPriority); + } - @Override - public DamageSource.@NotNull Builder createDamageSourceBuilder( - @NotNull DamageType damageType - ) { - return null; - } + @Override + public BlockData fromLegacy(Material material, byte data) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'fromLegacy'"); + } - @Override - public String get(Class aClass, String value) { - return ""; - } + @Override + public Material getMaterial(String material, int version) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getMaterial'"); + } - @Override - public B get(RegistryKey registry, NamespacedKey key) { - return null; - } + @Override + public int getDataVersion() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getDataVersion'"); + } - // Adventure components - commonly used - @Override - public ComponentFlattener componentFlattener() { - return ComponentFlattener.basic(); - } + @Override + public ItemStack modifyItemStack(ItemStack stack, String arguments) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'modifyItemStack'"); + } - @Override - public PlainComponentSerializer plainComponentSerializer() { - return null; - } + @Override + public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'processClass'"); + } - @Override - public PlainTextComponentSerializer plainTextSerializer() { - return null; - } + @Override + public Advancement loadAdvancement(NamespacedKey key, String advancement) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'loadAdvancement'"); + } - @Override - public GsonComponentSerializer gsonComponentSerializer() { - return null; - } + @Override + public boolean removeAdvancement(NamespacedKey key) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'removeAdvancement'"); + } - @Override - public GsonComponentSerializer colorDownsamplingGsonComponentSerializer() { - return null; - } + @Override + public Multimap getDefaultAttributeModifiers(Material material, EquipmentSlot slot) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getDefaultAttributeModifiers'"); + } - @Override - public LegacyComponentSerializer legacyComponentSerializer() { - return null; - } + @Override + public CreativeCategory getCreativeCategory(Material material) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getCreativeCategory'"); + } - @Override - public Component resolveWithContext( - Component component, - CommandSender context, - Entity scoreboardSubject, - boolean bypassPermissions - ) throws IOException { - return null; - } + @Override + public String getBlockTranslationKey(Material material) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getBlockTranslationKey'"); + } - // Stub everything else - @Override - public Material toLegacy(Material material) { - throw new UnsupportedOperationException( - "Pumpkin doesn't support legacy materials" - ); - } + @Override + public String getItemTranslationKey(Material material) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getItemTranslationKey'"); + } - @Override - public Material fromLegacy(Material material) { - return null; - } + @Override + public String getTranslationKey(EntityType entityType) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getTranslationKey'"); + } - @Override - public Material fromLegacy(MaterialData material) { - return null; - } + @Override + public String getTranslationKey(ItemStack itemStack) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getTranslationKey'"); + } - @Override - public Material fromLegacy(MaterialData material, boolean itemPriority) { - return null; - } + @Override + public String getTranslationKey(Attribute attribute) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getTranslationKey'"); + } - @Override - public BlockData fromLegacy(Material material, byte data) { - return null; - } + @Override + public InternalPotionData getInternalPotionData(NamespacedKey key) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getInternalPotionData'"); + } - @Override - public Material getMaterial(String material, int version) { - return null; - } + @Override + public @NotNull Builder createDamageSourceBuilder(@NotNull DamageType damageType) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'createDamageSourceBuilder'"); + } - // ... etc + @Override + public String get(Class aClass, String value) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'get'"); + } + + @Override + public B get(RegistryKey registry, NamespacedKey key) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'get'"); + } + + @Override + public byte[] serializeItem(ItemStack item) { + System.out.println("Serializing item: " + item); + System.out.println(item.getType().getKey().getKey()); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'serializeItem'"); + } + + @Override + public ItemStack deserializeItem(byte[] data) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deserializeItem'"); + } + + @Override + public @NotNull JsonObject serializeItemAsJson(@NotNull ItemStack itemStack) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'serializeItemAsJson'"); + } + + @Override + public @NotNull ItemStack deserializeItemFromJson(@NotNull JsonObject data) throws IllegalArgumentException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deserializeItemFromJson'"); + } + + @Override + public byte @NotNull [] serializeEntity(@NotNull Entity entity, + @NotNull EntitySerializationFlag... serializationFlags) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'serializeEntity'"); + } + + @Override + public @NotNull Entity deserializeEntity(byte @NotNull [] data, @NotNull World world, boolean preserveUUID, + boolean preservePassengers) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deserializeEntity'"); + } + + @Override + public int nextEntityId() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'nextEntityId'"); + } + + @Override + public @NotNull String getMainLevelName() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getMainLevelName'"); + } + + @Override + public int getProtocolVersion() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getProtocolVersion'"); + } + + @Override + public boolean isValidRepairItemStack(@NotNull ItemStack itemToBeRepaired, @NotNull ItemStack repairMaterial) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'isValidRepairItemStack'"); + } + + @Override + public boolean hasDefaultEntityAttributes(@NotNull NamespacedKey entityKey) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'hasDefaultEntityAttributes'"); + } + + @Override + public @NotNull Attributable getDefaultEntityAttributes(@NotNull NamespacedKey entityKey) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getDefaultEntityAttributes'"); + } + + @Override + public @NotNull NamespacedKey getBiomeKey(RegionAccessor accessor, int x, int y, int z) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getBiomeKey'"); + } + + @Override + public void setBiomeKey(RegionAccessor accessor, int x, int y, int z, NamespacedKey biomeKey) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setBiomeKey'"); + } + + @Override + public String getStatisticCriteriaKey(@NotNull Statistic statistic) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getStatisticCriteriaKey'"); + } + + @Override + public @Nullable Color getSpawnEggLayerColor(EntityType entityType, int layer) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getSpawnEggLayerColor'"); + } + + @Override + public LifecycleEventManager createPluginLifecycleEventManager(JavaPlugin plugin, + BooleanSupplier registrationCheck) { + return new PatchBukkitLifecycleEventManager(plugin, registrationCheck); + } + + @Override + public @NotNull List computeTooltipLines(@NotNull ItemStack itemStack, + @NotNull TooltipContext tooltipContext, @Nullable Player player) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'computeTooltipLines'"); + } + + @Override + public ItemStack createEmptyStack() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'createEmptyStack'"); + } + + @Override + public @NotNull Map serializeStack(ItemStack itemStack) { + System.out.println("Serializing itemstack: " + itemStack); + System.out.println(itemStack.getType().getKey().getKey()); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'serializeStack'"); + } + + @Override + public @NotNull ItemStack deserializeStack(@NotNull Map args) { + System.out.println("Deserializing itemstack: " + args); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deserializeStack'"); + } + + @Override + public @NotNull ItemStack deserializeItemHover(@NotNull ShowItem itemHover) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deserializeItemHover'"); + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/command/PatchBukkitCommandSender.java b/java/patchbukkit/src/main/java/org/patchbukkit/command/PatchBukkitCommandSender.java index 7d5cd6a..98603c5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/command/PatchBukkitCommandSender.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/command/PatchBukkitCommandSender.java @@ -4,6 +4,7 @@ import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.permissions.PermissibleBase; @@ -18,6 +19,11 @@ import org.jetbrains.annotations.Nullable; import net.kyori.adventure.text.Component; import net.md_5.bungee.api.chat.BaseComponent; +import patchbukkit.bridge.NativeBridgeFfi; +import patchbukkit.log.LogLevel; +import patchbukkit.log.SendLogRequest; +import org.patchbukkit.PatchBukkitServer; + public class PatchBukkitCommandSender implements CommandSender, ServerOperator { private final Server server; @@ -133,7 +139,14 @@ public class PatchBukkitCommandSender implements CommandSender, ServerOperator { if (this.server != null && this.server.getLogger() != null) { this.server.getLogger().info(message); } else { - System.out.println(message); + LogLevel logLevel = LogLevel.INFO; + NativeBridgeFfi.sendLog( + SendLogRequest.newBuilder() + .setLevel(logLevel) + .setMessage(ChatColor.stripColor(message)) + .setLoggerName("console") + .build() + ); } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitLifecycleEventManager.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitLifecycleEventManager.java new file mode 100644 index 0000000..e887dd3 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitLifecycleEventManager.java @@ -0,0 +1,44 @@ +package org.patchbukkit.events; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; +import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; + +public class PatchBukkitLifecycleEventManager implements LifecycleEventManager { + + private final Plugin plugin; + private final BooleanSupplier registrationCheck; + private final List> handlers = new ArrayList<>(); + + public PatchBukkitLifecycleEventManager(Plugin plugin, BooleanSupplier registrationCheck) { + this.plugin = plugin; + this.registrationCheck = registrationCheck; + } + + @Override + public void registerEventHandler( + @NotNull LifecycleEventHandlerConfiguration handlerConfiguration) { + if (!registrationCheck.getAsBoolean()) { + throw new IllegalStateException( + "Cannot register lifecycle event handler for " + plugin.getName() + + " — registration is not allowed at this time"); + } + } + + public Plugin getPlugin() { + return plugin; + } + + private record RegisteredHandler( + LifecycleEventType type, + LifecycleEventHandler handler + ) {} +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/versioning/ApiVersion.java b/java/patchbukkit/src/main/java/org/patchbukkit/versioning/ApiVersion.java new file mode 100644 index 0000000..85ce5a4 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/versioning/ApiVersion.java @@ -0,0 +1,130 @@ +package org.patchbukkit.versioning; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import org.jetbrains.annotations.NotNull; + +public final class ApiVersion implements Comparable, Serializable { + + public static final ApiVersion CURRENT; + public static final ApiVersion FLATTENING; + public static final ApiVersion FIELD_NAME_PARITY; + public static final ApiVersion ABSTRACT_COW; + public static final ApiVersion NONE; + + private static final Map versions; + + static { + versions = new HashMap<>(); + CURRENT = getOrCreateVersion(Versioning.getCurrentApiVersion()); + FLATTENING = getOrCreateVersion("1.13"); + FIELD_NAME_PARITY = getOrCreateVersion("1.20.5"); + ABSTRACT_COW = getOrCreateVersion("1.21.5"); + NONE = getOrCreateVersion("none"); + } + + private final boolean none; + private final int major; + private final int minor; + private final int patch; + + private ApiVersion() { + this.none = true; + this.major = Integer.MIN_VALUE; + this.minor = Integer.MIN_VALUE; + this.patch = Integer.MIN_VALUE; + } + + private ApiVersion(int major, int minor, int patch) { + this.none = false; + this.major = major; + this.minor = minor; + this.patch = patch; + } + + public static ApiVersion getOrCreateVersion(String versionString) { + if (versionString == null || versionString.trim().isEmpty() || versionString.equalsIgnoreCase("none")) { + return ApiVersion.versions.computeIfAbsent("none", s -> new ApiVersion()); + } + + ApiVersion version = ApiVersion.versions.get(versionString); + + if (version != null) { + return version; + } + + String[] versionParts = versionString.split("\\."); + + if (versionParts.length != 2 && versionParts.length != 3) { + throw new IllegalArgumentException(String.format("API version string should be of format \"major.minor.patch\" or \"major.minor\", where \"major\", \"minor\" and \"patch\" are numbers. For example \"1.18.2\" or \"1.13\", but got '%s' instead.", versionString)); + } + + int major = ApiVersion.parseNumber(versionParts[0]); + int minor = ApiVersion.parseNumber(versionParts[1]); + + int patch; + if (versionParts.length == 3) { + patch = ApiVersion.parseNumber(versionParts[2]); + } else { + patch = 0; + } + + versionString = ApiVersion.toVersionString(major, minor, patch); + return ApiVersion.versions.computeIfAbsent(versionString, s -> new ApiVersion(major, minor, patch)); + } + + private static int parseNumber(String number) { + return Integer.parseInt(number); + } + + private static String toVersionString(int major, int minor, int patch) { + return major + "." + minor + "." + patch; + } + + @Override + public int compareTo(@NotNull ApiVersion other) { + int result = Integer.compare(this.major, other.major); + + if (result == 0) { + result = Integer.compare(this.minor, other.minor); + } + + if (result == 0) { + result = Integer.compare(this.patch, other.patch); + } + + return result; + } + + public String getVersionString() { + if (this.none) { + return "none"; + } + + return ApiVersion.toVersionString(this.major, this.minor, this.patch); + } + + public boolean isNewerThan(ApiVersion apiVersion) { + return this.compareTo(apiVersion) > 0; + } + + public boolean isOlderThan(ApiVersion apiVersion) { + return this.compareTo(apiVersion) < 0; + } + + public boolean isNewerThanOrSameAs(ApiVersion apiVersion) { + return this.compareTo(apiVersion) >= 0; + } + + public boolean isOlderThanOrSameAs(ApiVersion apiVersion) { + return this.compareTo(apiVersion) <= 0; + } + + @Override + public String toString() { + return this.getVersionString(); + } + + private static final long serialVersionUID = 0L; +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/Versioning.java b/java/patchbukkit/src/main/java/org/patchbukkit/versioning/Versioning.java similarity index 97% rename from java/patchbukkit/src/main/java/org/patchbukkit/Versioning.java rename to java/patchbukkit/src/main/java/org/patchbukkit/versioning/Versioning.java index 2c54046..2d48b6c 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/Versioning.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/versioning/Versioning.java @@ -1,4 +1,4 @@ -package org.patchbukkit; +package org.patchbukkit.versioning; import java.io.BufferedReader; import java.io.IOException; diff --git a/proto/patchbukkit/bridge.proto b/proto/patchbukkit/bridge.proto index 09a774c..85df0ae 100644 --- a/proto/patchbukkit/bridge.proto +++ b/proto/patchbukkit/bridge.proto @@ -5,6 +5,7 @@ import "google/protobuf/empty.proto"; import "google/protobuf/wrappers.proto"; import "patchbukkit/abilities.proto"; import "patchbukkit/common/types.proto"; +import "patchbukkit/config.proto"; import "patchbukkit/events/event.proto"; import "patchbukkit/log.proto"; import "patchbukkit/message.proto"; @@ -28,4 +29,6 @@ service NativeBridge { rpc PlayerPlaySound(patchbukkit.sound.PlayerPlaySoundRequest) returns (google.protobuf.Empty); rpc SendLog(patchbukkit.log.SendLogRequest) returns (google.protobuf.Empty); + + rpc GetPatchBukkitConfig(patchbukkit.common.EmptyRequest) returns (patchbukkit.config.GetPatchBukkitConfigResponse); } diff --git a/proto/patchbukkit/common/types.proto b/proto/patchbukkit/common/types.proto index 03d7341..52ab136 100644 --- a/proto/patchbukkit/common/types.proto +++ b/proto/patchbukkit/common/types.proto @@ -25,3 +25,5 @@ message Location { float yaw = 3; float pitch = 4; } + +message EmptyRequest {} diff --git a/proto/patchbukkit/config.proto b/proto/patchbukkit/config.proto new file mode 100644 index 0000000..12c48c0 --- /dev/null +++ b/proto/patchbukkit/config.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package patchbukkit.config; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.config"; + +message GetPatchBukkitConfigResponse { + string minimum_supported_plugin_api = 1; +} diff --git a/proto/patchbukkit/itemstack.proto b/proto/patchbukkit/itemstack.proto new file mode 100644 index 0000000..6e9670a --- /dev/null +++ b/proto/patchbukkit/itemstack.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package patchbukkit.itemstack; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.itemstack"; + +// message GetPatchBukkitConfigResponse { +// string minimum_supported_plugin_api = 1; +// } + +message ItemStack { + string type = 1; + uint32 amount = 2; +} diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 6fe3265..abb3802 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -400,9 +400,9 @@ checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "constant_time_eq" -version = "0.4.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "cookie" @@ -1132,18 +1132,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "74f70a332ddf75e5e5e43284304179ba02f391f82f692f030b08a8378adf3c99" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi", "rand_core 0.10.0", "wasip2", "wasip3", - "wasm-bindgen", ] [[package]] @@ -1905,12 +1903,14 @@ dependencies = [ "pumpkin-data", "pumpkin-protocol", "pumpkin-util", + "pumpkin-world", "rand", "rust-embed", "serde", "serde-saphyr", "serde_json", "tokio", + "toml 1.0.2+spec-1.1.0", "tracing", "uuid", "walkdir", @@ -2193,7 +2193,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "arc-swap", "base64", @@ -2203,7 +2203,6 @@ dependencies = [ "futures", "hmac 0.13.0-rc.5", "libloading 0.9.0", - "log", "num-bigint", "pkcs8 0.11.0-rc.10", "pumpkin-config", @@ -2235,7 +2234,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2246,19 +2245,19 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ - "log", "pumpkin-util", "serde", - "toml", + "toml 0.9.11+spec-1.1.0", + "tracing", "uuid", ] [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "crc-fast", "phf", @@ -2270,22 +2269,22 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "crossbeam-utils", - "log", "pumpkin-data", "pumpkin-protocol", "pumpkin-util", "pumpkin-world", "thiserror", "tokio", + "tracing", ] [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2296,7 +2295,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "bytes", "cesu8", @@ -2308,13 +2307,14 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "aes", "async-compression", "bitflags", "bytes", "cfb8", + "flate2", "pumpkin-data", "pumpkin-macros", "pumpkin-nbt", @@ -2330,7 +2330,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "base64", "bytes", @@ -2355,7 +2355,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#e438e09991619d105c9835570b09c1b4624eedc5" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" dependencies = [ "bitflags", "bytes", @@ -2366,7 +2366,6 @@ dependencies = [ "flate2", "futures", "itertools", - "log", "lz4-java-wrc", "num_cpus", "pumpkin-config", @@ -2383,6 +2382,7 @@ dependencies = [ "thiserror", "tokio", "tokio-util", + "tracing", "uuid", ] @@ -2417,7 +2417,7 @@ version = "0.10.0-rc.9" source = "git+https://github.com/rust-random/rand#72afe1e973fcd83d840cf597888223072bbdb04c" dependencies = [ "chacha20", - "getrandom 0.4.1", + "getrandom 0.4.0-rc.1", "rand_core 0.10.0", ] @@ -3124,9 +3124,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -3146,9 +3146,9 @@ checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -3214,7 +3214,22 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml" +version = "1.0.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1dfefef6a142e93f346b64c160934eb13b5594b84ab378133ac6815cb2bd57f" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime 1.0.0+spec-1.1.0", "toml_parser", "toml_writer", "winnow", @@ -3230,10 +3245,19 @@ dependencies = [ ] [[package]] -name = "toml_parser" -version = "1.0.6+spec-1.1.0" +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] @@ -3524,16 +3548,16 @@ version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "0.3.1+wasi-0.3.0-rc-2025-09-16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "87ba4be47b1d11244670d11857eee0758a8f2c39aea64d80b78c1ce29b4642cd" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.48.1", ] [[package]] @@ -3583,9 +3607,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.244.0" +version = "0.241.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8" dependencies = [ "leb128fmt", "wasmparser", @@ -3593,9 +3617,9 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.244.0" +version = "0.241.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167" dependencies = [ "anyhow", "indexmap", @@ -3605,9 +3629,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.244.0" +version = "0.241.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8" dependencies = [ "bitflags", "hashbrown 0.15.5", @@ -3834,18 +3858,24 @@ checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "7f8c2adb5f74ac9395bc3121c99a1254bf9310482c27b13f97167aedb5887138" dependencies = [ "wit-bindgen-rust-macro", ] [[package]] -name = "wit-bindgen-core" +name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "wit-bindgen-core" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b881a098cae03686d7a0587f8f306f8a58102ad8da8b5599100fbe0e7f5800b" dependencies = [ "anyhow", "heck", @@ -3854,9 +3884,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" -version = "0.51.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +checksum = "69667efa439a453e1d50dac939c6cab6d2c3ac724a9d232b6631dad2472a5b70" dependencies = [ "anyhow", "heck", @@ -3870,9 +3900,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" -version = "0.51.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +checksum = "eae2e22cceb5d105d52326c07e3e67603a861cc7add70fc467f7cc7ec5265017" dependencies = [ "anyhow", "prettyplease", @@ -3885,9 +3915,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.244.0" +version = "0.241.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241" dependencies = [ "anyhow", "bitflags", @@ -3904,9 +3934,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.244.0" +version = "0.241.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91" dependencies = [ "anyhow", "id-arena", @@ -4045,9 +4075,9 @@ dependencies = [ [[package]] name = "zip" -version = "7.4.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc12baa6db2b15a140161ce53d72209dacea594230798c24774139b54ecaa980" +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0" dependencies = [ "aes", "bzip2", @@ -4055,7 +4085,8 @@ dependencies = [ "crc32fast", "deflate64", "flate2", - "getrandom 0.4.1", + "generic-array", + "getrandom 0.3.4", "hmac 0.12.1", "indexmap", "lzma-rust2", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index a376882..5da1da6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,6 +14,7 @@ pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "ma pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } +pumpkin-world = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-world" } tokio = "1" tracing = "0.1" @@ -33,6 +34,8 @@ serde-saphyr = "0.0.17" rand = { git = "https://github.com/rust-random/rand"} prost = "0.14" +toml = "1.0" + [build-dependencies] j4rs = { version = "0.24", artifact = "cdylib", lib = true } env_logger = "0.11.8" diff --git a/rust/src/config/mod.rs b/rust/src/config/mod.rs index a33bd6f..ca0beb1 100644 --- a/rust/src/config/mod.rs +++ b/rust/src/config/mod.rs @@ -1,2 +1,3 @@ pub mod paper; +pub mod patchbukkit; pub mod spigot; diff --git a/rust/src/config/patchbukkit.rs b/rust/src/config/patchbukkit.rs new file mode 100644 index 0000000..1434aee --- /dev/null +++ b/rust/src/config/patchbukkit.rs @@ -0,0 +1,37 @@ +use std::{fs, path::Path}; + +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct PatchBukkitConfig { + pub settings: SettingsConfig, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "kebab-case")] +pub struct SettingsConfig { + pub minimum_supported_plugin_api: Option, +} + +impl PatchBukkitConfig { + pub const DEFAULT: PatchBukkitConfig = PatchBukkitConfig { + settings: SettingsConfig { + minimum_supported_plugin_api: None, + }, + }; + + pub fn parse>(config: S) -> Result { + toml::from_str(config.as_ref()) + } + + pub fn get_or_create>(config_path: P) -> anyhow::Result { + let config_path = config_path.as_ref(); + if !config_path.exists() { + let default = PatchBukkitConfig::DEFAULT; + std::fs::write(config_path, &toml::to_string_pretty(&default)?)?; + return Ok(default); + } + let config = PatchBukkitConfig::parse(fs::read_to_string(config_path)?)?; + Ok(config) + } +} diff --git a/rust/src/java/jvm/commands.rs b/rust/src/java/jvm/commands.rs index a8301f6..3fdf763 100644 --- a/rust/src/java/jvm/commands.rs +++ b/rust/src/java/jvm/commands.rs @@ -7,8 +7,8 @@ use tokio::sync::{mpsc, oneshot}; use uuid::Uuid; use crate::{ - commands::SimpleCommandSender, events::handler::JvmEventPayload, - proto::patchbukkit::events::FireEventResponse, + commands::SimpleCommandSender, config::patchbukkit::PatchBukkitConfig, + events::handler::JvmEventPayload, proto::patchbukkit::events::FireEventResponse, }; pub enum LoadPluginResult { @@ -26,6 +26,7 @@ pub enum JvmCommand { respond_to: oneshot::Sender>, context: Arc, command_tx: mpsc::Sender, + config: PatchBukkitConfig, }, LoadPlugin { plugin_path: PathBuf, diff --git a/rust/src/java/jvm/worker.rs b/rust/src/java/jvm/worker.rs index 9ba9af8..4fe3703 100644 --- a/rust/src/java/jvm/worker.rs +++ b/rust/src/java/jvm/worker.rs @@ -48,11 +48,13 @@ impl JvmWorker { respond_to, context, command_tx, + config, } => { init_callback_context( context.clone(), tokio::runtime::Handle::current(), command_tx.clone(), + config, ) .unwrap(); self.context = Some(context); diff --git a/rust/src/java/native_callbacks/config.rs b/rust/src/java/native_callbacks/config.rs new file mode 100644 index 0000000..04e8730 --- /dev/null +++ b/rust/src/java/native_callbacks/config.rs @@ -0,0 +1,21 @@ +use crate::{ + java::native_callbacks::CALLBACK_CONTEXT, + proto::patchbukkit::{common::EmptyRequest, config::GetPatchBukkitConfigResponse}, +}; + +pub fn ffi_native_bridge_get_patch_bukkit_config_impl( + _request: EmptyRequest, +) -> Option { + if let Some(context) = CALLBACK_CONTEXT.get() { + Some(GetPatchBukkitConfigResponse { + minimum_supported_plugin_api: context + .config + .settings + .minimum_supported_plugin_api + .clone() + .unwrap_or("0.0.0".to_string()), + }) + } else { + None + } +} diff --git a/rust/src/java/native_callbacks/itemstack.rs b/rust/src/java/native_callbacks/itemstack.rs new file mode 100644 index 0000000..769e490 --- /dev/null +++ b/rust/src/java/native_callbacks/itemstack.rs @@ -0,0 +1,5 @@ +// pub fn ffi_native_bridge_serialize_item_stack_impl( +// request: SerializeItemStackRequest, +// ) -> Option { +// Some(()) +// } diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index f843fe3..b2a72a5 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -5,7 +5,10 @@ use j4rs::Jvm; use pumpkin::plugin::Context; use tokio::sync::mpsc; -use crate::{java::jvm::commands::JvmCommand, proto::initialize_ffi_callbacks}; +use crate::{ + config::patchbukkit::PatchBukkitConfig, java::jvm::commands::JvmCommand, + proto::initialize_ffi_callbacks, +}; mod abilities; pub use abilities::*; @@ -30,23 +33,32 @@ pub mod utils; pub mod log; pub use log::*; +pub mod config; +pub use config::*; + +pub mod itemstack; +pub use itemstack::*; + static CALLBACK_CONTEXT: OnceLock = OnceLock::new(); struct CallbackContext { pub plugin_context: Arc, pub runtime: tokio::runtime::Handle, pub command_tx: mpsc::Sender, + pub config: PatchBukkitConfig, } pub fn init_callback_context( plugin_context: Arc, runtime: tokio::runtime::Handle, command_tx: mpsc::Sender, + config: PatchBukkitConfig, ) -> Result<()> { let context = CallbackContext { plugin_context, runtime, command_tx, + config, }; CALLBACK_CONTEXT diff --git a/rust/src/java/resources.rs b/rust/src/java/resources.rs index 4023dd1..72bb46e 100644 --- a/rust/src/java/resources.rs +++ b/rust/src/java/resources.rs @@ -86,6 +86,7 @@ pub const DEPENDENCIES: &[(&str, &str, &str)] = &[ // These are deps of patchbukkit itself ("io.papermc.paper", "paper-api", "1.21.11-R0.1-SNAPSHOT"), ("com.google.protobuf", "protobuf-java", "4.33.5"), + ("org.slf4j", "slf4j-jdk14", "2.0.16"), ]; pub fn setup_j4rs(j4rs_folder: &Path) -> Result<()> { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c8385e1..663e48a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -19,12 +19,15 @@ use tokio::sync::{ oneshot, }; -use crate::java::{ - jvm::{ - commands::{JvmCommand, LoadPluginResult}, - worker::JvmWorker, +use crate::{ + config::patchbukkit::PatchBukkitConfig, + java::{ + jvm::{ + commands::{JvmCommand, LoadPluginResult}, + worker::JvmWorker, + }, + resources::setup_j4rs, }, - resources::setup_j4rs, }; async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc) -> Result<(), String> { @@ -34,7 +37,10 @@ async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc) -> Resu // Setup directories let dirs = setup_directories(&server)?; - proto::patchbukkit::common::Uuid::default(); + let mut config_path = dirs.base.clone(); + config_path.push("patchbukkit.config.toml"); + let config = PatchBukkitConfig::get_or_create(config_path) + .map_err(|e| format!("Failed to setup PatchBukkit config: {e}"))?; // Discover and prepare JAR files let jar_paths = discover_jar_files(&dirs.plugins); @@ -112,6 +118,7 @@ async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc) -> Resu respond_to: tx, context: server.clone(), command_tx: plugin.command_tx.clone(), + config, }) .await .map_err(|e| format!("Failed to send command to initialize J4RS: {e}"))?; diff --git a/rust/src/proto/mod.rs b/rust/src/proto/mod.rs index a958c5e..ebf5045 100644 --- a/rust/src/proto/mod.rs +++ b/rust/src/proto/mod.rs @@ -30,6 +30,14 @@ pub mod patchbukkit { pub mod log { include!(concat!(env!("OUT_DIR"), "/patchbukkit.log.rs")); } + + pub mod config { + include!(concat!(env!("OUT_DIR"), "/patchbukkit.config.rs")); + } + + pub mod itemstack { + include!(concat!(env!("OUT_DIR"), "/patchbukkit.itemstack.rs")); + } } include!(concat!(env!("OUT_DIR"), "/ffi_init.rs"));