From 18442c22983f85a3a549db7a51ad52fcfe2179cc Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Sun, 1 Feb 2026 01:23:47 -0700 Subject: [PATCH] Add in the base registry --- .../patchbukkit/bridge/NativePatchBukkit.java | 31 +++- .../registry/LegacyRegistryIdentifiers.java | 53 +++++++ .../registry/PatchBukkitRegistry.java | 143 ++++++++++++++++++ .../registry/PatchBukkitRegistryAccess.java | 66 +++++++- .../registry/PatchBukkitSound.java | 62 ++++++++ .../patchbukkit/registry/PatchBukkitTag.java | 56 +++++++ rust/Cargo.lock | 93 +++++++++--- rust/Cargo.toml | 8 +- rust/src/java/native_callbacks/mod.rs | 3 + rust/src/java/native_callbacks/registry.rs | 60 ++++++++ 10 files changed, 550 insertions(+), 25 deletions(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/registry/LegacyRegistryIdentifiers.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistry.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitSound.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitTag.java create mode 100644 rust/src/java/native_callbacks/registry.rs diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java index 0952f52..a5e36c5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java @@ -18,6 +18,7 @@ public class NativePatchBukkit { private static MethodHandle getLocationNative; private static MethodHandle getWorldNative; private static MethodHandle freeStringNative; + private static MethodHandle getRegistryDataNative; // Struct layout matching Rust's #[repr(C)] AbilitiesFFI private static final StructLayout ABILITIES_LAYOUT = @@ -184,7 +185,8 @@ public class NativePatchBukkit { long setAbilitiesAddr, long getLocationAddr, long freeStringAddr, - long getWorldAddr + long getWorldAddr, + long getRegistryDataAddr ) { // void rust_send_message(const char* uuid, const char* message) sendMessageNative = LINKER.downcallHandle( @@ -240,6 +242,11 @@ public class NativePatchBukkit { FunctionDescriptor.ofVoid(ValueLayout.ADDRESS) ); + // const char* rust_get_registry_entries(const char* registry_name) + getRegistryDataNative = LINKER.downcallHandle( + MemorySegment.ofAddress(getRegistryDataAddr), + FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS) + ); } /** @@ -401,4 +408,26 @@ public class NativePatchBukkit { } } + /** + * Get all data for a registry (entries + tags) as JSON. + * + * @param registryName The registry identifier (e.g. "sound_event", "block") + * @return JSON string with "entries" and "tags" fields, or null if registry unknown + */ + public static String getRegistryData(String registryName) { + try (Arena arena = Arena.ofConfined()) { + MemorySegment nameStr = arena.allocateFrom(registryName); + MemorySegment resultPtr = (MemorySegment) getRegistryDataNative.invokeExact(nameStr); + + if (resultPtr.equals(MemorySegment.NULL)) return null; + + try { + return resultPtr.reinterpret(Long.MAX_VALUE).getString(0); + } finally { + freeRustString(resultPtr); + } + } catch (Throwable t) { + throw new RuntimeException("Failed to get registry data: " + registryName, t); + } + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/registry/LegacyRegistryIdentifiers.java b/java/patchbukkit/src/main/java/org/patchbukkit/registry/LegacyRegistryIdentifiers.java new file mode 100644 index 0000000..a611285 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/registry/LegacyRegistryIdentifiers.java @@ -0,0 +1,53 @@ +package org.patchbukkit.registry; + +import com.google.common.collect.ImmutableMap; +import io.papermc.paper.registry.RegistryKey; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.Map; +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; + + +@Deprecated +public final class LegacyRegistryIdentifiers { + + public static final Map, RegistryKey> CLASS_TO_KEY_MAP; + + static { + final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); + try { + for (final Field field : RegistryKey.class.getFields()) { + if (field.getType() == RegistryKey.class) { + // get the legacy type from the RegistryKey generic parameter on the field + final Class legacyType = LegacyRegistryIdentifiers.erase(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); + builder.put(legacyType, (RegistryKey) field.get(null)); + } + } + } catch (final ReflectiveOperationException ex) { + throw new RuntimeException(ex); + } + CLASS_TO_KEY_MAP = builder.build(); + } + + private static Class erase(Type type) { + if (type instanceof Class clazz) { + return clazz; + } else if (type instanceof ParameterizedType parameterized) { + return (Class) parameterized.getRawType(); + } else if (type instanceof GenericArrayType arrayType) { + return Array.newInstance(erase(arrayType.getGenericComponentType()), 0).getClass(); + } else if (type instanceof TypeVariable typeVar) { + return erase(typeVar.getBounds()[0]); + } else if (type instanceof WildcardType wildcard) { + return erase(wildcard.getUpperBounds()[0]); + } + throw new IllegalArgumentException("Unsupported type: " + type); + } + + private LegacyRegistryIdentifiers() { + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistry.java b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistry.java new file mode 100644 index 0000000..b734ad2 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistry.java @@ -0,0 +1,143 @@ +package org.patchbukkit.registry; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.patchbukkit.bridge.NativePatchBukkit; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Stream; + +public class PatchBukkitRegistry implements Registry { + + private final Map entries = new LinkedHashMap<>(); + private final Map> tags = new LinkedHashMap<>(); + + /** + * Build a registry by fetching JSON from the native side and parsing + * entries and tags from the combined response. + * + * Expected JSON shape: + * { + * "entries": [{"name": "...", "id": ...}, ...], + * "tags": {"minecraft:logs": ["minecraft:oak_log", ...], ...} + * } + * + * @param registryName The native registry name (e.g. "sound_event") + * @param registryKey The Paper RegistryKey for this registry + * @param factory Converts a single JsonObject into a B instance + */ + public PatchBukkitRegistry( + String registryName, + RegistryKey registryKey, + Function factory + ) { + String json = NativePatchBukkit.getRegistryData(registryName); + if (json == null) return; + + JsonObject root = JsonParser.parseString(json).getAsJsonObject(); + + JsonArray entriesArray = root.getAsJsonArray("entries"); + if (entriesArray != null) { + for (JsonElement element : entriesArray) { + B value = factory.apply(element.getAsJsonObject()); + if (value != null) { + entries.put(value.getKey(), value); + } + } + } + + JsonElement tagsElement = root.get("tags"); + if (tagsElement != null && tagsElement.isJsonObject()) { + loadTags(tagsElement.getAsJsonObject(), registryKey); + } + } + + private void loadTags(JsonObject tagMap, RegistryKey registryKey) { + for (Map.Entry entry : tagMap.entrySet()) { + String tagName = entry.getKey(); + JsonArray members = entry.getValue().getAsJsonArray(); + + Set memberKeys = new LinkedHashSet<>(); + for (JsonElement member : members) { + String raw = member.getAsString(); + // Tag values may or may not have "minecraft:" prefix + NamespacedKey key; + if (raw.contains(":")) { + key = NamespacedKey.fromString(raw); + } else { + key = new NamespacedKey(NamespacedKey.MINECRAFT, raw); + } + if (key != null) memberKeys.add(key); + } + + NamespacedKey tagKeyName = tagName.contains(":") + ? NamespacedKey.fromString(tagName) + : new NamespacedKey(NamespacedKey.MINECRAFT, tagName); + + if (tagKeyName == null) continue; + + TagKey tagKey = TagKey.create(registryKey, tagKeyName); + tags.put(tagName, new PatchBukkitTag<>(tagKey, registryKey, memberKeys)); + } + } + + @Override + public @Nullable B get(NamespacedKey key) { + return entries.get(key); + } + + @Override + public @Nullable NamespacedKey getKey(B value) { + return value.getKey(); + } + + @Override + public boolean hasTag(TagKey key) { + return tags.containsKey(key.key().asString()); + } + + @Override + public @NonNull Tag getTag(TagKey key) { + PatchBukkitTag tag = tags.get(key.key().asString()); + if (tag == null) { + throw new NoSuchElementException("Unknown tag: " + key.key().asString()); + } + return tag; + } + + @Override + public @NonNull Collection> getTags() { + return Collections.unmodifiableCollection(tags.values()); + } + + @Override + public @NonNull Stream stream() { + return entries.values().stream(); + } + + @Override + public @NonNull Stream keyStream() { + return entries.keySet().stream(); + } + + @Override + public int size() { + return entries.size(); + } + + @Override + public @NonNull Iterator iterator() { + return Collections.unmodifiableCollection(entries.values()).iterator(); + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistryAccess.java b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistryAccess.java index 039d4e4..9e30a7e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistryAccess.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitRegistryAccess.java @@ -4,19 +4,77 @@ import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; import org.bukkit.Keyed; import org.bukkit.Registry; +import org.bukkit.Sound; import org.jspecify.annotations.Nullable; +import org.patchbukkit.bridge.NativePatchBukkit; + +import com.google.gson.JsonObject; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; public class PatchBukkitRegistryAccess implements RegistryAccess { + private static final Map, Registry> instances = new ConcurrentHashMap<>(); + + /** + * Maps a RegistryKey to (native registry name, factory function). + * Add an entry here for each registry you support. + */ + private static final Map, RegistryFactory> FACTORIES = Map.of( + RegistryKey.SOUND_EVENT, new RegistryFactory<>( + "sound_event", + RegistryKey.SOUND_EVENT, + json -> new PatchBukkitSound( + json.get("name").getAsString(), + json.get("id").getAsInt() + ) + ) + ); + + private record RegistryFactory( + String nativeRegistryName, + RegistryKey registryKey, + Function factory + ) {} @Override public @Nullable Registry getRegistry(Class type) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRegistry'"); + final RegistryKey registryKey = byType(type); + return this.getRegistry(registryKey); } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Registry getRegistry(RegistryKey registryKey) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRegistry'"); + if (registryKey == null) return null; + + return (Registry) instances.computeIfAbsent(registryKey, key -> { + RegistryFactory factoryEntry = FACTORIES.get(key); + if (factoryEntry != null) { + return buildRegistry(factoryEntry); + } + + // We return an empty registry for unsupported types, since if we don't the server will crash immediately when the registry class is first loaded + return new PatchBukkitRegistry<>( + key.key().value(), + (RegistryKey) key, + json -> null + ); + }); + } + + private static PatchBukkitRegistry buildRegistry(RegistryFactory factory) { + return new PatchBukkitRegistry<>( + factory.nativeRegistryName(), + factory.registryKey(), + factory.factory() + ); + } + + @SuppressWarnings({"unchecked", "deprecation"}) + public static @Nullable RegistryKey byType(final Class type) { + return (RegistryKey) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitSound.java b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitSound.java new file mode 100644 index 0000000..5acd1f3 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitSound.java @@ -0,0 +1,62 @@ +package org.patchbukkit.registry; + +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; + +public class PatchBukkitSound implements Sound { + + private final NamespacedKey namespacedKey; + private final Key adventureKey; + private final String enumName; + private final int protocolId; + + public PatchBukkitSound(String soundName, int protocolId) { + this.namespacedKey = new NamespacedKey(NamespacedKey.MINECRAFT, soundName); + this.adventureKey = Key.key(Key.MINECRAFT_NAMESPACE, soundName); + this.protocolId = protocolId; + this.enumName = soundName.toUpperCase().replace('.', '_'); + } + + @Override + public NamespacedKey getKey() { + return namespacedKey; + } + + @Override + public Key key() { + return adventureKey; + } + + @Override + public int ordinal() { + return protocolId; + } + + @Override + public String name() { + return enumName; + } + + @Override + public int compareTo(Sound other) { + return Integer.compare(this.ordinal(), other.ordinal()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Sound other)) return false; + return namespacedKey.equals(other.getKey()); + } + + @Override + public int hashCode() { + return namespacedKey.hashCode(); + } + + @Override + public String toString() { + return "PatchBukkitSound{" + namespacedKey + "}"; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitTag.java b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitTag.java new file mode 100644 index 0000000..1157cc1 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/registry/PatchBukkitTag.java @@ -0,0 +1,56 @@ +package org.patchbukkit.registry; + +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.*; +import java.util.stream.Collectors; + +public class PatchBukkitTag implements Tag { + + private final TagKey tagKey; + private final Set> memberKeys; + + public PatchBukkitTag(TagKey tagKey, RegistryKey registryKey, Set rawKeys) { + this.tagKey = tagKey; + this.memberKeys = rawKeys.stream() + .map(k -> TypedKey.create(registryKey, k)) + .collect(Collectors.toUnmodifiableSet()); + } + + @Override + public TagKey tagKey() { + return tagKey; + } + + @Override + public @Unmodifiable Collection> values() { + return memberKeys; + } + + @Override + public @Unmodifiable Collection resolve(Registry registry) { + List resolved = new ArrayList<>(); + for (TypedKey key : memberKeys) { + B value = registry.get(key.key()); + if (value != null) resolved.add(value); + } + return Collections.unmodifiableList(resolved); + } + + @Override + public boolean contains(TypedKey valueKey) { + return memberKeys.contains(valueKey); + } + + @Override + public RegistryKey registryKey() { + return tagKey.registryKey(); + } +} diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c513d38..b195d2f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1695,10 +1695,12 @@ dependencies = [ "log", "pumpkin", "pumpkin-api-macros", - "pumpkin-util", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master)", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "rust-embed", "serde", "serde-saphyr", + "serde_json", "tokio", "uuid", "walkdir", @@ -1977,12 +1979,12 @@ dependencies = [ "num-bigint", "pkcs8 0.11.0-rc.10", "pumpkin-config", - "pumpkin-data", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-inventory", "pumpkin-macros", - "pumpkin-nbt", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-protocol", - "pumpkin-util", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-world", "rand", "rsa", @@ -2019,12 +2021,32 @@ version = "0.1.0-dev+1.21.11" source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#f93be68caa3969502c13d5d284da59fe1017ed9a" dependencies = [ "log", - "pumpkin-util", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "serde", "toml", "uuid", ] +[[package]] +name = "pumpkin-data" +version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master#007b97eed8243cf744cb0353b12438db8eab2938" +dependencies = [ + "crc-fast", + "heck", + "indexmap", + "phf", + "proc-macro2", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master)", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master)", + "quote", + "rayon", + "serde", + "serde_json", + "serde_json5", + "syn", +] + [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" @@ -2035,8 +2057,8 @@ dependencies = [ "indexmap", "phf", "proc-macro2", - "pumpkin-nbt", - "pumpkin-util", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "quote", "rayon", "serde", @@ -2052,9 +2074,9 @@ source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#f93be68caa dependencies = [ "crossbeam-utils", "log", - "pumpkin-data", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-protocol", - "pumpkin-util", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-world", "thiserror", "tokio", @@ -2067,11 +2089,23 @@ source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#f93be68caa dependencies = [ "proc-macro-error2", "proc-macro2", - "pumpkin-data", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "quote", "syn", ] +[[package]] +name = "pumpkin-nbt" +version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master#007b97eed8243cf744cb0353b12438db8eab2938" +dependencies = [ + "bytes", + "cesu8", + "flate2", + "serde", + "thiserror", +] + [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" @@ -2094,10 +2128,10 @@ dependencies = [ "bitflags", "bytes", "cfb8", - "pumpkin-data", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-macros", - "pumpkin-nbt", - "pumpkin-util", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "pumpkin-world", "serde", "take_mut", @@ -2106,6 +2140,31 @@ dependencies = [ "uuid", ] +[[package]] +name = "pumpkin-util" +version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master#007b97eed8243cf744cb0353b12438db8eab2938" +dependencies = [ + "base64", + "bytes", + "colored", + "ecdsa", + "enum_dispatch", + "md5", + "num-derive", + "num-traits", + "p384", + "proc-macro2", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/BjornTheProgrammer/Pumpkin.git?branch=master)", + "quote", + "serde", + "serde_json", + "syn", + "thiserror", + "tokio", + "uuid", +] + [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" @@ -2121,7 +2180,7 @@ dependencies = [ "num-traits", "p384", "proc-macro2", - "pumpkin-nbt", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "quote", "serde", "serde_json", @@ -2152,9 +2211,9 @@ dependencies = [ "num-traits", "num_cpus", "pumpkin-config", - "pumpkin-data", - "pumpkin-nbt", - "pumpkin-util", + "pumpkin-data 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", + "pumpkin-nbt 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", + "pumpkin-util 0.1.0-dev+1.21.11 (git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master)", "rand", "rustc-hash", "ruzstd", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2369647..7e38835 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -8,6 +8,7 @@ crate-type = ["cdylib"] [dependencies] pumpkin = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin" } +pumpkin-data = { git = "https://github.com/BjornTheProgrammer/Pumpkin.git", branch = "master", package = "pumpkin-data" } 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" } @@ -20,12 +21,13 @@ rust-embed = { version = "8.11.0", features = ["interpolate-folder-path"] } walkdir = "2" zip = "7.2" -serde-saphyr = "0.0.16" -serde = { version = "1", features = ["derive"] } - anyhow = "1.0" uuid = "1.20.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde-saphyr = "0.0.16" + [build-dependencies] j4rs = { version = "0.24", artifact = "cdylib", lib = true } env_logger = "0.11.8" diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index 50c2d6c..bb6892d 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -9,6 +9,7 @@ pub mod events; pub mod location; pub mod memory; pub mod message; +pub mod registry; pub mod utils; pub mod world; @@ -42,6 +43,7 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { let get_location_addr = location::rust_get_location as *const () as i64; let free_string_addr = memory::rust_free_string as *const () as i64; let get_world_addr = world::rust_get_world as *const () as i64; + let rust_get_registry_data_addr = registry::rust_get_registry_data as *const () as i64; jvm.invoke_static( "org.patchbukkit.bridge.NativePatchBukkit", @@ -54,6 +56,7 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { InvocationArg::try_from(get_location_addr)?.into_primitive()?, InvocationArg::try_from(free_string_addr)?.into_primitive()?, InvocationArg::try_from(get_world_addr)?.into_primitive()?, + InvocationArg::try_from(rust_get_registry_data_addr)?.into_primitive()?, ], )?; diff --git a/rust/src/java/native_callbacks/registry.rs b/rust/src/java/native_callbacks/registry.rs new file mode 100644 index 0000000..5118079 --- /dev/null +++ b/rust/src/java/native_callbacks/registry.rs @@ -0,0 +1,60 @@ +use std::{collections::HashMap, ffi::CString, os::raw::c_char}; + +use serde::Serialize; +use serde_json::Value; + +use crate::java::native_callbacks::utils::get_string; + +#[derive(Serialize, Debug, Clone)] +struct Registry { + pub entries: Vec, + pub tags: HashMap>, +} + +impl Registry { + pub fn new(entries: Vec, tags: HashMap>) -> Self { + Registry { entries, tags } + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn rust_get_registry_data(registry_name: *const c_char) -> *const c_char { + let name = get_string(registry_name); + + let registry: Option = match name.as_ref() { + "sound_event" => { + let entries: Vec = pumpkin_data::sound::Sound::slice() + .iter() + .map(|s| { + serde_json::json!({ + "name": s.to_name(), + "id": *s as u16 + }) + }) + .collect(); + Some(Registry::new(entries, HashMap::new())) + } + _ => None, + }; + + let registry = match registry { + Some(registry) => registry, + None => return std::ptr::null(), + }; + + let json_str = match serde_json::to_string(®istry) { + Ok(json_str) => json_str, + Err(err) => { + log::error!("Failed to serialize registry: {}", err); + return std::ptr::null(); + } + }; + + match CString::new(json_str) { + Ok(cstring) => cstring.into_raw(), + Err(err) => { + log::error!("Failed to convert registry string to CString: {}", err); + return std::ptr::null_mut(); + } + } +}