NetKit

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

Shared Photon co-op transport layer for Outward BepInEx mods: channels over one relay, a hello/peer ledger, per-channel counters/heartbeat, PUN diagnostics, and a replicated-record store for consumer

模組介紹 作者原文

NetKit

📖 Full documentation: NetKit wiki page

The shared Photon co-op transport layer for the Outward mod kits. It owns the transport shell

CompanionKit's NetBus and SpawnKit's SpawnNet used to duplicate (~65–75% line-identical): relay

attach, send helpers, the one hello + peer ledger + absence detector, per-channel+verb counters and

trace, join/leave hooks, heartbeat, and the PUN diagnostics. Message semantics (verbs, codecs,

authorization, flush policies) stay in the consumer mods.

Requires: BepInEx 5 (BepInExPack_Outward) and ForgeKit — a hard dependency

([BepInDependency]), so BepInEx refuses to load NetKit if ForgeKit/ isn't in BepInEx/plugins.

No SideLoader; NetKit builds on a clean runner.

Full design + decisions: docs/netkit-plan.md. Background: docs/photon-layer-research-2026-07-18.md.

What it owns

  • Channels, not per-mod buses. One shared NK_Bus wire envelope

(channel, verb, seq, extra, payload) carries every channel; the demux is channel → verb.

  • One hello / one absence detector. nk.hello on join/connect/guest-scene-ready carries the

proto version + the registered channel→version map + optional per-channel extension strings. Peer

state surfaces per channel (OnPeerReady / OnPeerLost / IsPeerReady / ReadyCount). The 10 s

"peer appears UNMODDED" warning lives here once.

  • Diagnostics under the owning channel's log tag: counters, ring-buffer trace, heartbeat

(all PhotonNetwork.time-stamped), the PUN log-signature watcher + per-id unknown-view table.

netdump reports transport/attach/peers/counters; selftest runs the loopback + Core checks.

The per-channel heartbeat line carries cumulative tx=/rx=/drops= totals (after pt=, before the

consumer fragment) so the passive stream survives when the interactive dumps are unreachable.

Dev verbs (BepInEx/config/NetKit_cmd.txt)

  • netdump — co-op census on this machine (transport/attach, per-channel verbs/peers/counters/

ring buffer, hello ledger, PUN-signature + unknown-view tables, helloMuted).

  • selftest — [SELFTEST] PASS/FAIL … DONE: hello codec, compat calc, peer-ledger timing,

counters, and (in a room) the transport loopback.

  • netmute [on|off|status] (bare = status) — ON suppresses OUTGOING nk.hello sends so this box

reads as UNMODDED to peers; the staging tool for incompatible-peer testplan rows without renaming a

DLL mid-session. Incoming handling unchanged. Session-only (not persisted), default off.

  • Pure half in core/NetKit.Core (unit-tested, zero game refs): hello codec (lossless

escaping), channel-version compat, the peer-ledger timing, counters/trace models, heartbeat

formatter, unknown-view table.

API sketch (game side)

var ch = Net.RegisterChannel("sk", "0.4.0", new ChannelOptions {

LogTag = "SKNET", HelloExtension = () => …, HeartbeatFragment = () => … });

ch.Register("spawn", msg => …); // msg: Verb, Payload, Extra, SenderActor,

// SenderIsMaster, SenderIsSelf

ch.SendToMaster("hit", payload, extra); // bool; also SendToOthers/SendToAll/SendToPlayer

ch.SendToAllLoopback("nk.test", …); // selftest

ch.OnPeerReady += info => …; // info: Actor, ChannelVersion, Extension, IsMaster

ch.CountDrop("spawn", "no-row"); // consumer-reported drops

Net.Attached / Net.InRoom / Net.IsMaster / Net.IsGuestInRoom

Send guards return false + drop-count (never throw). Unknown verb on receive = warn-once +

counter. Handlers run inside try/catch with per-verb error counters.

Two backends (one internal transport interface)

  • Rpc (default): the NK_Bus [PunRPC] relay piggybacked on CharacterManager's PhotonView

(viewID 999). RefreshRpcMonoBehaviourCache() after attach is a harmless no-op precaution —

the shipped UseRpcMonoBehaviourCache is false, so it is not "mandatory".

  • Event (opt-in): PhotonNetwork.RaiseEvent on one configurable code ([Net] EventCode, default

177) — no GameObject, no view. Implemented + selftest-covered but config-gated OFF

([Net] Transport = Rpc) until its offline loopback + two-box behavior are live-verified.

Example configuration

BepInEx

安裝與使用 安裝:BepInEx 外掛

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

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

前置依賴

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

BepInEx-BepInExPack_OutwardCeruleanCutlass-ForgeKit

檔案與校驗

檔案名稱
NetKit-0.2.10.zip
檔案大小
192.2 KiB