EternalTD 关卡与地图
EternalTD 中的"关卡"是位于 plugins/EternalTD/levels/ 中的 YAML 配置,并与 plugins/EternalTD/worlds/ 中的模板世界文件夹配对。当玩家加入时,EternalTD 会将模板世界克隆到服务器的世界容器中,并在该克隆副本中运行会话。
关卡配置字段
| 字段 | 类型 | 默认值 | 备注 |
|---|---|---|---|
isEnabled | bool | true | 已禁用的关卡在加载时会被跳过 |
levelName | string | null | 在消息、计分板和 NPC 菜单中显示的名称 |
levelDescription | string list | [] | 在 NPC 菜单中显示的行。支持 $highscoreWave 和 $highscorePlayer 占位符 |
worldName | string | null | plugins/EternalTD/worlds/ 下的模板文件夹名称 |
startLocation | string list | null | 生物生成位置的序列化位置列表 |
endLocation | string list | null | 生物所走向的位置列表("红色"瓦片) |
levelLocations | string list | null | 关卡中每一个可行走的网格方格,注册地板选择时自动生成 |
wavesConfigFile | string | 必填 | 链接的波次配置的文件名(waves/<name>.yml) |
waveCount | int | -1 | 缓存的波次计数,当前仅供参考 |
highscoreWave | int | 0 | 该关卡达到的最佳波次 |
highscorePlayerName | string | "no one" | 创下分数的玩家显示名称 |
environment | enum | NORMAL | 加载克隆世界时使用的世界环境 |
整个系统使用的网格大小为每个逻辑方格 3 格(代码中的常量 GRID_SIZE)。
位置字符串格式
EternalTD 中的位置以下列形式的逗号分隔字符串进行序列化:
worldName,x,y,z,yaw,pitch
通常无需手动编写 —— /etd selectfloor 加注册命令会为你计算并保存它们。
世界生命周期
当玩家加入关卡时:
- EternalTD 通过
worldName在plugins/EternalTD/worlds/中查找模板文件夹。 - 选择下一个空闲的数字后缀(
<worldName>_0、<worldName>_1……)并将克隆写入服务器世界容器,同时清理任何过期的旧版或新版布局副本。 - 通过 MagmaCore 的
TemporaryWorldManager将克隆世界加载为临时空世界,从而隔离 Paper 26.1+ 迁移。 - 玩家被传送到新世界;内部的
InstanceProtector应用 EternalTD 的保护规则。
当会话结束时:
- 克隆世界中剩余的所有玩家都会被传送回
config.yml中的出生位置,如果未配置出生位置则会被踢出。 - 克隆世界会被卸载并从磁盘删除(
TemporaryWorldManager.permanentlyDeleteWorld)。
实例保护规则
在关卡活跃期间,克隆世界会应用以下规则:
- 禁用爆炸
- 禁用液体流动
- 禁用鞘翅
- 阻止切换飞行
- 阻止友军伤害
- 阻止原版生物生成
地图创作工作流程
当前的地图创作流程使用游戏内工具:
- 在
plugins/EternalTD/worlds/<worldName>/下放置一个模板世界文件夹。 - 在
plugins/EternalTD/levels/中创建或下载一个匹配的关卡 YAML。 - 运行
/etd reload并手动加入关卡世界(或在单人模式下打开以进行设置)。 - 使用
/etd selectfloor,并通过右键/左键点击两个角落来标记游戏区域,或使用/etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2>直接提供它们。 - 运行
/etd showselection <level>以确认选择看起来正确。 - 运行
/etd register <level>以清除选择。请注意,在当前版本中,register和showselection都不会实际持久化地板区域 —— 本应保存levelLocations的辅助方法(LevelsConfigFields#addLevelLocations)已定义但从未被任何命令调用。如果尚未被下载的包填充,目前你必须手动将levelLocations写入关卡 YAML 中。 - 站在一个起始生成瓦片上并运行
/etd register <level> start。对每个起始瓦片重复此操作(此命令会持久化到startLocation)。 - 站在一个终点瓦片上并运行
/etd register <level> end。对每个终点瓦片重复此操作(此命令会持久化到endLocation)。 - 再次重新加载,并通过 NPC 菜单或
/etd join <level>加入关卡进行测试。
选择命令使用以下公式生成网格方格:
size = abs(corner1 - corner2 + 1) / 3
如果方格的顶部方块为空气(或地板方块可穿过),则会被跳过 —— 因此地板方块必须是实心的,方格才会被注册为可玩。
路径验证
每当放置塔时,EternalTD 都会运行一次 A* 寻路检查。如果放置该塔会让任何起始瓦片到任何终点瓦片都没有可行走的路径,则放置会被拒绝,金币不会被消耗。
Air 敌人使用一条单独的路径,该路径完全忽略塔,并改为遵循空中偏移量(配置路径上方 4 格)。
NPC 与关卡菜单
plugins/EternalTD/npcs/ 中的 NPC 配置将村民 NPC 与一个或多个关卡链接起来。右键点击 NPC 会打开一个 9 格物品栏,将每个关卡列为一片绿色染色玻璃板,并标注关卡名称和描述。
| 字段 | 类型 | 默认值 | 备注 |
|---|---|---|---|
isEnabled | bool | true | 已禁用的 NPC 会被跳过 |
levelIDs | string list | 必填 | 此 NPC 提供的关卡文件名 |
location | string | null | 标准 worldName,x,y,z,yaw,pitch 格式的生成位置 |
name | string | "Default Name" | NPC 显示名称 |
difficulty | string | "Difficulty: Not Set" | 显示在 NPC 上方的难度标签 |
disguise | string | null | LibsDisguises 描述符(例如 custom:etd_tutorial_npc) |
customDisguiseData | string | null | 额外的 LibsDisguises 命令数据 —— 通常是较长的玩家皮肤字符串 |
村民生成时具有无敌、AI 禁用、持久化属性,并带有 EternalTD 的 NPC 命名空间键标签。如果安装了 LibsDisguises,并且同时设置了 disguise 和 customDisguiseData,则村民会在生成时被伪装。
带有 difficulty 标签的漂浮盔甲架会生成在 NPC 上方 2.3 格处。
出生点行为
DefaultConfig 控制如何在大厅世界中管理玩家:
setupDone—— 跟踪首次设置引导是否已完成的标志。spawnLocations—— 默认为etd_spawn,0,65,0,0,0。仅在etd_spawn世界存在时使用。manageSpawn—— 默认为true。启用时,加入的玩家会在登录后 1 刻被传送到出生位置。playerGuide—— 游戏内指南书的文本。
当 manageSpawn 为 true 且出生世界已加载时,每个加入服务器的玩家都会被传送到 spawnLocations。