diff --git a/src/main/java/zzzank/probejs/ProbeDumpingThread.java b/src/main/java/zzzank/probejs/ProbeDumpingThread.java index d4e88573..4b025182 100644 --- a/src/main/java/zzzank/probejs/ProbeDumpingThread.java +++ b/src/main/java/zzzank/probejs/ProbeDumpingThread.java @@ -42,10 +42,12 @@ public void run() { messageSender.accept(TextWrapper .translate("probejs.download_rhizo_help") .append(TextWrapper.string("CurseForge") + .aqua() .underlined() .click("https://www.curseforge.com/minecraft/mc-mods/rhizo/files")) .append(" / ") .append(TextWrapper.string("Github") + .aqua() .underlined() .click("https://github.com/ZZZank/Rhizo/releases/latest")) .component() diff --git a/src/main/java/zzzank/probejs/docs/events/ForgeEvents.java b/src/main/java/zzzank/probejs/docs/events/ForgeEvents.java index 9553a093..250a765e 100644 --- a/src/main/java/zzzank/probejs/docs/events/ForgeEvents.java +++ b/src/main/java/zzzank/probejs/docs/events/ForgeEvents.java @@ -31,10 +31,8 @@ public void addGlobals(ScriptDump scriptDump) { "handler", Types.lambda() .param("event", Types.instanceType(Types.primitive(T))) - .returnType(Types.VOID) .build() ) - .returnType(Types.VOID) .build()); } diff --git a/src/main/java/zzzank/probejs/docs/events/RegistryEvents.java b/src/main/java/zzzank/probejs/docs/events/RegistryEvents.java index ccdd855b..7378bb80 100644 --- a/src/main/java/zzzank/probejs/docs/events/RegistryEvents.java +++ b/src/main/java/zzzank/probejs/docs/events/RegistryEvents.java @@ -1,34 +1,50 @@ package zzzank.probejs.docs.events; +import dev.latvian.kubejs.script.ScriptType; +import lombok.val; +import zzzank.probejs.features.kubejs.SpecialData; +import zzzank.probejs.lang.java.clazz.ClassPath; +import zzzank.probejs.lang.typescript.ScriptDump; +import zzzank.probejs.lang.typescript.code.ts.Statements; +import zzzank.probejs.lang.typescript.code.ts.Wrapped; +import zzzank.probejs.lang.typescript.code.type.Types; import zzzank.probejs.plugin.ProbeJSPlugin; +import zzzank.probejs.utils.GameUtils; +import zzzank.probejs.utils.NameUtils; + +import java.util.HashSet; +import java.util.Set; public class RegistryEvents extends ProbeJSPlugin { -// @Override -// public void addGlobals(ScriptDump scriptDump) { -// if (scriptDump.scriptType != ScriptType.STARTUP) return; -// -// Wrapped.Namespace groupNamespace = new Wrapped.Namespace("StartupEvents"); -// -// for (ResourceKey> key : BuiltInRegistries.REGISTRY.registryKeySet()) { -// ClassPath registryPath = getRegistryClassPath(key.location().getNamespace(), key.location().getPath()); -// String extraName = key.location().getNamespace().equals("minecraft") ? -// key.location().getPath() : -// key.location().toString(); -// -// MethodDeclaration declaration = Statements.method("registry") -// .param("type", Types.literal(extraName)) -// .param("handler", Types.lambda() -// .param("event", Types.type(registryPath)) -// .build() -// ) -// .build(); -// groupNamespace.addCode(declaration); -// } -// -// scriptDump.addGlobal("registry_events", groupNamespace); -// } -// + @Override + public void addGlobals(ScriptDump scriptDump) { + if (scriptDump.scriptType != ScriptType.STARTUP) { + return; + } + + val groupNamespace = new Wrapped.Namespace("StartupEvents"); + + for (val info : SpecialData.instance().registries()) { + val key = info.resKey(); + val registryPath = getRegistryClassPath(key.location().getNamespace(), key.location().getPath()); + val extraName = key.location().getNamespace().equals("minecraft") + ? key.location().getPath() + : key.location().toString(); + + val declaration = Statements.func("registry") + .param("type", Types.literal(extraName)) + .param("handler", Types.lambda() + .param("event", Types.type(registryPath)) + .build() + ) + .build(); + groupNamespace.addCode(declaration); + } + + scriptDump.addGlobal("registry_events", groupNamespace); + } + // @Override // public void modifyClasses(ScriptDump scriptDump, Map globalClasses) { // if (scriptDump.scriptType != ScriptType.STARTUP) return; @@ -57,12 +73,14 @@ public class RegistryEvents extends ProbeJSPlugin { // .ifPresent(method -> method.params.get(1).type = Types.lambda().returnType(Types.generic("T")).build()); // // } -// -// private static ClassPath getRegistryClassPath(String namespace, String location) { -// return new ClassPath("zzzank.probejs.generated.registry.%s.%s".formatted( -// namespace, NameUtils.rlToTitle(location) -// )); -// } + + private static ClassPath getRegistryClassPath(String namespace, String location) { + return new ClassPath(String.format( + "zzzank.probejs.generated.registry.%s.%s", + namespace, + NameUtils.rlToTitle(location) + )); + } // // private static ClassDecl generateRegistryClass(ResourceKey key, Class baseClass, RegistryInfo info) { // ClassDecl.Builder builder = Statements.clazz(NameUtils.rlToTitle(key.location().getPath())) @@ -84,20 +102,24 @@ public class RegistryEvents extends ProbeJSPlugin { // // return builder.build(); // } -// -// @Override -// public Set> provideJavaClass(ScriptDump scriptDump) { -// Set> classes = new HashSet<>(); -// -// for (ResourceKey> key : BuiltInRegistries.REGISTRY.registryKeySet()) { -// RegistryInfo registryInfo = RegistryInfo.of(RegistryUtils.castKey(key)); -// var defaultType = registryInfo.getDefaultType(); -// if (defaultType != null) classes.add(defaultType.builderClass()); -// for (BuilderType type : registryInfo.getTypes()) { -// classes.add(type.builderClass()); -// } -// } -// -// return classes; -// } + + @Override + public Set> provideJavaClass(ScriptDump scriptDump) { + Set> classes = new HashSet<>(); + + for (val info : SpecialData.instance().registries()) { + val forgeRegistry = info.forgeRaw(); + val vanillaRegistry = info.raw(); + classes.add(forgeRegistry.getRegistrySuperType()); + if (vanillaRegistry != null) { + //dont use val here, it's unable to figure out the exact type + var instance = GameUtils.anyIn(vanillaRegistry.entrySet()); + if (instance != null) { + classes.add(instance.getValue().getClass()); + } + } + } + + return classes; + } } diff --git a/src/main/java/zzzank/probejs/docs/events/TagEvents.java b/src/main/java/zzzank/probejs/docs/events/TagEvents.java index e33eb491..1ffb1913 100644 --- a/src/main/java/zzzank/probejs/docs/events/TagEvents.java +++ b/src/main/java/zzzank/probejs/docs/events/TagEvents.java @@ -1,97 +1,130 @@ package zzzank.probejs.docs.events; +import dev.latvian.kubejs.script.ScriptType; +import dev.latvian.kubejs.server.TagEventJS; +import lombok.val; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import zzzank.probejs.features.kubejs.SpecialData; import zzzank.probejs.lang.java.clazz.ClassPath; +import zzzank.probejs.lang.typescript.ScriptDump; +import zzzank.probejs.lang.typescript.TypeScriptFile; +import zzzank.probejs.lang.typescript.code.Code; +import zzzank.probejs.lang.typescript.code.ts.Statements; +import zzzank.probejs.lang.typescript.code.ts.Wrapped; +import zzzank.probejs.lang.typescript.code.type.Types; import zzzank.probejs.plugin.ProbeJSPlugin; +import zzzank.probejs.utils.NameUtils; + +import java.util.*; public class TagEvents extends ProbeJSPlugin { + public static final Set POSTED = new HashSet<>(); + public static final ClassPath TAG_EVENT = new ClassPath("zzzank.probejs.generated.TagEventProbe"); public static final ClassPath TAG_WRAPPER = new ClassPath("zzzank.probejs.generated.TagWrapperProbe"); // Create TagEventProbe and TagWrapperProbe // Generate string overrides for all registry types // tags(extra: "item", handler: (event: TagEventProbe) => void) -// -// @Override -// public void addGlobals(ScriptDump scriptDump) { -// if (scriptDump.scriptType != ScriptType.SERVER) { -// return; -// } -// -// BaseType eventType = Types.type(TAG_EVENT); -// MinecraftServer currentServer = ServerLifecycleHooks.getCurrentServer(); -// if (currentServer == null) { -// return; -// } -// RegistryAccess registryAccess = currentServer.registryAccess(); -// -// Wrapped.Namespace groupNamespace = new Wrapped.Namespace("ServerEvents"); -// for (ResourceKey> key : RegistryUtils.getRegistries(registryAccess)) { -// Registry registry = registryAccess.registry(key).orElse(null); -// if (registry == null) { -// continue; -// } -// -// String typeName = "Special." + NameUtils.rlToTitle(key.location().getPath()); -// String tagName = typeName + "Tag"; -// String extraName = key.location().getNamespace().equals("minecraft") ? -// key.location().getPath() : -// key.location().toString(); -// MethodDeclaration declaration = Statements.method("tags") -// .param("extra", Types.literal(extraName)) -// .param("handler", Types.lambda() -// .param("event", Types.parameterized( -// eventType, -// Types.primitive(tagName), Types.primitive(typeName) -// )) -// .build() -// ) -// .build(); -// groupNamespace.addCode(declaration); -// } -// -// scriptDump.addGlobal("tag_events", groupNamespace); -// } -// -// @Override -// public void modifyClasses(ScriptDump scriptDump, Map globalClasses) { -// if (scriptDump.scriptType != ScriptType.SERVER) { -// return; -// } -// -// BaseType wrapperType = Types.type(TAG_WRAPPER); -// -// ClassDecl tagEventProbe = Statements.clazz(TAG_EVENT.getName()) -// .superClass(Types.type(TagKubeEvent.class)) -// .typeVariables("T", "I") -// .method("add", builder -> builder -// .returnType(Types.parameterized(wrapperType, Types.generic("T"), Types.generic("I"))) -// .param("tag", Types.generic("T")) -// .param("filters", Types.generic("I").asArray(), false, true) -// ) -// .method("remove", builder -> builder -// .returnType(Types.parameterized(wrapperType, Types.generic("T"), Types.generic("I"))) -// .param("tag", Types.generic("T")) -// .param("filters", Types.generic("I").asArray(), false, true) -// ) -// .build(); -// TypeScriptFile eventFile = new TypeScriptFile(TAG_EVENT); -// eventFile.addCode(tagEventProbe); -// globalClasses.put(TAG_EVENT, eventFile); -// -// ClassDecl tagWrapperProbe = Statements.clazz(TAG_WRAPPER.getName()) -// .superClass(Types.type(TagEventJS.TagWrapper.class)) -// .typeVariables("T", "I") -// .method("add", builder -> builder -// .returnType(Types.THIS) -// .param("filters", Types.generic("I").asArray(), false, true) -// ) -// .method("remove", builder -> builder -// .returnType(Types.THIS) -// .param("filters", Types.generic("I").asArray(), false, true) -// ) -// .build(); -// TypeScriptFile wrapperFile = new TypeScriptFile(TAG_WRAPPER); -// wrapperFile.addCode(tagWrapperProbe); -// globalClasses.put(TAG_WRAPPER, wrapperFile); -// } + + @Override + public void addGlobals(ScriptDump scriptDump) { + if (scriptDump.scriptType != ScriptType.SERVER) { + return; + } + + val eventType = Types.type(TAG_EVENT); + val server = ServerLifecycleHooks.getCurrentServer(); + if (server == null) { + return; + } + + val events = new ArrayList(); + for (val info : SpecialData.instance().registries()) { + val forgeRegistry = info.forgeRaw(); + val tagFolder = forgeRegistry.getTagFolder(); + if (tagFolder == null) { + continue; + } + + } + + val groupNamespace = new Wrapped.Namespace("ServerEvents"); + for (val info : SpecialData.instance().registries()) { + val key = info.resKey(); + val registry = info.raw(); + if (registry == null) { + continue; + } + val typeName = "Special." + NameUtils.rlToTitle(key.location().getPath()); + val tagName = typeName + "Tag"; + val extraName = key.location().getNamespace().equals("minecraft") + ? key.location().getPath() + : key.location().toString(); + val declaration = Statements.func("tags") + .param("extra", Types.literal(extraName)) + .param("handler", Types.lambda() + .param("event", Types.parameterized( + eventType, + Types.primitive(tagName), Types.primitive(typeName) + )) + .build() + ) + .build(); + groupNamespace.addCode(declaration); + } + + scriptDump.addGlobal("tag_events", groupNamespace); + } + + @Override + public void modifyClasses(ScriptDump scriptDump, Map globalClasses) { + if (scriptDump.scriptType != ScriptType.SERVER) { + return; + } + + val wrapperType = Types.type(TAG_WRAPPER); + + val genericT = Types.generic("T"); + val genericI = Types.generic("I"); + + val tagEventProbe = Statements.clazz(TAG_EVENT.getName()) + .superClass(Types.type(TagEventJS.class)) + .typeVariables("T", "I") + .method("add", builder -> builder + .returnType(Types.parameterized(wrapperType, genericT, genericI)) + .param("tag", genericT) + .param("filters", genericI.asArray(), false, true) + ) + .method("remove", builder -> builder + .returnType(Types.parameterized(wrapperType, genericT, genericI)) + .param("tag", genericT) + .param("filters", genericI.asArray(), false, true) + ) + .build(); + val eventFile = new TypeScriptFile(TAG_EVENT); + eventFile.addCode(tagEventProbe); + globalClasses.put(TAG_EVENT, eventFile); + + val tagWrapperProbe = Statements.clazz(TAG_WRAPPER.getName()) + .superClass(Types.type(TagEventJS.TagWrapper.class)) + .typeVariables("T", "I") + .method("add", builder -> builder + .returnType(Types.THIS) + .param("filters", genericI.asArray(), false, true) + ) + .method("remove", builder -> builder + .returnType(Types.THIS) + .param("filters", genericI.asArray(), false, true) + ) + .build(); + val wrapperFile = new TypeScriptFile(TAG_WRAPPER); + wrapperFile.addCode(tagWrapperProbe); + globalClasses.put(TAG_WRAPPER, wrapperFile); + } + + @Override + public Set disableEventDumps(ScriptDump dump) { + return POSTED; + } } diff --git a/src/main/java/zzzank/probejs/features/interop/EvaluateCommand.java b/src/main/java/zzzank/probejs/features/interop/EvaluateCommand.java index 8493c30f..8e85d7b1 100644 --- a/src/main/java/zzzank/probejs/features/interop/EvaluateCommand.java +++ b/src/main/java/zzzank/probejs/features/interop/EvaluateCommand.java @@ -10,6 +10,7 @@ import dev.latvian.mods.rhino.NativeJavaObject; import lombok.val; import zzzank.probejs.features.bridge.Command; +import zzzank.probejs.utils.GameUtils; import zzzank.probejs.utils.JsonUtils; public class EvaluateCommand extends Command { @@ -31,7 +32,10 @@ public JsonElement handle(JsonObject payload) { }; //well, there's one and only one ScriptPack in so-called scriptManager.pack`s` - val pack = scriptManager.packs.values().stream().findAny().get(); + val pack = GameUtils.anyIn(scriptManager.packs.values()); + if (pack == null) { + throw new RuntimeException("Unable to get script context or scope."); + } Object result = pack.context.evaluateString(pack.scope, content, "probejsEvaluator", 1, null); if (result instanceof NativeJavaObject nativeJavaObject) { result = nativeJavaObject.unwrap(); diff --git a/src/main/java/zzzank/probejs/utils/GameUtils.java b/src/main/java/zzzank/probejs/utils/GameUtils.java index 8895ffa3..7bb92791 100644 --- a/src/main/java/zzzank/probejs/utils/GameUtils.java +++ b/src/main/java/zzzank/probejs/utils/GameUtils.java @@ -9,13 +9,13 @@ import zzzank.probejs.features.kubejs.SpecialData; import zzzank.probejs.utils.registry.RegistryInfo; +import javax.annotation.Nullable; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class GameUtils { public static long modHash() { @@ -60,4 +60,15 @@ public static void logThrowable(Throwable t) { lines.addAll(Arrays.asList(trace)); ProbeJS.LOGGER.error(lines.stream().map(Object::toString).collect(Collectors.joining("\n"))); } + + @Nullable + public static T anyIn(Iterable iterable) { + val iterator = iterable.iterator(); + return iterator.hasNext() ? iterator.next() : null; + } + + @Nullable + public static T anyIn(Stream stream) { + return stream.findAny().orElse(null); + } }