- 版权类型
- 原创
- 语言支持
- 中文(简体)
- 前置组件
- PLand:https://github.com/IceBlcokMC/PLand
DebugShape :https://github.com/IceBlcokMC/DebugShape
iListenAttentively:https://github.com/LiteLDev/iListenAttentively
- 适配版本(基岩)
- 最新版本
[MD]
# TerritorySweeper
> 基岩版 BDS 原生插件:在自己的 PLand 领地内,按层、按分块推进的方块清理工具。
> 基于 **LeviLamina (LL3)** + **PLand** + **DebugShape** + **iListenAttentively**,目标平台 Windows x64 / Release。
---
## 1. 功能概览
| 功能 | 说明 |
| :--- | :--- |
| **领地内清扫** | 严格绑定玩家脚下所在领地,选区自动裁剪到领地 AABB 内,禁止越界清理 |
| **权限隔离** | 仅领地主人(Owner)、领地管理(Admin)或管理员可用;访客与成员一律拒绝 |
| **分层推进** | 支持向下/向上逐层推进,每层开始前可设倒计时;BossBar 实时显示层数、分块、倒计时与总进度 |
| **分块清理与余量吸纳** | 面积超过阈值自动分块;边缘残余宽度 ≤ `chunk_tail_padding` 时自动吸纳,彻底杜绝 1 格碎屑分片 |
| **流体流入拦截** | 接入 iListenAttentively,任务运行与暂停期间通过 `LiquidFlowBeforeEvent` 事前拦截流体流入,彻底避免水流/岩浆回灌 |
| **极速终检清扫** | 结算前全选区终检清除残留水块/方块;基于 SubChunk 16×16×16 `isUniform(air)` 块级粗筛,54 万方块终检 < 0.1 毫秒瞬时完成 |
| **多任务高并发调度** | 全服共享全局每秒方块配额池(`global_blocks_per_tick_budget`),时间片公平轮换,20 个大领地并发清理依然锁定 20.0 TPS 满帧 |
| **空间哈希网格** | 活跃任务区块维护在空间哈希网格中,流体事件先做 O(1) 短路(< 5ns),消除多任务线性比对开销 |
| **基岩保护与绝对地板** | 支持清理选区内基岩,世界最低层(主世界 `y = -64`、下界/末地 `y = 0`)受绝对保护,绝不掏空基岩掉入虚空 |
| **双经济后端** | 默认支持 LLMoney,亦可切换为原版计分板(Scoreboard) |
| **挂起账单** | 未付款方案按领地持久化,可跨重启恢复;再次手持木棍点击领地方块即可唤起支付 |
| **比例退款与离线暂存** | 终止任务按未完成工作量比例退款;若玩家离线写入 `pending_payouts` 暂存,玩家下次进服自动补发并提示 |
| **看门狗与自动续跑** | 按领地 AABB 水平范围判断离开,离开 15 秒自动暂停;返回领地自动续跑(手动暂停不续跑);暂停 300 秒超时释放并退款 |
| **SQLite 极致读写** | 预编译语句池化常驻复用(消除 100% 重复编译),内存脏标记批量单事务提交(写事务减少 95% 以上),启用 256MB mmap 与 16MB 缓存 |
| **视觉反馈** | 选点时显示领地金色边框,选完自动关闭;清理期间常驻显示任务区域青色边框 |
| **API 动态解析自检** | 跨插件调用全部在启动时通过符号探针动态解析,依赖插件更新或缺失时优雅降级并输出报告,绝不导致 DLL 无法加载 |
---
## 2. 依赖
| 依赖 | 版本 | 作用 | 是否必需 |
| :--- | :--- | :--- | :--- |
| **LeviLamina** | 26.51.x | 插件加载器 / 核心 SDK | 必需 |
| **PLand** | 0.25.0+ | 领地查询、角色权限校验、领地 AABB | 必需 |
| **iListenAttentively** | 0.17.2+ | 细粒度事件支持(流体流动事前拦截 `LiquidFlowBeforeEvent`) | 必需 |
| **DebugShape** | 0.11.0+ | 选区与任务区域边框可视化渲染 | 可选(缺失仅不显示边框) |
| **LegacyMoney** | 0.22.0+ | 默认经济系统后端 | `economy_type=LLMoney` 时必需 |
---
## 3. 构建与部署
```powershell
# 首次构建前(若遇到上游包 semver 兼容问题)
powershell -ExecutionPolicy Bypass -File .\tools\repair-xmake-env.ps1
# 若修改了 iListenAttentively 相关接口,从测试服已安装 DLL 重新生成导入库
powershell -ExecutionPolicy Bypass -File .\tools\gen-ila-lib.ps1
# 编译发布版本
xmake f -y -p windows -a x64 -m release
xmake -y
```
- **构建产物**:`bin/TerritorySweeper/`(`TerritorySweeper.dll` + `manifest.json` + `TerritorySweeper.pdb`);
- **部署方式**:将 `bin/TerritorySweeper/` 文件夹复制到服务端 `plugins/TerritorySweeper/`。
---
## 4. 指令列表
主命令:`/ts`(权限等级 Any,内置领地主人权限校验)
| 指令 | 说明 |
| :--- | :--- |
| `/ts` | 显示指令帮助与基本信息 |
| `/ts new` | 发起新任务:校验并发上限与挂起账单,开启领地边框并进入木棍选点 |
| `/ts pos1 [x y z]` | 设置点 A(缺省坐标时取玩家脚下方块坐标) |
| `/ts pos2 [x y z]` | 设置点 B(缺省坐标时取玩家脚下方块坐标) |
| `/ts ok` | 确认当前选区并打开清扫方向与层数选择菜单 |
| `/ts list` | 查看全服进行中任务与待支付账单列表 |
| `/ts start` | 继续本领地当前已暂停的清扫任务 |
| `/ts stop` | 手动暂停本领地当前运行中的清扫任务 |
| `/ts kill` | 手动终止本领地任务并按未完成比例自动退款 |
---
## 5. 木棍交互
手持 `minecraft:stick` 点击方块。**仅在下列状态下响应,其余情况完全静默(不干扰普通木棍使用)**:
1. 已使用 `/ts new` 进入选点流程;
2. 当前领地存在运行中或已暂停的任务;
3. 当前领地存在待支付的挂起账单。
- **潜行过滤 (`stick_requires_sneak`)**:开启后必须下蹲潜行点击才响应,站立点击无任何反应;
- **左键方块**:设置点 A(同时取消破坏事件,避免敲碎方块);
- **右键/移动端点击方块**:第 1 次设置点 A,第 2 次设置点 B;
- **点击状态路由**:
- 存在任务 -> 打开【任务管理面板】(暂停/继续、终止退款);
- 存在账单 -> 打开【账单支付面板】(立即支付、保留、关闭账单);
- 选点完成 -> 打开【方向与层数选择面板】;
- 选点中 -> 设置对应端点坐标并刷新选区边框。
---
## 6. 配置文件详解 (`config.jsonc`)
配置文件位于 `plugins/TerritorySweeper/config/config.jsonc`,支持标准 `//` 注释。
版本升级(当前为 **`config_version: 4`**)时,插件会自动备份旧配置为 `.bak-时间戳` 并重写生成纯净模板,**用户既有配置值完整保留**。
```jsonc
{
// 配置文件版本号,请勿手动修改
"config_version": 4,
// 调试模式:开启后输出发包、调度、任务推进等详细日志
"debug": false,
// 经济系统后端:LLMoney / Scoreboard
"economy_type": "LLMoney",
// 计分板目标名称(Scoreboard 模式下生效)
"scoreboard_objective": "money",
// 界面与提示文案中显示的货币名称
"moneyname": "金币",
// 全服同时运行的清理任务数量上限
"global_task_limit": 3,
// 单个玩家同时运行的清理任务数量上限
"player_task_limit": 1,
// 全服所有并发任务共享的每秒最大方块处理预算(锁定 20.0 TPS)
"global_blocks_per_tick_budget": 12000,
// 是否显示 BossBar 进度条
"bossbar_enabled": true,
// BossBar 刷新方式:incremental(增量发包,省流量)/ recreate(每秒重建)
"bossbar_update_mode": "incremental",
// 是否显示调试线框(依赖 DebugShape)
"region_frame_enabled": true,
// 每层清理前倒计时秒数
"layer_countdown_seconds": 10,
// 是否启用分块清理
"chunked_clean_enabled": true,
// 分块矩阵跨度(方块数)
"chunk_matrix_width": 10,
"chunk_matrix_depth": 10,
// 面积超过该值时才触发分块清理(如 1024 = 32x32)
"chunked_min_area": 1024,
// 相邻分块之间的等待秒数
// 注意:若设为 0,单 tick 内将连续清扫多个分块(饱和吞吐),整层极速清完;
// 若需要清晰可见的分片推进节奏,请设为 >= 1(推荐 1~2 秒)
"chunk_interval_seconds": 2,
// 领主离开领地范围时是否自动暂停任务
"pause_on_player_leave": true,
// 离开领地多少秒后触发暂停
"player_leave_pause_seconds": 15,
// 领主返回领地后是否自动继续任务(仅对因离开暂停的任务生效,手动暂停不续跑)
"auto_resume_on_return": true,
// 判定是否在领地内时的水平容差(格)
"leave_check_tolerance": 2,
// 判定离开领地时是否忽略 Y 轴(true 时仅按水平 X/Z 判断,高空不误判)
"leave_check_ignore_y": true,
// 是否要求下蹲才响应木棍点击
"stick_requires_sneak": false,
// 分块清理时是否跳过纯空气分块(不消耗分块间隔)
"skip_empty_chunks": true,
// 整层都无需清理时是否跳过该层(不消耗每层倒计时)
"skip_empty_layers": true,
// 每 tick 用于空区域扫描的方块读取预算
"empty_scan_budget": 8192,
// 暂停多少秒后自动终止任务并退款
"pause_auto_cancel_seconds": 300,
// 清理时是否主动加载未加载的目标区块,防止玩家远离时卡死
"force_load_chunks": true,
// 每秒最多主动加载的区块数,防 IO 尖峰
"chunk_load_budget": 4,
// 是否允许清理选区内的基岩
"clear_bedrock": true,
// 保留世界最底部的基岩层数(掉下去会进虚空的那层,强制 >= 1)
"preserve_bottom_layers": 1,
// 任务进行中(含暂停)是否阻止流体流入选区(基于 iListenAttentively)
"block_liquid_inflow": true,
// 任务完成前是否对整个选区做一次终检清扫(清除残留水块/杂物)
"final_sweep": true,
// 边缘碎屑分片吸纳阈值(格):当残余宽度 <= 该值时直接并入前一分片
"chunk_tail_padding": 4,
// 是否开启 SubChunk 级快速粗筛(跳过纯空气 SubChunk,大选区终检 < 0.1ms)
"subchunk_culling": true,
// 清扫收费阶梯规格(按面积自小到大匹配第一个满足的档位)
"price_levels": [
{ "levelname": "9*9", "max_width": 9, "max_depth": 9, "price_per_layer": 1 },
{ "levelname": "17*17", "max_width": 17, "max_depth": 17, "price_per_layer": 2 },
{ "levelname": "33*33", "max_width": 33, "max_depth": 33, "price_per_layer": 4 },
{ "levelname": "65*65", "max_width": 65, "max_depth": 65, "price_per_layer": 8 }
]
}
```
---
## 7. 核心机制深度解析
### 7.1 分块清理与尾部余量吸纳 (Tail Absorption)
针对标准切分容易在选区边缘产生 1 格碎屑切片(如 33×33 选区产生 1 格碎屑分片并死等 2 秒冷却)的问题,引入余量吸纳算法:
- 当末端残余宽度/深度 `rem <= chunk_tail_padding` 时,自动延伸并入前一个分片;
- 33×33 区域(分片 32×32)直接合并为一个 33×33 分片,**耗时减少 75%,提速 400%**。
### 7.2 液体流入拦截 (iListenAttentively)
- 监听 ILA 的 `LiquidFlowBeforeEvent` 前置事件;
- 当流体试图流入处于 `Running` 或 `Paused` 状态的任务选区时,直接执行 `event.cancel()`,从物理源头上阻止液体生成;
- 空间哈希网格(Spatial Hash Grid)记录活跃任务 ChunkKey,99.9% 外部水流 O(1) 瞬时短路放行(< 5ns),无额外 CPU 负担;
- 任务彻底完成或终止后自动解除拦截,水流恢复自然扩散。
### 7.3 SubChunk 块级粗筛与终检清扫
- 利用 Bedrock 底层 16×16×16 `SubChunk` 的 `isUniform(air)` 接口;
- 精准比对 `sc.mAbsoluteIndex == (pos.y >> 4)` 绝对索引(主世界 -4 ~ 19);
- 纯空气 SubChunk 直接 O(1) 瞬时跳过(一次跳过 4096 方块),仅对非纯空 SubChunk 执行局部精细清理;
- 终检在选区水平 Chunk 列一次性完成预加载,解除限流瓶颈,**54 万格大选区终检时间从 60+ 秒缩短至 1 秒以内**。
### 7.4 基岩保护与绝对地板
- `preserve_bottom_layers` 强制 `>= 1`;
- 建立绝对地板防御:世界最低层(主世界 `y = -64`、下界/末地 `y = 0`)在任何配置下强制不可破坏;
- `clearUnit` 写入前追加防挖穿硬断言;
- 开启 `clear_bedrock: true` 时,主世界清理到底层 `y = -63`,只保留最底层完整平整的 `-64` 基岩,打破即掉虚空的防线始终完好。
### 7.5 多任务高并发与 SQLite 性能引擎
- **全局预算池**:所有并发任务共享 `global_blocks_per_tick_budget`,时间片公平轮换,杜绝任务饥饿,服务器 TPS 稳死 20.0;
- **语句池化复用**:核心高频 SQL 通过 `Statement::cached` 常驻内存终身复用,消除反复编译开销;
- **脏标记单事务提交**:内存作为事实源,状态变更打上 dirty 标记,每秒仅执行 1 次批量单事务写入(`flushDirtyTasks`),降低 95% 磁盘写事务;
- **引擎参数**:启用 256MB mmap、16MB 内存页缓存与内存临时表。
### 7.6 比例退款与离线暂存
- 任务终止时按 `退款 = paidAmount × (未完成单元数 / 总单元数)` 精确退款;
- 若终止时玩家离线,款项写入 `pending_payouts` 表暂存,玩家下次进服在 `onPlayerJoin` 自动补发并提示。
---
## 8. 已知取舍
1. **长加载**:不使用 BDS TickingArea(其 `_addArea` 需要 LevelStorage,且易与玩家自建区域混淆),改为清理时按 `chunk_load_budget` 主动加载目标区块,玩家远离也不会中断;
2. **基岩清理不可逆**:`clear_bedrock` 开启后会真实挖掘基岩,最底层受绝对地板安全保护。
[/MD]