注册点
注册点是插件向编辑器挂接功能的位置。全部在 Register(host) 中以 host.Add…(数据类型) 调用。数据类型为 C# record。有默认值的字段可以用命名参数(Order: 600)传入。
| 注册点 | 数据类型 | SDK | 编辑器界面 |
|---|---|---|---|
AddMenuItem | NpMenuItem | 1.0 | 菜单栏 |
AddQuickAddItem | NpQuickAdd | 1.0 | 主工具栏「添加」 |
AddCommand | NpCommand | 1.0 | 「控制台」面板 |
AddImporter · AddExporter | NpFileFormat | 1.0 | 「文件 › 导入: …」 · 「构建 › 导出: …」 |
AddContentTab | NpContentTab | 1.0 | 下方区域面板(「窗口」菜单) |
AddMode | NpMode | 1.0 | 模式栏 · 工具面板 · 视口点击 |
AddActorType | NpActorType | 1.0 | 大纲「类型」列 |
AddCellGuard | Func<int,int,int,bool> | 1.0 | 所有方块编辑 |
AddSymmetry | Func<IReadOnlyList<NpBlock>, IEnumerable<NpBlock>> | 1.0 | 放置 · 破坏 · 笔刷 · 形状 |
AddShotScenario | NpShot | 1.0 | --np-shot=<id> |
AddShortcut | NpShortcut | 1.1 | 「工具 › 快捷键…」 |
AddSceneEvent | NpSceneEvent | 1.2 | 世界逻辑 — 添加世界逻辑 type |
以下是通用规则。
Id在编辑器内会加上ext.<插件 id>.。只要在插件内部不重复即可。Id(命令为Name,Actor 类型为Kind)为空或执行函数(Run·Spawn·Build)为null时,注册抛出异常。此时整个插件都不会启用。- 注册的回调中发生异常时,该插件被隔离。
Order是同一位置内的顺序,越小越靠前。默认值为 500。- 界面文字中不要使用表情符号 · 图形字符。菜单 · 标签页 · 模式名称中的图形字符会在界面上被去除。图标通过
Icon字段以图标名称(prefab·block·light·trigger·logic…)指定。
AddMenuItem — 菜单项
Section titled “AddMenuItem — 菜单项”public sealed record NpMenuItem(string Id, string Menu, string Label, Action Run, string Shortcut = "", int Order = 500);| 字段 | 说明 |
|---|---|
Id | 菜单项 id |
Menu | "파일" · "편집" · "창" · "도구" · "빌드" · "도움말"。若为其他名称,则在「帮助」前新建菜单。 |
Label | 菜单中显示的文字 |
Run | 点击时执行 |
Shortcut | 快捷键字符串(例 "Ctrl+Alt+H")。若为可识别的键,则显示在菜单文字旁,按下即执行,并可在「工具 › 快捷键…」中更改。 |
Order | 菜单内顺序。百位发生变化处会出现分隔线(例 499 与 500 之间)。 |
host.AddMenuItem(new NpMenuItem("hollow", "도구", "선택 속 비우기", () =>{ if (host.World.Selection is not { } b) { host.Message("먼저 영역을 고르세요"); return; } int n = host.World.Edit("속 비우기", e => { for (int y = b.Min.Y + 1; y < b.Max.Y; y++) for (int z = b.Min.Z + 1; z < b.Max.Z; z++) for (int x = b.Min.X + 1; x < b.Max.X; x++) e.Clear(x, y, z); }); host.Message($"{n:N0}칸 비움");}, Order: 550));- 「窗口」菜单的菜单项挂在面板列表下方。
- 具有导出性质的菜单项放在「构建」中。
AddQuickAddItem — 快速添加
Section titled “AddQuickAddItem — 快速添加”public sealed record NpQuickAdd(string Id, string Label, string Category, Action<NpQuickAddContext> Spawn, string Keywords = "", int Order = 500, string Icon = "", string IconState = "");public sealed record NpQuickAddContext(INpWorld World, NpCell Place);| 字段 | 说明 |
|---|---|
Label | 列表中显示的名称 |
Category | 分类名称。若为新名称,则在内置分类之后新建分类。 |
Spawn | 选中时执行。ctx.Place = 放置的格(鼠标下方方块面外侧的格,没有时为画面中央前方) |
Keywords | 搜索词(空格分隔)。同时写入韩语 · 英语便于查找。 |
Icon | 图标名称(例 "prefab" · "light") |
IconState | 作为图标绘制的方块状态字符串。若有,则优先于 Icon 使用。 |
host.AddQuickAddItem(new NpQuickAdd("lamp_post", "가로등", "도로", ctx => ctx.World.Edit("가로등", e => { for (int y = 0; y < 3; y++) e.Set(ctx.Place.X, ctx.Place.Y + y, ctx.Place.Z, "minecraft:dark_oak_fence"); e.Set(ctx.Place.X, ctx.Place.Y + 3, ctx.Place.Z, "minecraft:lantern[hanging=false]"); }), Keywords: "lamp light 가로등", Icon: "light", IconState: "minecraft:lantern"));AddCommand — 控制台命令
Section titled “AddCommand — 控制台命令”public sealed record NpCommand(string Name, string Usage, string Help, Func<string[], string> Run);| 字段 | 说明 |
|---|---|
Name | 命令名称。不含空格。由于不加前缀,请在前面加上自己的名称(例 road_count)。 |
Usage | 一行用法(例 "road_count [블록 id]") |
Help | 一行说明 |
Run | 参数(名称后的各个词) → 显示在控制台中的结果字符串 |
host.AddCommand(new NpCommand("road_count", "road_count [블록 id]", "선택 안에서 그 블록 수를 셈", args =>{ string id = args.Length > 0 ? args[0] : "minecraft:stone"; long n = host.World.Blocks(host.World.Selection).LongCount(b => b.State.StartsWith(id)); return $"{id}: {n:N0}칸";}));- 若名称已存在(内置 · 其他插件),则该命令不会挂接。
Run中发生异常时,控制台显示为失败,插件被隔离。
AddImporter · AddExporter — 文件格式
Section titled “AddImporter · AddExporter — 文件格式”public sealed record NpFileFormat(string Id, string Label, string[] Extensions, Action<string> Run, int Order = 500);| 字段 | 说明 |
|---|---|
Label | 菜单文字。显示为「文件 › 导入: Label」 · 「构建 › 导出: Label」。 |
Extensions | 扩展名列表(不含点,例 new[] { "csv" })。用于文件对话框的过滤。 |
Run | 接收用户所选文件的完整路径。 |
Order | 菜单内顺序 |
host.AddExporter(new NpFileFormat("road_stats", "블록 통계 CSV", new[] { "csv" }, path =>{ var rows = host.World.Blocks(host.World.Selection) .GroupBy(b => b.State.Split('[')[0]) .OrderByDescending(g => g.Count()) .Select(g => $"{g.Key},{g.Count()}"); File.WriteAllLines(path, rows.Prepend("block,count"), new System.Text.UTF8Encoding(true));}));- 导出对话框的默认文件名为
<世界名称>.<第一个扩展名>。 - 导入时更改方块,也要合并在一次
World.Edit中。
AddContentTab — 面板
Section titled “AddContentTab — 面板”public sealed record NpContentTab(string Id, string Label, Func<NpUi> Build, int Order = 500);| 字段 | 说明 |
|---|---|
Label | 面板标题。「窗口」菜单的面板列表中也以此名称显示。 |
Build | 面板内容(NpUi)。启用插件时调用一次。 |
Order | 面板列表顺序 |
host.AddContentTab(new NpContentTab("panel", "도로", () => new NpUi() .Title("도로 만들기") .Number("폭", _width, 1, 9, 1, v => _width = (int)v) .Check("가로등", _lamps, v => _lamps = v) .Button("선택 영역에 깔기", () => host.Message($"폭 {_width}"))));- 面板以关闭状态生成在下方区域。由用户从「窗口」菜单打开。打开后可以拖到其他区域,或拖出为浮动窗口。
- 图标为
plugin图案。 NpUi的用法见面板 UI (NpUi)。
AddMode — 模式
Section titled “AddMode — 模式”public sealed record NpMode(string Id, string Label, Func<NpUi>? Panel = null, Func<NpClick, bool>? OnClick = null, Action? Enter = null, Action? Exit = null, string Shortcut = "", int Order = 500);public sealed record NpClick(NpCell Hit, NpCell Place, bool Shift, bool Ctrl);| 字段 | 说明 |
|---|---|
Label | 模式名称(模式栏工具提示 · 工具面板标题) |
Panel | 工具面板中显示的内容。首次显示时创建一次并重复使用。没有时只显示标题。 |
OnClick | 视口左键点击。Hit = 命中的方块格,Place = 该面外侧的格(放置位置)。处理后返回 true。 |
Enter · Exit | 进入模式时 · 离开模式时 |
Shortcut | 切换到该模式的快捷键字符串 |
Order | 插件模式之间的顺序。插件模式始终排在内置模式之后。 |
host.AddMode(new NpMode("flag", "깃발 꽂기", Panel: () => new NpUi().Title("깃발").Label("왼쪽 클릭 = 깃발 · Shift+클릭 = 지우기"), OnClick: c => { var p = c.Shift ? c.Hit : c.Place; host.World.Edit(c.Shift ? "깃발 지우기" : "깃발", e => { if (c.Shift) { for (int i = 0; i < 3; i++) e.Clear(p.X, p.Y + i, p.Z); return; } e.Set(p.X, p.Y, p.Z, "minecraft:oak_fence"); e.Set(p.X, p.Y + 1, p.Z, "minecraft:oak_fence"); e.Set(p.X, p.Y + 2, p.Z, "minecraft:red_wool"); }); return true; }, Exit: () => host.Draw.Clear()));- 若有
OnClick,该模式下视口的所有左键点击都交给OnClick,不执行默认的方块放置。 - 未命中方块的点击(天空)不会调用
OnClick。 - 目前还无法接收拖动(按住移动),只接收点击。
- 模式栏前 8 个之后的模式会放入「更多」中。插件模式通常位于「更多」中。
- 禁用插件时若正在使用该模式,则返回方块笔刷模式。
AddActorType — Actor 类型
Section titled “AddActorType — Actor 类型”public sealed record NpActorType(string Kind, string Label, string Color = "#9a9a9a");| 字段 | 说明 |
|---|---|
Kind | Actor kind 字符串。在前面加上自己的名称(例 "myroad.zone")。 |
Label | 大纲「类型」列中的文字 |
Color | 「类型」列的颜色 "#rrggbb"。无法识别时为灰色。 |
host.AddActorType(new NpActorType("myroad.zone", "도로 구역", "#44aaff"));- 决定该 kind 的 Actor 显示在大纲中时的文字和颜色。
- SDK 中目前还没有创建 Actor 的 API。
AddCellGuard — 格守卫
Section titled “AddCellGuard — 格守卫”void AddCellGuard(Func<int, int, int, bool> guard);返回 true 的格不能被任何编辑更改。适用于笔刷 · 形状 · 填充 · 控制台命令 · 其他插件的 World.Edit。撤销 · 重做不做检查。
host.AddCellGuard((x, y, z) => y < 0); // y 0 以下不可更改- 有多个守卫时,只要有一个返回
true就会阻止。 - 每个格都会调用。请写得非常轻量(字典 · 框比较程度)。
AddSymmetry — 对称
Section titled “AddSymmetry — 对称”void AddSymmetry(Func<IReadOnlyList<NpBlock>, IEnumerable<NpBlock>> expand);接收用户编辑(放置 · 破坏 · 笔刷 · 形状 · 拖动框 · 绘制)要更改的格列表,返回扩展后的列表。接在内置对称之后执行。
host.AddSymmetry(cells => cells.Concat(cells.Select(b => b with { X = -b.X }))); // 以 X=0 面镜像- 返回时要包含原来的格。若省略,原来的编辑会消失。
- 改为空气的格(破坏)的
State为"minecraft:air"。
AddShotScenario — 画面验证
Section titled “AddShotScenario — 画面验证”public sealed record NpShot(string Id, Func<INpShotApi, Task> Run);INpShotApi 成员 | 说明 |
|---|---|
World | 世界(INpWorld) |
LookAt(float ex, float ey, float ez, float tx, float ty, float tz) | 将相机设为从眼睛位置 → 看向目标点 |
Frames(int n) | 等待 n 帧(await) |
Check(bool ok, string what) | 记录一项判定(PASS/FAIL) |
Shot(string name) | 将画面保存为 PNG(await) |
示例、运行方法和限制见测试与调试。
AddShortcut — 快捷键
Section titled “AddShortcut — 快捷键”public sealed record NpShortcut(string Id, string Label, string Key, Action Run, string Mode = "");| 字段 | 说明 |
|---|---|
Id | 快捷键 id。用户更改的键以此 id 保存。 |
Label | 快捷键窗口中显示的名称。在前面加上插件名称便于查找(例 "도로: 속 비우기")。 |
Key | 默认键字符串。遵循下表。 |
Run | 按下时执行 |
Mode | "" = 任何位置。模式 id = 仅在该模式下。若是自己的模式,直接使用 AddMode 中写的 id。 |
host.AddShortcut(new NpShortcut("hollow_key", "도로: 선택 속 비우기", "Ctrl+Alt+H", Hollow));host.AddShortcut(new NpShortcut("flag_undo", "깃발: 마지막 지우기", "Shift+J", RemoveLast, Mode: "flag"));| 键字符串 | 可识别 |
|---|---|
Ctrl+Alt+H · ctrl + alt + h · Cmd+K(= Ctrl) | 是 |
Shift+F5 · Ctrl+Enter · Alt+Space · Ctrl+[ | 是 |
J(不带修饰键的单个键) | 是。容易与内置键冲突,不推荐。 |
1~8 · W/E/R · Ctrl++ | 否 → 注册异常 → 插件无法启用 |
- 键 =
Ctrl·Alt·Shift加一个键。键名为单个字母 · 数字、F1~F24,或Enter·Space·Delete·Esc等名称。 - 用户在「工具 › 快捷键…」(Ctrl+Alt+K)中更改键。更改后的键在重新启用插件后依然保留。
- 与其他键冲突时也会注册。在快捷键窗口中以红色显示,并记录到输出日志。
- 键相同时,模式专用键优先于任何位置键。编辑器固定键 · 默认键(Ctrl+Z · F1~F7 等)优先。