服务器插件开发中的 Clojure:调用服务器启动后必须初始化的类

Clojure in server plugin dev: calling classes that must be initialized after server startup

提问人:Freeze Dolphin 提问时间:6/14/2023 最后编辑:amalloyFreeze Dolphin 更新时间:6/15/2023 访问量:70

问:

我是 clojure 的新手。.

假设服务器通过在运行时加载 jar 文件来加载插件。

服务器本身有许多类,必须在服务器启动后进行初始化。(这些类将检查服务器是否在构建时运行......

clojure 能参与这样的场景吗?


以下是详细的

我想创建一个 Slimefun 插件。我只想使用 clojure 来设置项目

但众所周知,在Minecraft开发中,几乎所有的东西都应该在服务器启动后才进行初始化,并且类在构建时也会检查服务器是否在运行(例如ItemStack)

在 clojure 编译过程中,代码似乎被执行了。(我不知道这是否正确......这意味着如果我的代码涉及诸如 之类的类,那么编译将失败。ItemStack

那么,如果我想开发涉及 Clojure 的 spigot 插件,我该怎么办?


编译日志:

freeze-dolphin@stardust:~/Documents/workspace/idea/Dumortierite/clj-module$ lein jar
Compiling io.sn.dumortierite.clj-module.items
Reflection warning, io/sn/dumortierite/clj_module/items.clj:15:1 - call to io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack ctor can't be resolved.
Syntax error macroexpanding def at (items.clj:15:1).
Execution error (NullPointerException) at org.bukkit.Bukkit/getItemFactory (Bukkit.java:1831).
Cannot invoke "org.bukkit.Server.getItemFactory()" because "org.bukkit.Bukkit.server" is null

Full report at:
/tmp/clojure-2943387361270522517.edn
Compilation failed: Subprocess failed (exit code: 1)

以下是报告全文: https://pastebin.com/xzmxHp5q


此外,如果对如何结合 leiningen 和 gradle 感兴趣,您可以查看上面使用的 repo: https://github.com/freeze-dolphin/Dumortierite/tree/master/clj-module

Clojure Minecraft Bukkit Leiningen 水龙头

评论

1赞 cfrick 6/14/2023
当你在编译时看到这样的东西时,很可能你正在做一些你只想在运行时做的顶级事情(例如,一个) - 你需要从编译器中“隐藏”它 - 但是当查看链接的存储库时,我没有找到“服务器”这个词,这是我所期望的。所以一般的提示:编译 clojure 总是在某种程度上运行 clojure——这通常归结为“不要定义沉重的东西”。def
0赞 amalloy 6/15/2023
我已经恢复了您的编辑。在 Stack Overflow 上,我们不会将解决方案编辑为问题。你已经接受了我的回答,这是一个足够明确的信号,表明问题已经解决。如果您认为我的答案没有涵盖重要细节,您可以自由评论,或添加包含详细信息的其他答案。如果有帮助,您可以从修订历史记录中检索您的编辑。

答:

0赞 Alan Thompson 6/14/2023 #1

我不熟悉 Minecraft 等,但你可以用 Java 做的任何事情也可以用 Clojure 完成。如果你知道如何编写一个 Java “插件”,你应该能够使用一个瘦的 Java“桥接”来“轻松地”将其转换为 Clojure。

所有细节都在这个问题中描述。

另请参阅此问题

评论

0赞 Freeze Dolphin 6/14/2023
所以我应该先写一个插件 api 包装器,然后从 clojure 调用包装器?
0赞 Eugene Pakhomov 6/14/2023
反之亦然 - Java 将调用 Clojure。尽管如果这是一种选择,我会尝试仅限 Clojure 的解决方案。Clojure 可以使用所需的 API 生成 Java 类,但有一些注意事项,并且有据可查。
2赞 amalloy 6/14/2023 #2

感谢您包含完整的堆栈跟踪 - 很多新手没有,这非常令人沮丧,因为它总是包含有用的信息。在这种情况下,它表明,不出所料,cfrick的猜测是正确的。具体来说,在第 15 行,您已经写了items.clj

(def something (whatever (org.bukkit.Bukkit/getItemFactory)))

这意味着,在编译过程中,您正在调用 .一般来说,在编译过程中,你应该依赖很少的东西。顶级 defs 应该只使用函数、数字、字符串、序列,诸如此类的轻量级内容。在运行时之前不需要的任何内容都应该被推迟,通常是通过将其放在由以下定义下的函数中:getItemFactorydefn

(defn something [args] (whatever (org.bukkit.Bukkit/getItemFactory)))

只有在准备好运行初始化代码后,才能在运行时调用它。

如果你需要一些类似变量的东西,尽管它的依赖关系很昂贵,当然你不希望每次调用它所包含的函数时都初始化它。最简单的解决方案是使用:delay

(def something (delay (whatever ...)))

然后,使用 取消引用它,它仅在您第一次取消引用它时调用它。@somethingwhatever

评论

0赞 Freeze Dolphin 6/15/2023
由返回地图的函数求解。;)