Skip to content

Use API wisely

Himxh edited this page Oct 4, 2026 · 1 revision

真的需要 API 吗? / Do You Really Need the API?

定位 / Positioning

这一章是扩展 API 部分的过滤层。在翻开 HimDSLAPI 之前,先想清楚一件事:

This chapter is the filter layer for the Extension API section. Before opening HimDSLAPI, settle one question:

你到底想让谁调用谁?

Who is calling whom?

方向搞反了,会用错工具,写出一堆不必要的 Java 代码。

Get the direction wrong and you will use the wrong tool, writing Java you did not need.


两个方向 / Two Directions

需求 需要 API 吗
脚本要调用其他插件 不需要——用脚本自身的 Java 互操作
其他插件要调用 HimDSL 需要——这才轮到 HimDSLAPI
Need API required?
Script calls another plugin No — use the script's Java interop
Another plugin calls HimDSL Yes — this is HimDSLAPI's territory

大部分人第一反应是"我想用 HimDSL 做点高级的,肯定要用 API"。但方向往往是反的——真正需要写 Java 的场景,比想象中少得多。

Most people assume "advanced HimDSL = API". Usually the direction is reversed — far fewer cases actually need Java.


场景一:脚本调用其他插件 / Scenario 1: Script Calls Another Plugin

这是最常见的需求,也是最不需要 API 的。

This is the most common need — and the one that needs the API least.

HimDSL 脚本本身就是 Java 互操作的入口。任何 public 的类、方法、字段,脚本都能直接访问。不用写一行 Java 代码。

A HimDSL script is itself a Java interop entry point. Any public class, method, or field is directly reachable. No Java code required.

用全限定名 new 对象 / Use the FQN to new an Object

// 创建其他插件的对象
var holder = new com.example.myplugin.DataHolder("steve", 5);
var config = new com.example.myplugin.MyConfig();

只要类名写全,不需要任何注册或声明。

Write the full class name; no registration or declaration needed.

直接调用静态方法 / Call Static Methods Directly

// 调用其他插件的静态工具方法
string formatted = com.example.myplugin.Utils.formatName("steve");
int result = com.example.myplugin.MathUtil.add(3, 7);

规则和调用 Bukkit 的静态方法完全相同——写全类名,点号,方法名,参数。

Identical to calling Bukkit statics — full class name, dot, method, arguments.

直接读静态字段 / Read Static Fields Directly

// 读其他插件的静态常量
int maxLevel = com.example.myplugin.Constants.MAX_LEVEL;
string prefix = com.example.myplugin.Constants.PREFIX;

举个完整例子 / A Complete Example

int main() {
    // 假设某插件提供静态工具
    int score = com.example.questplugin.QuestAPI.getScore(@p.uuid);

    // 假设某插件提供可 new 的对象
    var board = new com.example.scoreboard.ScoreboardBuilder();
    board.setTitle("积分榜");
    board.setLine(0, "你的分数: " + score);

    // 通过反射调用实例方法
    board.build();
}

整个脚本没有一行 Java,但完整地用上了其他插件的能力。

Zero Java written, yet the other plugin's capabilities are fully used.


什么时候这个方法会失效 / When This Fails

三种情况:

Three cases:

情况一:类不是 public / Not public

Java 的访问修饰符依然生效。private、包级私有、protected 的类和方法访问不到。

Java's access modifiers still apply. private, package-private, and protected members are unreachable.

情况二:需要注册回调 / Callback Registration Required

如果插件的 API 是"你实现一个接口,我稍后调用"的模式——比如注册事件监听器——脚本做不到。因为脚本没有"实现 Java 接口"的语法。

If the API follows "implement an interface, I call you later" — like registering a listener — the script cannot do it. Scripts have no syntax for implementing a Java interface.

例外:函数式接口例外。单个抽象方法的接口可以用 lambda 适配(见《函数式接口》)。

Exception: functional interfaces. Single-abstract-method interfaces adapt via lambda (see Functional Interfaces).

情况三:需要拿到插件的实例 / You Need the Plugin Instance

有些 API 是实例方法——你先要拿到插件对象:

Some APIs are instance methods — you first need the plugin object:

MyPlugin plugin = (MyPlugin) Bukkit.getPluginManager().getPlugin("MyPlugin");
plugin.doSomething();

HimDSL 脚本能做到:

A HimDSL script can:

var plugin = Bukkit.getPluginManager().getPlugin("MyPlugin");
plugin.doSomething();

如果 getPlugin 返回的是接口,方法调用会走到反射,正常工作。如果能拿到实例,这条路就通。

If getPlugin returns an interface, reflection resolves the method. If you can reach the instance, this path works.


场景二:其他插件调用 HimDSL / Scenario 2: Another Plugin Calls HimDSL

这才是 HimDSLAPI 真正存在的理由。

This is why HimDSLAPI exists.

触发时机不在脚本控制范围内时——比如"另一个插件在它的某个流程里,要执行一段 HimDSL 逻辑"——脚本自己无法感知。

When the trigger is outside the script's control — "another plugin, inside its own flow, wants a HimDSL script to run" — the script cannot sense this.

HimDSL 脚本只能被:

A HimDSL script can only be driven by:

  • Bukkit 事件(@EventHandler)。
  • 定时任务(@BukkitRunnable)。
  • GUI 交互。
  • /himdsl run 命令。
  • 服务器启动 / 关闭(onServerLoad.himdsl 等)。

如果触发源不在这份清单里,就得让对方插件来通知 HimDSL。这需要 Java 代码,需要 HimDSLAPI。

If the trigger is not in this list, the other plugin must notify HimDSL — Java code, HimDSLAPI.


判断标准 / Decision Rule

用下面三个问题判断:

Three questions:

  1. 触发时机是脚本能感知的吗?

    • 是(Bukkit 事件、定时器、GUI、命令)→ 不用 API。
    • 否 → 继续第 2 步。
  2. 触发时机是否可以改成"定时轮询"?

    • 可以(例如"每 5 秒查一次"能接受)→ 不用 API,写个 @BukkitRunnable。
    • 不可以(必须实时响应)→ 继续第 3 步。
  3. 能否让对方插件通过 PlaceholderAPI 暴露状态?

    • 可以 → 不用 API,脚本用 papi(...) 读。
    • 不可以(对方不提供 PAPI 扩展)→ 需要 API。
  4. Is the trigger something the script can sense?

    • Yes (Bukkit event, timer, GUI, command) → No API.
    • No → step 2.
  5. Can the trigger be turned into "polling"?

    • Yes ("check every 5 s" is acceptable) → No API; write a @BukkitRunnable.
    • No (must be real-time) → step 3.
  6. Can the other plugin expose state via PlaceholderAPI?

    • Yes → No API; read with papi(...).
    • No → API is justified.

API 真正必要的情况 / When the API Is Truly Needed

只有同时满足这三个条件:

Only when all three hold:

  • 触发时机不在 Bukkit 事件里。

  • 不能延迟(轮询不可接受)。

  • 对方插件不提供 PlaceholderAPI 扩展。

  • The trigger is not a Bukkit event.

  • No delay is acceptable (polling ruled out).

  • The other plugin has no PlaceholderAPI extension.

典型例子:

Typical examples:

  • 你的插件在自定义流程的中间要"询问 HimDSL"。

  • 你的插件动态生成脚本内容(用户在 GUI 里配规则,你翻译成脚本)。

  • 你的插件在服务器启动之前就要写入脚本。

  • Your plugin needs to "ask HimDSL" mid-flow.

  • Your plugin dynamically generates script content (GUI rules → script).

  • Your plugin writes scripts before server startup.

其他所有场景,都能用脚本自身的 Java 互操作、PlaceholderAPI、或普通事件系统解决。

Every other case is solvable with the script's Java interop, PlaceholderAPI, or the plain event system.


一个反面教材 / A Counter-Example

想做的事:脚本里读取某插件的玩家分数。

Goal: read a player's score from another plugin, inside a script.

用 API 的做法(过度) / The Over-Engineered Way

  1. 写一个 Java 插件。
  2. 用 HimDSLAPI.registerPlaceholder 覆盖一个内置类型。
  3. 脚本里调 $player(score)$。
  4. 影响所有脚本的 $player$ 行为。

几十行 Java,破坏性副作用。

Dozens of lines of Java, destructive side effects.

直接用引用的做法(正确) / The Right Way

int score = com.example.questplugin.QuestAPI.getScore(@p.uuid);

一行脚本,零副作用。

One line, zero side effects.

这个对比就是本章的全部要义。

This comparison is the whole point of this chapter.


常见误解 / Common Misunderstandings

误解一:"高级功能需要 API" / "Advanced = API"

不成立。HimDSL 脚本本身就能访问整个 Java 生态。用全限定名 + new + 静态方法,已经覆盖绝大多数需求。

False. HimDSL scripts reach the entire Java ecosystem. FQNs + new + static methods cover most needs.

误解二:"用 API 更正规" / "API Looks More Formal"

看方向。脚本调其他插件 = 用脚本语法。其他插件调脚本 = 用 API。方向反了,写再多代码也是错的。

Direction matters. Script → plugin = script syntax. Plugin → script = API. Reversed direction means wrong code.

误解三:"PlaceholderAPI 太麻烦,不如直接调 API" / "PAPI Is a Hassle"

恰恰相反。PAPI 扩展跨版本稳定,对脚本用户透明,不影响其他插件。它比 HimDSLAPI 更适合跨插件集成。

Opposite. PAPI extensions are version-stable, transparent to scripts, non-invasive. They beat HimDSLAPI for cross-plugin integration.

误解四:"写 Java 更高效" / "Java Is Faster"

看情况。脚本调一次静态方法的开销和 Java 调用同一量级(都走反射,HimDSL 已经缓存)。唯一"更高效"的场景是"每秒调用上万次"——这在服务器脚本里几乎不存在。

Depends. A single static call from a script costs the same order as Java (reflection, cached by HimDSL). "More efficient" only matters at ten-thousands-per-second rates — rare in server scripts.


小结 / Summary

  • 先问方向:脚本调其他插件,还是其他插件调脚本?

  • 脚本调其他插件 → 用全限定名 + new + 静态方法。不需要 API。

  • 其他插件调脚本 → 才轮到 HimDSLAPI。

  • 判断标准:触发时机是否在脚本控制内?能否改成轮询?对方是否提供 PAPI?

  • API 只在三种情况同时满足时才必要。

  • 不要为了"看起来正规"而写不必要的 Java。

  • Ask direction first: script → plugin, or plugin → script?

  • Script → plugin → FQN + new + statics. No API needed.

  • Plugin → script → HimDSLAPI's territory.

  • Decision: is the trigger script-sensible? Can it become polling? Does PAPI exist?

  • The API is needed only when all three conditions hold.

  • Do not write Java for the appearance of rigor.


下一步 / Next Steps

如果你确认了方向是"其他插件调 HimDSL",翻到 HimDSLAPI。

If you have confirmed the direction is "plugin → script", turn to HimDSLAPI.

如果确认方向是"脚本调其他插件",回到 [Java 互操作 / Java-Interop],那里讲了 new、静态方法、全限定名的完整用法。

If the direction is "script → plugin", return to [Java 互操作 / Java-Interop] for full usage of new, statics, and FQNs.


(第五十二章 · 前置章完 / End of Prerequisite Chapter 52)

HimDSL 文档 / Documentation

入门 / Getting Started

语言基础 / Language Basics

控制流 / Control Flow

函数 / Functions

数据结构 / Data Structures

自定义类型 / Custom Types

Minecraft 集成 / Minecraft Integration

事件与调度 / Events & Scheduling

GUI 系统 / GUI System

内置函数参考 / Built-ins Reference

进阶 / Advanced

扩展 API / Extension API

你真的需要 API 吗?/ Do you really need the API?

Clone this wiki locally