FastAsyncWorldEdit,重新編到 Lycohinya 的生電核心上。 測試 / 正式服跑的是 Lecithin(Folia 系:Lophine → 修復 Paper 中間層 API 的分支),上游 FAWE 與社群的幾個 Folia 分支要嘛在 26.2 build 不起來,要嘛能 build 但大範圍 / 超遠距離的 //copy+//paste、筆刷、//undo 會幽靈方塊、卡住、甚至觸發 Folia watchdog 崩潰。這個分支把「在區域化伺服器上真的能用」補完。
不是獨立插件。 是 FastAsyncWorldEdit 的 fork,Folia 排程骨架來自 ssquadteam/FAWE-Folia。這裡只維護「Folia / Paper 26.2」這一段 delta;指令、設定、限制系統等一切照上游,上游文件仍然適用。
Lecithin 沒有單一主執行緒,區塊資料的存取被 Moonrise 綁在擁有該區域的執行緒上(ServerLevel#getCurrentWorldData() 在別的執行緒回 null)。上游 FAWE 假設有主執行緒;上游的 feature/folia* 分支與社群 fork 各自補了一部分,但在 26.2 + Lecithin 上仍然會:
//copy一塊地、/tp到很遠、//paste→ 方塊寫進去了(重登看得到)但客戶端一直是舊區塊,得重登才渲染;- 大範圍
//paste直接卡住,relight 永遠跑不完; - 筆刷
//br在區塊邊界觸發FoliaWatchdogThread「region has not responded」而整個區域崩潰; - 大
//paste之後的//undo要排隊等好幾分鐘。
所有改動都用 //FAWE-Folia 註解標出,細節見 FOLIA.md。
| 區塊 | 問題 | 處置 |
|---|---|---|
| 排程層 | FoliaLib 帶來額外 maven repo / relocate / 不可控的相依 | 換成插件內建的 com.github.ssquadteam.fawe.scheduler(來自 ssquad 分支),只暴露 FAWE 實際用到的方法 |
| 編輯完成器 | 每個區塊用阻塞式 runAtLocation 掛在「擁有該區塊的區域」上;該區域在忙 worldgen 或還沒 tick 時整個編輯 hang 死 |
改走 queueHandler.sync,由永遠在 tick 的全域區域執行緒排掉;會碰區域狀態的 tile / entity / beacon 任務才個別 RegionSync.dispatch 回自己的區域 |
| 區塊重繪 | 只送給「追蹤該區塊」的玩家,長距 /tp 後追蹤還沒建好 → 送給 0 人 → 要重登;而且每個區塊掃全服玩家清單 |
天光階段一跑完就立刻送重繪封包(此時佇列還健康);收件者先算、算不到就不做任何事(不查 holder、不鎖、不序列化整塊封包) |
| 光照補算 | 遠 / 冷區塊的鄰居讀取阻塞在非同步區塊載入上,relight worker 永遠 hang | getChunk() 加 15s 上限(fawe.folia.chunkLoadTimeoutSeconds);光照兩個 pass 都包成盡力執行,失敗只記 log、重繪照送 |
| 光照補算 | 區塊光照 pass 在弱核 / 記憶體吃緊時會佔著唯一的 relight worker 好幾分鐘,卡住下一個指令 | Folia 上加 3s 牆鐘預算(fawe.folia.blockLightBudgetMs);超時就收手,沒補完的接縫由下一次自然 relight 收尾 |
| 區域執行緒 | 筆刷 / 工具動作在區域執行緒上就地跑,收尾 relight 讀到未載入區塊 → getChunk() 等一個只有自己能完成的 future → 自我死鎖 → watchdog |
在 tick 執行緒上永不阻塞等區塊載入(ca.spottedleaf.moonrise.common.util.TickThread.isTickThread());不在場就讓那一次讀取快速失敗,relight 跳過該區塊 |
取捨: 遠 / 大 //paste 的方塊會立刻出現,但接縫的區塊光照可能短暫不對,等下一次自然 relight 修正。這是拿光照品質換「不 hang、不崩、不用重登」。
Credit: 「編輯完成器走全域 tick queue、區塊封包在 worker 執行緒 inline 送出」這個方向,是跟 BrilliantTeam/FAWE-Folia(1.21 的可用 Folia 版)對照確認的。本分支沒有複製它的程式碼——上面的天光階段預送、區塊光照時間預算、tick 執行緒不阻塞、
RegionSync逾時、收件者優先判斷,都是針對 26.2 / Lecithin 自己寫的。
| 伺服器 | Paper 26.2 / Lecithin(或其它 Folia 系;非區域化的 Paper/Spigot 也能跑,走上游路徑) |
| Java | 25 |
| 版本適配器 | 只保留 26.1 / 26.2(d2b889513);舊版 adapter 原始碼還在,但不編進 jar |
把 lycohinya-fawe.jar 放進 plugins/。設定沿用上游的 plugins/FastAsyncWorldEdit/config.yml。
Folia 專屬的開關全部是 JVM -D 參數(預設值即可,只有排障時才動):
| 參數 | 預設 | 作用 |
|---|---|---|
fawe.folia.blockLightBudgetMs |
3000 |
區塊光照 pass 的牆鐘預算;0 = 不限制 |
fawe.folia.chunkLoadTimeoutSeconds |
15 |
FAWE worker 等單一區塊載入的上限 |
fawe.folia.regionSyncTimeoutSeconds |
20 |
RegionSync 區域跳轉等待上限 |
fawe.folia.debugSend |
true |
記錄每次區塊重繪的收件者數 / 略過原因(排完 root cause 後關掉) |
fawe.folia.debugRelight |
true |
記錄 relight 每次 flush 的區塊數與 sky/block pass 邊界(同上) |
完整清單見 FOLIA.md。重點:
- 傳送是非同步的(
teleportAsync,樂觀回報成功)。 - 光照用 FAWE 自己的
NMSRelighter,不是 starlight(regionised 伺服器上 starlight relighter 不可用)。 - tick limiter 關閉(那套計數器不是執行緒安全的,1.12 起就沒動過);把
tick-limiter.enabled設false消掉警告。 - 大 / 遠
//paste的方塊即時渲染,接縫光照由自然 relight 收尾。
./gradlew :worldedit-bukkit:shadowJar # → worldedit-bukkit/build/libs/lycohinya-fawe.jar需要 JDK 25(gradle toolchain)。./gradlew build 會連 spigot 版(-Bukkit-,本分支不用)一起編。
- Fork 自 IntellectualSites/FastAsyncWorldEdit。
- Folia 排程骨架(
com.github.ssquadteam.fawe.scheduler、FOLIA.md記錄的 ownership 規則)來自 ssquadteam/FAWE-Folia。 - 幽靈方塊那條的修法方向,跟 BrilliantTeam/FAWE-Folia(1.21)對照確認過——沒有複製程式碼,26.2 專屬的修正是自己寫的。
- 授權沿用上游 FAWE(見
LICENSE.txt/NOTICE.txt);本分支的修改同樣依該授權釋出。 - 上游的使用說明、指令清單、限制系統文件全部仍然有效,請優先參考上游 wiki 與 Discord。