SkillKit

版本 v0.1.6·更新於 2026-09-06

Ship a learnable custom skill for Outward without rediscovering the traps: SideLoader pack-load wiring, effect-bucket routing, the stuck-cast guard, dynamic quickslot icons, native cast sync. Requires

模組介紹 作者原文

SkillKit — ship a learnable custom skill without rediscovering the traps

📖 Full documentation: SkillKit wiki page

A BepInEx library plugin for Outward (Definitive Edition, Mono branch) that owns the mechanism

of shipping a custom skill: SideLoader pack-load wiring, effect-bucket routing, the stuck-cast

guard, dynamic multi-state quickslot icons, weapon-dependent native cast animation, learn helper,

and convergent re-stamping. Consumers own the content: the SL_Skill XML, the ItemID block, the

icon PNGs, and what the skill actually does.

Extracted from Beastwhispering 2026-07-06 (plan + evidence trail: docs/skilltoolkit-plan.md).

Requires: BepInEx 5 (BepInExPack_Outward) and ForgeKit — the only declared

[BepInDependency], and a hard one. SideLoader must be present at runtime (SkillKit does

nothing without it) but is deliberately not a [BepInDependency]: it's a compile reference only,

resolved locally from the gitignored reference/gamelibs/SideLoader.dll, with load ordering handled

through SL.OnPacksLoaded. StoryKit follows the same precedent. The distinction matters — BepInEx

will happily load SkillKit with SideLoader absent, and the failure surfaces later and less clearly

than a dependency error would.

Consuming the kit

  • Reference the project (Private=false — the DLL ships once, from dist/SkillKit, never

inside your mod's folder: two copies in plugins/ = duplicate-GUID load + split types):

  • Declare the load-order dependency on your plugin class:

[BepInPlugin(GUID, NAME, VERSION)]

[BepInDependency(SkillKit.Plugin.GUID, SkillKit.Plugin.VERSION)] // VERSION = the min-version floor, see kits/versioning.md

  • Ship an SL_Skill XML in your own SideLoader pack (/SideLoader/Items... next to your

DLL — see the template below), then register a spec from your Awake:

SkillRegistry.Register(new SkillSpec

{

ItemId = 12345, // an id from YOUR mod's community-allocated range

Label = "PetCommand", // log tag

OnCast = player => TogglePetCommand(), // what the skill DOES (runs from the native pipeline)

// OPTIONAL: multi-state quickslot icon (vanilla PistolSkill Fire/Reload mechanism).

// For a plain STATIC icon use Icon = DynamicIcon.Fixed("YourSkill.png") — same

// convergent restamping, one state.

Icon = new DynamicIcon

{

Select = () => passive? "engage": "disengage", // state key, polled on every sync

Sprites = // embedded PNGs in YOUR assembly

{

["engage"] = "PetCommandEngage.png",

["disengage"] = "PetCommandDisengage.png",

},

},

// OPTIONAL: native cast animation, re-resolved per equipped weapon every frame

CastAnim = player => IsBow(player)? new CastPick("PowerShot", Character.SpellCastModifier.Immobilized): new CastPick("Probe", Character.SpellCastModifier.Attack),

});

  • SkillRegistry.Learn(player, itemId) grants it (TryUnlockSkill + immediate re-stamp).

SkillRegistry.Verify(player) asserts every spec's wired state — run it from a dev verb after

pack load; bug-16/19 regressions are silent by nature, so assert, don't infer.

The kit's own Plugin drives the convergence loop (per-frame cast-anim sync, ~2s icon tick, a

re-stamp at player-ready on every scene load). Call SkillRegistry.SyncIcons(player) yourself

whenever an icon's state input flips, for same-frame feedback.

Diagnostics to bind into your command channel: DumpLearned(player, filter),

DumpPrefabs(filter), CastDump(player), CastClear(player).

The trap table (why each piece exists)

| Piece | The trap it encodes |

|---|---|

| Effect host named "ActivationEffects" (SetupOne) | Bug 19: EffectSynchronizer.RegisterEffect buckets an Effect by its host GameObject's NAME — only an Activation name lands where Skill.SkillStarted() reads. Wrong name = silent no-op, zero errors. Never wire an effect GameObject by hand. |

| CastGuard (spec default ClearCastAfter = true) | Bug 16: donor 8200040's Spark cast NEVER fires its CastDone animation event for a cloned skill — IsCasting sticks true forever and every later CastSpell (any mod's!) silently n

安裝與使用 安裝:BepInEx 外掛

  1. 本站下載的壓縮包就是模組本體,通常是 BepInEx 外掛(解壓後得到 .dll 或外掛資料夾)。
  2. 建議流程:用社群模組管理器(如 r2modman)選中本遊戲後匯入該模組,管理器會自動裝好 BepInEx 前置並處理依賴。
  3. 手動流程:先在遊戲目錄裝好 BepInEx 載入器,再把解壓出的 .dll 或外掛資料夾放進 BepInEx/plugins/。
  4. 啟動遊戲,BepInEx 控制台會列印載入日誌;確認這個模組出現在日誌裡即為安裝成功。

帶「前置依賴」的模組需要一併安裝,否則不會載入。功能開關通常在遊戲內或外掛自帶的設定檔裡調整。

前置依賴

下面這些內容需要先安裝,否則該模組不會生效:

BepInEx-BepInExPack_Outwardsinai-dev-SideLoaderCeruleanCutlass-ForgeKit

檔案與校驗

檔案名稱
SkillKit-0.1.6.zip
檔案大小
145.9 KiB