夜花櫻TINYYANA
今晚的顏色櫻粉

夜、花、櫻。名字裡的三個字就是上面那片天空,拉一下會跟著換。

今晚的音樂

月夜蝶~君ヲ想フ~,來自H/MIX GALLERY。 音量在這裡調,右上角能暫停。

← 回筆記
技術實作

Lycohinya 是怎麼搭起來的(二):插件怎麼拆

上一篇講了 Lycohinya 的插件分三層。這篇講最上面那層:玩法插件是怎麼拆的,以及為什麼不是每個功能都拆成一顆。

拆之前

2.0 之前,大部分功能都塞在兩顆插件裡:核心插件 LycohinyaCore,和生活功能插件 LycoServerTweaks。插件 JAR 是熱換的最小單位,所以只要改一行使魔設定,就得整顆核心插件熱換,玩家開著的選單會被關掉、排程會重來。生活功能插件也一樣,調一下定時重啟,跟它無關的背包整理、傳送功能都會跟著被打斷。

拆了哪些

2.0 拆出了五顆:

  • LycoFamiliar:使魔,原本在核心插件裡,是核心插件最大的一塊。
  • LycoTravel:家、傳送點、領地飛行、生態域定位,原本在生活功能插件裡。
  • LycoOps:定時重啟、健康檢查、維護時段、管理員警報。
  • LycoChat:聊天守則、禁言、洗頻偵測、@提及。
  • LycoAlts:小號判定和登入上限。

後面四顆都是從生活功能插件拆出來的。留在原地的是簽到、檢定、玩家偏好、主選單、信箱這些共用同一批玩家資料的功能(核心插件),以及背包整理、催熟、展示框這類沒有資料表、幾乎不會改的小功能(生活功能插件)。

怎麼判斷要不要拆

我不是看功能大小,而是看這幾件事:

  • 它有沒有自己的資料表,而且沒有別人在寫。
  • 改它的時候,同一顆插件裡的其他功能會不會一起改。
  • 熱換它會打斷什麼,例如玩家開著的選單、登入檢查、排程。
  • 它有沒有自己的排程、事件監聽、Discord 訂閱這些要收拾的東西。
  • 用到它的插件,在它不在的時候能不能退回安全的預設。

拆開之後如果兩邊還要寫同一張表,那就不拆。那樣只是把同一個麻煩分到兩顆插件裡,之後更難修。

資料一列都不搬

拆的時候我沒有搬任何資料。以使魔為例:

---
config:
  layout: elk
---
flowchart TB
  subgraph lib["LycoLib"]
    api["使魔介面"]
  end
  fam["使魔插件<br/>LycoFamiliar"]
  core["核心插件<br/>LycohinyaCore"]
  works["工作站插件"]
  subgraph db["核心插件的資料庫"]
    famt[("使魔的表")]
    coret[("玩家共用的表")]
  end
  fam -- 實作並登記 --> api
  core -- 要用時才查 --> api
  works -- 要用時才查 --> api
  fam -- 唯一能寫 --> famt
  core -- 只寫自己的 --> coret
  fam -. 讀它的資料庫設定 .-> core

使魔的資料表還放在核心插件的資料庫裡,只是改成只有使魔插件能寫。使魔插件啟動時,先確認核心插件在場、讀它的資料庫設定連過去,再檢查自己那幾張表的結構對不對,不對就不啟用,資料一筆都不碰。核心插件則不再讀寫使魔的表。旅行、聊天、小號的表也是一樣,留在生活功能插件的資料庫,由新的插件來寫。

這樣做的好處是不用搬資料,上線時就少一個會出錯的步驟。代價是借出資料庫的那一方脫不了關係:核心插件沒啟動,使魔插件也起不來。

插件之間怎麼互相用

插件之間不直接引用對方,要互相呼叫的介面都放在 LycoLib。使魔插件啟動時把自己登記上去;核心插件、工作站插件要查使魔狀態時,每次都現場去問有沒有人提供。

使魔插件不在的時候,查詢會拿到安全的預設值;如果是「發一隻使魔當獎勵」這種動作,會回「無法使用」,讓商城或抽卡那邊可以退款,不會把玩家的東西吞掉。

拆的時候我定了一條規矩:玩家打的指令、看到的選單入口、權限節點一個都不能變。玩家不需要知道背後換了插件。

拆完之後

現在改使魔不用再碰核心插件,調重啟排程也不會關掉玩家的選單。代價是插件數量變多,每多一顆就多一份設定、一組介面,還有「對方不在時怎麼辦」要想清楚。LycoLib 也因此變成所有人的依賴,它一換版,整串插件都得跟著重載。

如果你的伺服器還沒遇到「熱換一個功能會打斷另一個」,我不建議先拆。等它變成日常再拆,判斷依據也會比較清楚。