跳至主要內容

EternalTD 關卡與地圖

EternalTD 中的「關卡」是位於 plugins/EternalTD/levels/ 的 YAML 設定,搭配 plugins/EternalTD/worlds/ 中的範本世界資料夾。當玩家加入時,EternalTD 會將範本世界複製到伺服器的世界容器中,並在該複製副本中執行工作階段。

關卡設定欄位​

欄位類型預設值備註
isEnabledbooltrue已停用的關卡在載入時會被跳過
levelNamestringnull顯示在訊息、計分板和 NPC 選單中的顯示名稱
levelDescriptionstring list[]顯示在 NPC 選單中的行。支援 $highscoreWave 和 $highscorePlayer 佔位符
worldNamestringnullplugins/EternalTD/worlds/ 下的範本資料夾名稱
startLocationstring listnull怪物生成的序列化位置列表
endLocationstring listnull怪物行走的目標位置列表(「紅色」格子)
levelLocationsstring listnull關卡中所有可行走的格子方塊。內容套件會提供這些值;自製地圖可用 /etd register <level> 從地板選取範圍寫入,也可以手動填寫
wavesConfigFilestring必填連結波次設定的檔案名稱(waves/<name>.yml)
highscoreWaveint0此關卡達到的最佳波次
highscorePlayerNamestring"No one"設定該分數的玩家顯示名稱
environmentenumNORMAL載入複製世界時使用的世界環境

整體使用的網格大小為每個邏輯格 3 個方塊(程式碼中的常數 GRID_SIZE)。

waveCount 未被使用。舊檔案中的這個鍵不會決定波次數量;EternalTD 使用連結的波次設定。

位置字串格式​

EternalTD 中的位置序列化為以逗號分隔的字串,格式如下:

worldName,x,y,z,pitch,yaw

也接受四段式的 worldName,x,y,z(此時 pitch 和 yaw 都為零),以及不含世界的五段式 x,y,z,pitch,yaw。工作階段的格線、起點及終點位置會改用實例世界;大廳與 NPC 位置則需要其指定的世界已載入。

下載的內容套件通常會提供這些值。自製地圖的 levelLocations 為每個可玩的 3×3 地板格存放一組中心方塊的整數座標,各中心間隔三格。載入器會在 X 和 Z 加上 0.5,取得世界中的中心位置。/etd register <level> 會從地板選取範圍寫入這份列表(請參閱地圖創作工作流程);你也可以手動填寫。

世界生命週期​

當玩家加入關卡時:

  1. EternalTD 根據 worldName 查詢 plugins/EternalTD/worlds/ 的直接子資料夾,排除名稱含有任何 . 的資料夾。範本不存在、波次設定未載入或名稱不安全時,會拒絕加入。若關卡的 levelLocations、startLocation 或 endLocation 缺少、為空,或含有無法解析的項目,也會被拒絕:「This level has missing or invalid floor, entrance, or exit coordinates. Nothing was started.」
  2. 玩家第一次的世界準備請求仍在處理時,會拒絕第二次請求;已在對局中的玩家(包括其他 Nightbreak 插件的對局)也會被拒絕(「You are already in a match!」)。處理中的請求會在共用對局系統上預留該玩家,因此在請求完成前,其他插件的對局都會拒絕該玩家。斷線,或 10 分鐘內世界仍未準備好,都會取消請求並刪除未完成的副本。
  3. 它會保留下一個可用的數字後綴(<worldName>_0、<worldName>_1、...)。保留動作是同步化的,並會記住已保留但尚未寫入磁碟的名稱,因此兩位玩家同時加入時不會撞到同一個實例名稱。
  4. 範本會在主執行緒之外被複製到伺服器的世界容器中。世界載入與工作階段初始化仍在主執行緒執行。
  5. 複製的世界透過 MagmaCore 的 TemporaryWorldManager 作為臨時 void 世界載入,因此 Paper 26.1+ 遷移被隔離,缺失的區塊會回傳為虛空而非新產生的地形。
  6. EternalTD 驗證格線(請參閱工作階段啟動驗證),InstanceProtector 套用 EternalTD 的保護規則。接著對局系統讓玩家進場:儲存其復原紀錄,在下一個 tick 將其傳送到新世界的重生點,並發放對局物品。若其他插件拒絕這次傳送,玩家會離開對局,本次遊玩隨之結束。請等到「Created your world! We're ready to go.」才開始。較早出現的「Joined level!」本身不代表工作階段成功啟動。

範本需求​

EternalTD 在建立副本前驗證根目錄,並在複製時檢查各子項目。若子項目不合法,會回滾已複製的部分。符合下列任一情況的範本會被拒絕:

  • 它不是一個目錄,或者它是一個符號連結
  • 它的根目錄沒有 level.dat
  • 它內部任何位置含有符號連結
  • 它含有名為 .eternaltd-instance 的檔案(該名稱為保留名稱,見下文)

複製失敗會觸發回滾並顯示失敗訊息。清理本身也可能失敗,請查看主控台;訊息不能證明所有檔案都已刪除。

實例歸屬標記​

每個副本都有一份 .eternaltd-instance 檔案,記錄範本與實例名稱。EternalTD 在刪除過時實例之前,以及刪除驗證失敗的副本世界之前,都會檢查這個標記。複製失敗時會立即移除未完成的副本;已建立工作階段的世界則在工作階段結束時由對局系統刪除(見下文)。

因當機而殘留的過時實例會在載入關卡時被清理,而且即使如此,也只會處理帶有有效標記且目前未載入的資料夾。

工作階段啟動驗證​

只有在下列條件全部成立時,工作階段才可遊玩:

  • levelLocations、startLocation 與 endLocation 皆存在且非空——否則會顯示「This level doesn't have a complete play area, start, and end configuration!」
  • 遊玩區域本身能解析為有效格線——否則會顯示「This level's play area is invalid!」
  • 每個起點格子都同時具備通往某個終點格子的地面路徑與空中路徑——否則會顯示「This level does not have complete land and air paths from every start to an end!」

這些檢查在副本世界載入之後、玩家進場之前執行,因此失敗時不會動到玩家本身的狀態。EternalTD 接著會刪除臨時世界,並回報「Failed to start the level. Your player and the temporary world were rolled back.」。若在復原紀錄儲存後進場本身失敗,該紀錄會立即還原。

當工作階段結束時:

  • 所有殘留的塔會被拆除(拆除時拋出例外的塔會被記錄並略過,而不會讓其餘的塔卡住)。
  • 玩家的復原紀錄會被還原,玩家會被移回進入關卡前所在的位置;若該世界已不再載入,則移到主世界的重生點。
  • 世界的保護規則會被移除。仍留在副本世界中的其他人(例如擁有 eternaltd.match.bypass 的管理人員)會被送到 config.yml 的大廳重生點;未設定大廳時,則送到主世界的重生點。
  • 為遊玩區域取得的區塊票證會被釋放(請參閱路徑驗證)。
  • 清理會請求卸載世界並刪除兩種受支援的目錄配置。卸載被拒絕時不會刪除;外掛啟用期間,刪除會在卸載 5 秒後非同步執行。清理前重新載入的世界也會被跳過,刪除不完整時會記錄錯誤。
  • 結束是冪等的——第二次 end()(例如 /etd quit 之後立刻 /etd hub)不會有任何作用。

實例保護規則​

當關卡活躍時,複製的世界會套用這些規則:

  • 停用爆炸
  • 停用液體流動
  • 停用鞘翅
  • 防止切換飛行
  • 防止友軍傷害
  • 防止原版怪物生成

對局系統也會守護這個世界:本次遊玩中的玩家除了 EternalTD 自己的移動之外,無法傳送進入、離開或在世界內傳送;沒有 eternaltd.match.bypass 的其他玩家也無法傳送進來。請參閱對局規則。

地圖創作工作流程​

以範本作為編輯來源,並將格線寫入關卡 YAML:

  1. 在獨立世界或單人模式中編輯地圖並儲存,再把範本放入 plugins/EternalTD/worlds/<worldName>/。編輯對戰副本不會更新範本。
  2. 建立關卡 YAML,連結已載入的波次設定,並填入 levelLocations、startLocation 與 endLocation。格線使用地板中心座標,起點和終點必須能解析到這些格子。
  3. 若要在編輯世界使用遊戲內工具,先執行 /etd reload 載入設定,再執行 /etd selectfloor。左鍵設定角落 1,右鍵設定角落 2。兩個角落須位於同一世界、相同地板 Y 高度,包含端點的 X/Z 長度須為 3 的倍數。
  4. 也可以使用 /etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2>,在目前世界設定角落。指令會將兩個 Y 各減 1,因此請填入地板 Y 加一。
  5. /etd showselection <level> 會在選取範圍會註冊的每個地板格上方顯示一個只有你看得到的 END_ROD 粒子。它不會儲存任何內容。
  6. 執行 /etd register <level> start 或 end 時,請保持選取範圍啟用。指令會附加玩家所在方塊的整數座標並立即儲存,不會將 Y 減 1,也不檢查該位置是否在格線上。使用前須初始化兩份列表,也可以直接在 YAML 中編輯它們。
  7. 完成起點與終點註冊後,執行 /etd register <level>。它會從選取範圍寫入 levelLocations,取代原有清單,儲存關卡檔案並清除選取範圍。關閉選取模式也會丟棄選取範圍。
  8. 儲存編輯後的範本、重新載入,並透過 NPC 選單或 /etd join <level> 加入。等候最後的世界就緒訊息,再實際遊玩檢查地圖。

選取檢查器使用下列尺寸公式,結果截斷為整數:

size = (abs(corner1 - corner2) + 1) / 3

角落順序不影響結果。檢查器在玩家目前的世界中、以角落 1 的 Y 高度,從較小 X/Z 角落加一的位置開始,每隔三格檢查中心方塊。中心地板可通行,或其上方方塊不可通行時,會跳過該格。它不會檢查每個 3×3 格子的全部方塊。

路徑驗證​

EternalTD 會為每個起點格子快取一條通往任一終點格子的最省 A* 路徑——一條地面路徑與一條空中路徑。當有多個終點格子時,它會比較已完成路徑的成本並保留最短的那條,因此一張有多個出口的地圖會把敵人導向最近的可達出口,而不是最先找到的那個。

地面快取會在工作階段開始時、每次放置塔時,以及每次販售塔時重建。空中快取只會計算一次,就在第一次重建時:空中路徑完全忽略塔,因此玩家蓋的任何東西都無法使其失效。

空中敵人使用另外的空中路徑,該路徑完全忽略塔的阻擋,改為沿著空中偏移(設定路徑上方 4 格)行進。

載入遊玩區域時也會強制載入每一個含有格子方塊的區塊,因此長時間的遊玩不會卡在未載入的區塊上。這些區塊票證會在工作階段結束時、實例世界被刪除之前釋放。

該快取同時也是判斷關卡是否可玩的關卡:若任何起點格子缺少地面路徑或空中路徑,該工作階段會在加入時就被拒絕,而不會開始一場敵人無法完成的遊玩。放置塔時也會執行同樣的檢查,因此會封死某個起點格子的塔會被拒絕且不會花費金幣。

起點與終點查詢只使用 X/Z 解析格線方格,不要求精確的中心座標,也不比較 Y。無法解析到任何格子的項目會被跳過並記錄警告。警告會提示中心位置不符,但也應檢查 levelLocations 是否包含所需格子。

每個解析出來的起點與終點格子也都會被標記為不可建造,因此玩家無法藉由在其上建造來封死生成點或出口。這些格子在放置高亮下會顯示為淡藍色。

NPC 和關卡選單​

plugins/EternalTD/npcs/ 中的 NPC 設定將村民連結到關卡。右鍵點擊會開啟 9 格選單,項目位於欄位 0、2、4、6、8。只會處理設定中的前五個關卡 ID;不存在的 ID 會留下空位,後續 ID 會被跳過並記錄警告。若 NPC 引用的關卡沒有任何一個已載入,整個 NPC 會被跳過。左鍵點擊綠色玻璃片可請求加入該關卡。

欄位類型預設值備註
isEnabledbooltrue已停用的 NPC 會被跳過
levelIDsstring list必填此 NPC 提供的關卡檔案名稱
locationstringnull標準 worldName,x,y,z,pitch,yaw 格式的生成位置
namestring自訂設定為 nullNPC 顯示名稱;預製定義可提供名稱
difficultystring自訂設定為 nullNPC 上方的標籤;請明確設定
disguisestringnullLibsDisguises 描述符(例如 custom:etd_tutorial_npc)
customDisguiseDatastringnull額外的 LibsDisguises 指令資料 — 通常是那串很長的玩家外觀字串

NPC 預定在其設定建立四秒後生成,且位置所屬世界必須已載入。村民無敵、停用 AI、持久存在,並帶有 EternalTD 的 NPC 標記。LibsDisguises 已啟用且兩個偽裝欄位都有設定時,EternalTD 會嘗試偽裝;無效的描述符可能使它保持普通村民外觀。

具有 difficulty 標籤的漂浮盔甲架會在 NPC 上方 2.3 格處生成。

重生點行為​

DefaultConfig 控制玩家在大廳世界中的管理方式:

  • setupDone — 追蹤是否已完成首次設定指引的旗標(預設 false)。
  • spawnLocations — 預設為 etd_spawn,0,65,0,0,0,且一律會被寫入設定檔。只有在 etd_spawn 世界存在時才會被解析並使用。
  • manageSpawn — 預設為 true。啟用且目的地已載入時,EternalTD 會在登入後 1 刻請求傳送至重生點。
  • playerGuide — 遊戲內指南書文字。
  • nightbreak.autoDownloadPluginUpdates — 共享的 MagmaCore 設定(預設 false)。啟用時,外掛和內容更新會在啟動時自動下載。
  • nightbreak.applyPluginUpdatesWithoutRestart(共享的 MagmaCore 設定,預設 never;也可設為 when-empty 或 immediately)控制已下載的外掛更新何時在不重啟的情況下套用。請參閱設定。

初始化完成後,EternalTD 也會為已在線上的玩家請求傳送,但已在目的地世界的玩家除外。這次處理同樣要求 manageSpawn 啟用且目的地已載入。登入與初始化後的傳送流程都不檢查傳送結果,因此其他外掛可能阻止玩家抵達。