diff --git a/src/main/java/dev/latvian/mods/kubejs/core/TagLoaderKJS.java b/src/main/java/dev/latvian/mods/kubejs/core/TagLoaderKJS.java index 6e7aef8f8..9a4b4b5dd 100644 --- a/src/main/java/dev/latvian/mods/kubejs/core/TagLoaderKJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/core/TagLoaderKJS.java @@ -36,6 +36,8 @@ public interface TagLoaderKJS { } } + hasDefaultTags |= !kjs$getResources().kjs$getServerScriptManager().serverRegistryTags.isEmpty(); + if (hasDefaultTags || ServerEvents.TAGS.hasListeners(objStorage.key)) { var preEvent = kjs$getResources().kjs$getServerScriptManager().preTagEvents.get(reg.key()); @@ -56,6 +58,12 @@ public interface TagLoaderKJS { } } + for (var e : kjs$getResources().kjs$getServerScriptManager().serverRegistryTags.entrySet()) { + for (var tag : e.getValue()) { + event.add(tag, new TagEventFilter.ID(e.getKey())); + } + } + if (preEvent == null) { ServerEvents.TAGS.post(event, objStorage.key); } else { diff --git a/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java b/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java index 7a41efb2a..4be4a2ca0 100644 --- a/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java @@ -56,6 +56,25 @@ static Holder wrap(KubeJSContext cx, Object from, TypeInfo param) { return holder.isEmpty() ? DeferredHolder.create(registry.key(), id) : holder.get(); } + static Holder.Reference wrapRef(KubeJSContext cx, Object from, TypeInfo param) { + if (from instanceof Holder.Reference h) { + return h; + } else if (from == null) { + throw Context.reportRuntimeError("Can't interpret 'null' as a holder", cx); + } + + var registry = cx.lookupRegistry(param, from); + + if (from instanceof Holder h) { + return Holder.Reference.createStandAlone(Cast.to(registry.holderOwner()), h.getKey()); + } else if (!ID.isKey(from)) { + throw Context.reportRuntimeError("Can't interpret '" + from + "' as a reference holder", cx); + } + + var id = ID.mc(from); + return Holder.Reference.createStandAlone(Cast.to(registry.holderOwner()), ResourceKey.create(registry.key(), id)); + } + static HolderSet wrapSet(KubeJSContext cx, Object from, TypeInfo param) { var registry = cx.lookupRegistry(param, from); diff --git a/src/main/java/dev/latvian/mods/kubejs/script/KubeJSContext.java b/src/main/java/dev/latvian/mods/kubejs/script/KubeJSContext.java index 3b96cdb33..93fbe74b7 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/KubeJSContext.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/KubeJSContext.java @@ -88,7 +88,7 @@ public Scriptable wrapAsJavaObject(Scriptable scope, Object javaObject, TypeInfo public int internalConversionWeightLast(Object fromObj, TypeInfo target) { var c = target.asClass(); - if (c == Optional.class || c == ResourceKey.class || c == Holder.class || c == HolderSet.class || c == TagKey.class) { + if (c == Optional.class || c == ResourceKey.class || c == Holder.class || c == HolderSet.class || c == TagKey.class || c == Holder.Reference.class) { return CONVERSION_TRIVIAL; } else if (c != Object.class) { var reg = RegistryType.allOfClass(target.asClass()); @@ -144,6 +144,8 @@ protected Object internalJsToJavaLast(Object from, TypeInfo target) { return ResourceKey.create(registryType.key(), id); } else if (c == Holder.class) { return HolderWrapper.wrap(this, from, target.param(0)); + } else if (c == Holder.Reference.class) { + return HolderWrapper.wrapRef(this, from, target.param(0)); } else if (c == HolderSet.class) { return HolderWrapper.wrapSet(this, from, target.param(0)); } else if (c == TagKey.class) { diff --git a/src/main/java/dev/latvian/mods/kubejs/server/ServerScriptManager.java b/src/main/java/dev/latvian/mods/kubejs/server/ServerScriptManager.java index bbf698bb5..562cd4618 100644 --- a/src/main/java/dev/latvian/mods/kubejs/server/ServerScriptManager.java +++ b/src/main/java/dev/latvian/mods/kubejs/server/ServerScriptManager.java @@ -1,6 +1,7 @@ package dev.latvian.mods.kubejs.server; import com.mojang.serialization.Codec; +import com.mojang.serialization.Lifecycle; import dev.latvian.mods.kubejs.KubeJS; import dev.latvian.mods.kubejs.KubeJSPaths; import dev.latvian.mods.kubejs.error.KubeRuntimeException; @@ -24,7 +25,9 @@ import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackResources; @@ -36,11 +39,15 @@ import java.nio.file.Files; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import java.util.stream.Stream; public class ServerScriptManager extends ScriptManager { private static ServerScriptManager staticInstance; @@ -92,6 +99,7 @@ public static ServerScriptManager release() { public final VirtualDataPack internalDataPack; public final VirtualDataPack registriesDataPack; public final Map virtualPacks; + public final Map> serverRegistryTags; public boolean firstLoad; private ServerScriptManager() { @@ -103,6 +111,7 @@ private ServerScriptManager() { this.internalDataPack = new VirtualDataPack(GeneratedDataStage.INTERNAL, this::getRegistries); this.registriesDataPack = new VirtualDataPack(GeneratedDataStage.REGISTRIES, this::getRegistries); this.virtualPacks = GeneratedDataStage.forScripts(stage -> new VirtualDataPack(stage, this::getRegistries)); + serverRegistryTags = new HashMap<>(); this.firstLoad = true; @@ -177,6 +186,26 @@ public void loadAdditional() { if (ServerEvents.REGISTRY.hasListeners()) { var builders = new ArrayList>(); + var current = RegistryAccessContainer.current; + RegistryAccessContainer.current = new RegistryAccessContainer(new RegistryAccess.Frozen() { + + final Map>, Optional>> registries = new HashMap<>(); + + @Override + public Optional> registry(ResourceKey> registryKey) { + return Cast.to(registries.computeIfAbsent(registryKey, key -> { + var c = current.access().registry(key); + if (c.isPresent()) return Cast.to(c); + return Optional.of(new MappedRegistry(key, Lifecycle.experimental())); + })); + } + + @Override + public Stream> registries() { + return current.access().registries(); + } + }); + var ops = RegistryAccessContainer.current.json(); var codecs = new Reference2ObjectOpenHashMap, Codec>(); @@ -196,6 +225,10 @@ public void loadAdditional() { for (var b : builders) { b.generateData(registriesDataPack); + + if (!b.defaultTags.isEmpty()) { + serverRegistryTags.put(b.id, b.defaultTags); + } } for (var b : builders) { @@ -226,6 +259,8 @@ public void loadAdditional() { } registriesDataPack.flush(); + + RegistryAccessContainer.current = current; } } }