HimDSLAPI - HimxhMC/HimDSL GitHub Wiki
HimDSLAPI
面向谁 / Who This Is For
本章面向 Java 插件开发者,不是脚本用户。如果你只写 .himdsl 脚本,可以跳过这一部分。
This chapter is for Java plugin developers, not script authors. If you only write .himdsl scripts, you may skip this section.
HimDSL 通过 Bukkit 的 ServicesManager 暴露一个 API 接口,其他插件可以:
HimDSL exposes an API through Bukkit's ServicesManager; other plugins can:
-
从 Java 代码里编译和运行脚本。
-
保存脚本到 HimDSL 数据目录。
-
注册自定义占位符。
-
Compile and run scripts from Java code.
-
Save scripts into HimDSL's data folder.
-
Register custom placeholders.
获取 API 实例 / Getting the API
在 onEnable 里用 ServicesManager 获取:
In onEnable, obtain it via the ServicesManager:
import com.himdsl.api.HimDSLAPI;
import org.bukkit.Bukkit;
HimDSLAPI api = Bukkit.getServicesManager()
.load(HimDSLAPI.class);
if (api == null) {
getLogger().warning("HimDSL 未安装或版本不兼容");
return;
}
HimDSL 必须在你的插件之前加载。在 plugin.yml 里声明软依赖:
HimDSL must load before your plugin. Declare a soft dependency in plugin.yml:
softdepend: [HimDSL]
用 softdepend 而非 depend——HimDSL 缺失时你的插件依然可以启动,只是脚本相关功能不可用。
Use softdepend, not depend — your plugin still starts without HimDSL; only script features go unavailable.
三个方法 / Three Methods
HimDSLAPI 提供三个方法:
HimDSLAPI offers three methods:
HimDSLAPI.CompileResult compile(File file);
HimDSLAPI.ExecutionResult run(File file);
boolean saveScript(String relativePath, String content);
每个方法返回一个结果对象或布尔值,不会抛异常。调用者应当检查返回值。
Each returns a result object or boolean, without throwing. Callers should check.
compile:编译脚本 / compile: Compile a Script
File script = new File(himdslDataFolder, "hello.himdsl");
HimDSLAPI.CompileResult result = api.compile(script);
if (result.isSuccess()) {
getLogger().info("脚本编译通过");
} else {
getLogger().warning("编译失败: " + result.getErrorMessage());
}
只做语法检查,不执行任何逻辑。适合"部署前验证脚本"或"从其他插件动态生成脚本后检查"。
Syntax check only, no execution. Good for "verify before deployment" or "check dynamically generated scripts".
CompileResult 的两个方法:
CompileResult's two methods:
-
isSuccess()— 是否成功。 -
getErrorMessage()— 失败原因(成功时为null)。 -
isSuccess()— success flag. -
getErrorMessage()— failure reason (nullon success).
run:执行脚本 / run: Execute a Script
HimDSLAPI.ExecutionResult result = api.run(script);
if (result.isSuccess()) {
getLogger().info("执行完成");
} else {
getLogger().warning("执行失败: " + result.getErrorMessage());
}
执行整个脚本:解析 → 收集定义 → 执行 main。
Executes the full script: parse → collect definitions → run main.
注意几点:
Note a few things:
-
每次
run都会清空之前的函数、结构体、枚举、事件缓存。也就是说run是"重新加载并运行一次",不是"增量执行"。 -
脚本里注册的
@EventHandler和@BukkitRunnable不会自动启动——它们需要脚本自己调用start。 -
run会同步执行到结束。长时间脚本会阻塞调用者。 -
Each
runclears previous functions, structs, enums, and event caches.runmeans "reload and run once", not "incremental". -
@EventHandler/@BukkitRunnabledeclared in the script do not auto-start — the script must callstart. -
runblocks until completion. Long scripts block the caller.
建议从主线程调用。脚本可能操作游戏世界(runcmd、引用方法),从异步线程调用虽然能工作(HimDSL 内部会切主线程),但会带来不必要的开销。
Call from the main thread. Scripts may touch the world (runcmd, reference methods); async works (HimDSL switches internally) but pays extra overhead.
saveScript:保存脚本 / saveScript: Save a Script
String code = "int main() {\n" +
" runcmd(\"CONSOLE\", \"say hello\");\n" +
"}\n";
boolean ok = api.saveScript("generated/hello.himdsl", code);
路径相对于 HimDSL 数据目录。子目录会自动创建。成功返回 true,任何 IO 异常返回 false。
Path is relative to the HimDSL data folder. Subdirectories are created automatically. Returns true on success, false on any IO exception.
这个方法的典型用途:
Typical uses:
-
动态生成脚本:根据配置或玩家输入生成
.himdsl文件。 -
备份/导出:把当前脚本内容写到新位置。
-
插件间集成:其他插件生成脚本,HimDSL 执行。
-
Dynamic generation: build
.himdslfiles from config or user input. -
Backup/export: copy script content to a new location.
-
Inter-plugin integration: another plugin writes, HimDSL runs.
注意:saveScript 不会自动执行脚本。写完文件后要显式调用 run。
Note: saveScript does not run the script. Call run explicitly after writing.
一个完整例子 / A Complete Example
其他插件根据玩家名生成并执行一个欢迎脚本:
Another plugin generates and runs a welcome script for a player:
public class MyPlugin extends JavaPlugin {
private HimDSLAPI himdsl;
@Override
public void onEnable() {
himdsl = Bukkit.getServicesManager().load(HimDSLAPI.class);
if (himdsl == null) {
getLogger().info("HimDSL 未安装,脚本功能已禁用");
}
}
public void welcomePlayer(String playerName) {
if (himdsl == null) return;
String code = "int main() {\n" +
" runcmd(\"CONSOLE\", \"say 欢迎 " + playerName + "!\");\n" +
"}\n";
String path = "generated/welcome_" + playerName + ".himdsl";
if (!himdsl.saveScript(path, code)) {
getLogger().warning("保存脚本失败");
return;
}
File file = new File(
Bukkit.getPluginManager().getPlugin("HimDSL").getDataFolder(),
path
);
HimDSLAPI.ExecutionResult r = himdsl.run(file);
if (!r.isSuccess()) {
getLogger().warning("执行脚本失败: " + r.getErrorMessage());
}
}
}
线程与生命周期 / Threading and Lifecycle
compile 和 saveScript 可以在任意线程调用——它们不触碰 Bukkit 状态。
compile and saveScript are thread-safe — they touch no Bukkit state.
run 建议在主线程调用。理由:
Call run from the main thread. Reasons:
-
脚本里的事件和定时任务默认在主线程注册。
-
脚本可以调用 GUI 和引用方法,都需要主线程。
-
HimDSL 的内部状态(函数表、环境)不是线程安全的。
-
Events and tasks register on the main thread.
-
Scripts may use GUIs and reference methods that require the main thread.
-
HimDSL's internal state (function tables, environments) is not thread-safe.
如果确实需要从异步调用,用 Bukkit 的 runTask 切回主线程:
If async is unavoidable, hop back to the main thread with Bukkit's runTask:
Bukkit.getScheduler().runTask(plugin, () -> {
api.run(script);
});
HimDSL 卸载时会清空所有已加载的函数和事件。插件不应在 HimDSL 卸载后继续调用 API。
HimDSL unload clears every loaded function and event. Do not call the API after HimDSL unloads.
小结 / Summary
-
用
Bukkit.getServicesManager().load(HimDSLAPI.class)获取。 -
在
plugin.yml中声明softdepend: [HimDSL]。 -
compile(file)只检查语法,返回CompileResult。 -
run(file)执行整个脚本,返回ExecutionResult。 -
saveScript(path, content)保存脚本,返回boolean。 -
三个方法都不抛异常,靠返回值判断。
-
run建议在主线程。 -
API 调用前确认 HimDSL 已加载。
-
Obtain via
Bukkit.getServicesManager().load(HimDSLAPI.class). -
Declare
softdepend: [HimDSL]inplugin.yml. -
compile(file)checks syntax; returnsCompileResult. -
run(file)executes the whole script; returnsExecutionResult. -
saveScript(path, content)saves a script; returnsboolean. -
None of them throw; check return values.
-
Call
runon the main thread. -
Verify HimDSL is loaded before calling.
下一步 / Next Steps
下一章 [自定义占位符 / Custom-Placeholders] 讲如何从你的插件向脚本暴露数据。
Next, [自定义占位符 / Custom-Placeholders] shows how to expose data from your plugin to scripts.