Repository navigation
Pitfalls
本章是速查汇总。每一条都能在前面找到详细解释。遇到问题时先在这里扫一眼。
This chapter is a lookup. Each entry is explained earlier. Scan here first when stuck.
| 陷阱 | 正确写法 |
|---|---|
int a[];(无初始化无长度) |
int a[5]; 或 int a[] = {...};
|
struct S { ... } 后忘分号 |
struct S { ... }; |
enum E { A, B } 后忘分号 |
enum E { A, B }; |
if (x) stmt1; stmt2; |
多条语句必须加 {}
|
Consumer<Player> c |
HimDSL 不支持泛型,用 var c
|
new Point() 用于 struct |
Point p; |
| Trap | Fix |
|---|---|
int a[]; |
int a[5]; or int a[] = {...};
|
Missing ; after struct S { ... }
|
Add it |
Missing ; after enum E { ... }
|
Add it |
if (x) stmt1; stmt2; |
Braces required for multiple statements |
Consumer<Player> c |
No generics in HimDSL; use var c
|
new Point() for a struct |
Point p; |
| 陷阱 | 说明 |
|---|---|
5 / 2 返回 2
|
整数除法截断;写 5.0 / 2 得 2.5
|
"" 在 if 里为真 |
空字符串不是假;用 s == "" 判断 |
int x = "hi"; 编译通过 |
类型检查是运行时的 |
toInt("abc") 返回 0
|
转换失败返回默认值,不报错 |
0.1 + 0.2 != 0.3 |
浮点精度问题;用 bigAdd
|
| Trap | Note |
|---|---|
5 / 2 returns 2
|
Integer division; write 5.0 / 2
|
"" is truthy in if
|
Compare with s == ""
|
int x = "hi"; compiles |
Type checks are runtime |
toInt("abc") returns 0
|
Failed conversion yields default |
0.1 + 0.2 != 0.3 |
Float precision; use bigAdd
|
| 陷阱 | 说明 |
|---|---|
s.replace(a, b) 后 s 不变 |
字符串不可变,要赋回 |
"a.b".split(".") 返回空 |
. 是正则字符,用 "\\\\."
|
s.length(无括号) |
方法必须带 ():s.length()
|
"a\\nb" 在聊天里不换行 |
Minecraft 聊天不渲染换行 |
| Trap | Note |
|---|---|
s.replace(a, b) leaves s
|
Strings are immutable; reassign |
"a.b".split(".") returns empty |
. is regex; use "\\\\."
|
s.length (no parens) |
Method call needs ()
|
"a\\nb" does not wrap in chat |
Chat does not render newlines |
| 陷阱 | 说明 |
|---|---|
list() 创建列表 |
用 vector()
|
map.size() |
Map 没有 size();用 isEmpty()
|
set.get(0) |
Set 无下标访问 |
stack.pop() on empty |
空容器上 pop / poll / peek 报错 |
queue.push(x) |
队列用 offer
|
list.remove(0) 和 list.remove(x)
|
同名不同行为;注意参数类型 |
| Trap | Note |
|---|---|
list() to create a list |
Use vector()
|
map.size() |
No size() on maps; use isEmpty()
|
set.get(0) |
Sets have no indices |
stack.pop() on empty |
pop / poll / peek on empty errors |
queue.push(x) |
Queues use offer
|
list.remove(0) vs list.remove(x)
|
Same name, different behavior |
| 陷阱 | 说明 |
|---|---|
@a[...] |
@a 不支持过滤器 |
@s in main
|
返回 null;只在事件、GUI、lambda 里有效 |
@p[distance=..10] 无原点 |
在 main 里没有执行原点,不匹配 |
@e 不加过滤 |
遍历所有世界的实体,很重 |
@e[...] 返回 null
|
返回空列表,不是 null;用 size() == 0
|
| Trap | Note |
|---|---|
@a[...] |
@a takes no filters |
@s in main
|
Returns null; only in events/GUI/lambdas |
@p[distance=..10] without origin |
No origin in main
|
Unfiltered @e
|
Very heavy |
@e[...] returns null
|
Returns an empty list; check size() == 0
|
| 陷阱 | 说明 |
|---|---|
$player(p, naem)$ |
拼错返回 null,不报错 |
$player(p, health)$ |
用 hp,不是 health
|
$player(@p, name)$ |
第一个参数是变量名,不能是选择器 |
papi("unknown") 返回空 |
PlaceholderAPI 未装或变量名错 |
| Trap | Note |
|---|---|
$player(p, naem)$ |
Typo returns null, no error |
$player(p, health)$ |
Use hp, not health
|
$player(@p, name)$ |
First argument is a variable name |
papi("unknown") returns empty |
PAPI missing or wrong key |
建议:能用引用(p.name)就别用占位符。引用拼错会报错。
Advice: prefer references (p.name) over placeholders. References error on typos.
| 陷阱 | 说明 |
|---|---|
写了 @EventHandler 但没反应 |
必须 start("函数名") |
start 已在运行的任务 |
报错;先 stop
|
| 事件函数重载 |
start 无法分辨,避免 |
@BukkitRunnable 不带 sche
|
异步执行,不能直接操作游戏 |
sleep 在 main 里 |
阻塞主线程,卡服 |
sleep 在 @BukkitRunnable
|
同上 |
| Trap | Note |
|---|---|
@EventHandler has no effect |
Must start("name") |
start on running task |
Errors; stop first |
| Overloaded event functions |
start cannot resolve; avoid |
@BukkitRunnable without sche
|
Async; cannot touch game directly |
sleep in main
|
Blocks main thread |
sleep in scheduled task |
Same |
| 陷阱 | 说明 |
|---|---|
| 填了槽位但界面空 | open 前要 updateAll |
修改 slot.name 后没变化 |
手动 update |
slot.lore[0] = "x" |
无效;读-改-写回 |
点击回调里用 @p
|
用 @s(点击者) |
| Shift 点击无反应 | 未注册 onShiftLeftClick,不回退 |
onClose 里打开同一 GUI |
死循环 |
| Trap | Note |
|---|---|
| Slots filled, GUI empty | updateAll before open |
slot.name changed, no visible effect |
Manually update |
slot.lore[0] = "x" |
Read-modify-reassign |
@p inside a click callback |
Use @s (the clicker) |
| Shift-click does nothing | Register onShiftLeftClick; no fallback |
Reopening same GUI in onClose
|
Infinite loop |
| 陷阱 | 说明 |
|---|---|
fwritelines 当追加 |
覆盖;追加用 fopen(..., "a")
|
相对路径 ../x
|
不能逃逸插件目录 |
fopen 后忘记 fclose
|
文件保持打开 |
runcmd 命令带斜杠 |
不带前导 /
|
runcmd 玩家名拼错 |
静默丢弃 |
| Trap | Note |
|---|---|
fwritelines as append |
Overwrites; use fopen(..., "a")
|
../x path |
Cannot escape |
Missing fclose
|
File stays open |
runcmd with slash |
No leading /
|
runcmd misspelled player |
Silently dropped |
除了具体陷阱,下面的习惯能让脚本更好维护:
Besides specific traps, these habits improve maintainability:
string name = p.name; // ✓
string name = $player(p, name)$; // 也可以,但拼错不报错
int n = list.size(); // ✓
int n = size(list); // 兼容但不推荐
// 单处使用
slot.onLeftClick = () -> { doWork(); }; // ✓
// 多处使用
void doWork() { ... } // ✓ 具名函数
slot1.onLeftClick = () -> { doWork(); };
slot2.onLeftClick = () -> { doWork(); };
lambda 只在"一次性回调"里用。多处复用时,具名函数更清楚。
Lambda for one-shot callbacks. For repeated use, named functions are clearer.
// ✗
int result;
void compute() { result = 42; }
// ✓
int compute() { return 42; }
不要把所有逻辑塞进一个文件。按功能拆分:welcome.himdsl、shop.himdsl、autosave.himdsl。
Do not cram everything into one file. Split by function: welcome.himdsl, shop.himdsl, autosave.himdsl.
-
本章是所有陷阱的速查表。
-
引用 > 占位符;方法形式 > 函数形式;具名函数 > 内联 lambda。
-
返回值 > 全局变量。
-
一个脚本做一件事。
-
A cheat sheet of all traps.
-
References > placeholders; method > function form; named > inline lambda.
-
Return values > globals.
-
One script, one purpose.
进阶部分到此结束。五章覆盖了:类解析、枚举解析、作用域与闭包、调试、常见陷阱。
The Advanced section ends here. Five chapters: class resolution, enum resolution, scopes and closures, debugging, and pitfalls.
日常脚本不需要深究这些机制。它们存在的意义是:当你遇到"为什么这样不生效"的时候,有个地方能查到。
Daily scripts ignore these internals. They exist so that, when "why doesn't this work" strikes, there is a place to look.
下一部分进入扩展 API。第十章 HimDSLAPI 讲如何从其他 Java 插件调用 HimDSL。
The next part covers the Extension API. Chapter HimDSLAPI shows how other Java plugins call HimDSL.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep