KiHan Plugin 框架详解
KiHan 144 个 C# 业务模块(商城/公会/忍具/充值…)的统一写法。源码:Assets/Scripts/Plugin/Infrastructure/
在架构中的位置:被状态机拉起 → KHGameFlow.BuildGame() → KHPluginManager.Instance.initializePlugins()
0. 一句话总览:部门类比
| 类 |
类比 |
职责 |
Plugin |
部门经理 |
模块入口 / 开窗 / 资源 / 消息派发(Controller) |
Operation |
办事员 |
按”事项名”接单干活(行为单元) |
Model |
档案柜 |
存数据,网络回包自动归档 |
View(UIWindow) |
对外柜台 |
界面展示 |
KHPluginManager |
公司总机 |
按名字找部门、转接消息 |
核心约定:Plugin 是 Controller,Model 是数据,Operation 是行为。三者靠「消息字符串」解耦,不直接互调。
1. 核心概念
| 基类 |
数量关系 |
生命周期 |
关键约束 |
| Plugin |
一模块一个 |
ConstructPlugin → Initialize(懒) → ShowView/HideView |
abstract,经 KHPluginManager 注册 |
| Operation |
一 Plugin 多个(按业务分组) |
构造时反射扫描 [Operation] |
abstract,方法打标签 |
| Model |
一 Plugin 一个 |
构造时反射扫描 [UpdateProcessor] |
继承 BindingSource |
| View |
一 Plugin 多个 |
OnInitWindow → OnInitData → OnOpen → OnClose |
挂 prefab 根节点的 MonoBehaviour |
PluginSetting(配置单,必须先懂)
1 2 3 4 5 6 7 8
| public class PluginSetting { public string PluginName; public bool LoadWhenShowView; public string[] Views; public string DefaultView; public bool WaitForNetMsg; }
|
2. 两条核心链路
链路 A:Plugin 生命周期
1 2 3 4 5 6 7 8
| new XxxPlugin() → ConstructPlugin() ← KHPluginManager 触发 ├─ CreateInitSetting() 填 PluginSetting(Views[] 等) ├─ CreateModel() model = new XxxModel(this) └─ RegisterOperations() ★ 必须调 base(注入 ViewOperation) → Initialize() 首次收到消息才触发(懒初始化) → ShowView(ShowViewArgument) 开窗(LoadWhenShowView 决定加载时机) → HideView(title) / CloseAllViews()
|
链路 B:消息流水线(核心数据流)
1 2 3 4 5 6 7 8
| 业务方 SendMessage("Plugin名", "消息名", data) → KHPluginManager 找到 Plugin → 遍历 Operations → Route() → 有 Lua hook? → 有:Lua 前置处理(可改数据/可终止) → 无/继续 → DoRoute → 反射 Invoke [Operation("消息名")] 方法 → Operation 改 Model → Model.Dispatcher.dispatchEvent → View 收事件刷新
【旁路】NetworkManager 回包 → [UpdateProcessor] 直接进 Model(不经过 Operation)
|
3. 三个”魔法”(反射机制,搜代码必知)
| 魔法 |
机制 |
排查影响 |
[Operation("MsgName")] |
Operation 构造时反射扫描方法登记字典 |
搜”谁调用了 OnXxx”搜不到,要搜消息名字符串 |
[UpdateProcessor(cmdId)] |
Model 构造时自动注册到 NetworkManager |
搜”回包谁处理”要搜 cmdId,不是方法名 |
base.RegisterOperations() |
注入 ViewOperation,自动响应 ShowView/HideView/HideAllViews/EnqueueMessage |
忘调 base → 界面打不开 |
Lua Hook 扩展点:Lua 可在 C# 方法执行前截获消息——返回 (true, newData) 替换数据继续;返回 (false, ...) 终止路由。→ 某消息”没反应”可能是被 Lua 拦了。
4. 子类标准模板(6 步)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class XxxPlugin : Plugin { public const string pluginName = "XxxPlugin"; private readonly string[] views = { UIDef.XXX_MAIN_VIEW }; public override string[] GetViews() => views.ToArray();
protected override void CreateInitSetting() { m_setting = new PluginSetting { PluginName = pluginName, Views = views }; InitSetting(m_setting); } protected override void CreateModel() => model = new XxxModel(this); protected override void RegisterOperations() { base.RegisterOperations(); Operations.Add(new XxxOp { ParentPlugin = this }); } }
|
5. 必知重点与坑
Views[] 是反查钥匙:Plugin 名 → Views[] 里 UIDef 常量 → Data/UIDef.cs 查 prefab 路径 → 定位 View 脚本
- View 嵌套
ViewArg:Model 提供 InitXxxViewArg() 打包状态 → View 的 OnInitData 接收渲染(准 ViewModel 模式)
- 8 种架构形态:先学 MVC 标准型(NinjaBattleField);Shopping/Arena 是 Lua 主导型(C# 薄壳,别照抄);GuildHegemony 等纯 Lua 型不走本框架
- 战斗类:继承链
Plugin → BattlePlugin → IFWBattlePlugin,BattlePlugin 多了战斗忍者请求/超时重试/Loading/跨场景资源等
- View 的
OnCloseWindow 必须清 Dispatcher 监听(关闭是 Hide 复用,不清会残留)
6. Plugin vs Act(怎么选)
|
Plugin |
Act |
| 基类 |
Plugin(C#) 或 LuaBehaviour |
仅 Lua |
| 注册 |
KHPluginManager 全局 |
ActCenterPlugin 子注册 |
| 生命周期 |
持续(部分常驻) |
活动期内(有限) |
| 适用 |
长期系统功能(商城/公会/好友/充值) |
限时运营活动(春节/签到/抽奖) |
7. 排查速查
| 现象 |
先查 |
| 界面打不开 |
漏调 base.RegisterOperations();Views[] 没注册该 UIDef |
| 发消息没反应 |
消息名拼错(反射静默失败);被 Lua Hook 拦截 |
| 收不到回包 |
Model 方法没打 [UpdateProcessor];cmdId 不对 |
| View 不刷新 |
没订阅 Model.Dispatcher;Model 改完没 dispatchEvent |
| 找不到界面文件 |
Views[] → UIDef.cs → prefab 路径 |
8. 记忆口诀
Plugin 经理开窗门,Operation 办事靠标签,Model 档案收回包,View 柜台看消息。
三把钥匙:Views[] 反查界面、[Operation] 找行为、[UpdateProcessor] 找数据源。
相关笔记
- [[KiHan状态机架构详解]](调度者)
- [[KiHan ActFramework详解]](Lua 侧对照)
- [[KiHan UI框架详解]](View 层深入)
本文从 LearnByCompany 原始文档 自动同步。