- 将 ShrinkEventBus、ShrinkDataSaver 及其 EventBus 集成从 gitlink 转为仓库直接维护的完整 UPM 包,补齐运行时、编辑器工具、测试与文档 - 新增 Command 和 Network 的 App 集成组件,支持 ContextLoader 服务发布、可逆注销及 Network Loopback 生命周期管理 - 更新 Starter 与演示组合逻辑,缺失模块时可注册、已有兼容安装器时可覆盖,并补充宿主启动断言 - 升级内部包依赖与 Shared CodeGen 包定义,放宽 Integration.App 包的 Git 忽略规则 - 将独立服务器生成器改为基于已编译程序集的语义扫描,支持 partial、复杂泛型、命名冲突检测及模板 SHA-256 覆写保护 - 新增 Network 语义扫描、模板保护和 App 组件生命周期测试 - 新增真实 UPM 消费工程验证脚本,校验内部版本一致性、程序集加载及 EditMode 测试 - 重构当前架构文档并归档已完成的 Cordis 迁移与旧代码地图
ShrinkNetwork.Integration.EventBus
ShrinkNetwork 与 ShrinkEventBus 的桥接层。目标不是“把网络生命周期抛几个普通事件出来”,而是让某些 EventBase 类型本身就能作为网络消息声明,并在本地与远端之间保持一致的事件语义。
✨ 特性概览
| 特性 | 说明 |
|---|---|
| 🌉 事件即网络消息 | EventBase 可直接实现 IShrinkNetworkMessage / IShrinkNetworkRequest 参与网络同步 |
| 🔁 自动双端分发 | 本地 EventBus.TriggerEvent(...) 后,可自动转发到远端并重新进入远端 EventBus |
| ✅ HasResult 请求语义 | 请求型事件支持 EventResult 与取消状态回传 |
| 📉 增量事件去重 | IShrinkNetworkDeltaEvent 按 SessionId + EventType + DeltaKey 做版本过滤 |
| 🧩 按键接入 | ShrinkNetworkEventBusComponent 注入网络服务,随依赖激活和撤回 |
| 🧰 更顺手的扩展 API | session.PublishEventAsync(...)、session.RequestEventAsync(...)、service.UseEventBusBridge(...) |
📦 依赖
ShrinkNetworkShrinkEventBus- Unity 2022.3+
⚙️ 安装前提
桥接层默认假设你已经有:
- 一套正常工作的
ShrinkNetworkService - 一套正常工作的
ShrinkEventBus - 事件类型明确声明
[ShrinkNetworkEvent] + [ShrinkNetworkMessage]
🚀 快速上手
第一步:声明广播型网络事件
using ShrinkEventBus;
using ShrinkNetwork;
using ShrinkNetwork.Integration;
[ShrinkNetworkEvent]
[ShrinkNetworkMessage(3001, "room/player_ready")]
public sealed class PlayerReadyEvent : EventBase, IShrinkNetworkMessage
{
public string PlayerId { get; set; } = string.Empty;
public string RoomId { get; set; } = string.Empty;
}
第二步:正常启动网络服务
var service = new ShrinkNetworkService(
new ShrinkMessagePackNetworkSerializer(),
new ShrinkNetworkMessageRegistry(),
new ShrinkNetworkRouter());
service.AutoRegisterAll();
service.BindTransport(new ShrinkTcpClientTransport("127.0.0.1", 17001));
ContextLoader 项目由 Starter 组合根装配 ShrinkNetworkEventBusComponent。Standalone 项目需要显式调用 service.UseEventBusBridge(...);仅绑定传输不会再通过反射接桥。
第三步:像普通事件一样触发
EventBus.TriggerEvent(new PlayerReadyEvent
{
PlayerId = "10001",
RoomId = "alpha"
});
注册之后:
- 本地事件先按正常
EventBus流程执行 - 桥接层自动把该事件转发到当前
ShrinkNetworkService的在线 session - 远端收到后重新进入远端
EventBus.TriggerEventAsync(...)
📖 核心概念
事件声明规则
可桥接事件需要同时满足:
- 继承
EventBase - 实现
IShrinkNetworkMessage或IShrinkNetworkRequest - 标记
[ShrinkNetworkEvent] - 标记
[ShrinkNetworkMessage(opcode, route)]
如果缺少这些条件,桥接层会忽略该事件类型。
广播型事件
广播型事件只需要:
EventBaseIShrinkNetworkMessage[ShrinkNetworkEvent][ShrinkNetworkMessage(...)]
适合:
- 玩家就绪
- 房间状态变更
- UI 同步通知
手动定向发送时,推荐直接用扩展:
await session.PublishEventAsync(new PlayerReadyEvent
{
PlayerId = "10001",
RoomId = "alpha"
});
增量事件
如果事件本身就是 delta,而不是完整状态,可以实现 IShrinkNetworkDeltaEvent:
[ShrinkNetworkEvent]
[ShrinkNetworkMessage(3002, "room/player_state_delta")]
public sealed class PlayerStateDeltaEvent : EventBase, IShrinkNetworkMessage, IShrinkNetworkDeltaEvent
{
public string PlayerId { get; set; } = string.Empty;
public int Hp { get; set; }
public string DeltaKey => PlayerId;
public long DeltaVersion { get; set; }
}
桥接层会按:
SessionId + EventType + DeltaKey
记录已应用版本:
- 新版本进入远端
EventBus - 旧版本或重复版本直接丢弃
这套语义是“事件自己声明 delta 载荷”,不是自动做字段 diff。
HasResult 请求型事件
如果事件同时满足:
[ShrinkNetworkEvent][ShrinkNetworkMessage(...)][HasResult]IShrinkNetworkRequest
就可以走“远端裁决”语义:
[Cancelable]
[HasResult]
[ShrinkNetworkEvent]
[ShrinkNetworkMessage(3010, "room/can_use_skill")]
public sealed class CanUseSkillEvent : EventBase, IShrinkNetworkRequest
{
public string PlayerId { get; set; } = string.Empty;
public string SkillId { get; set; } = string.Empty;
}
var outcome = await session.RequestEventAsync(new CanUseSkillEvent
{
PlayerId = "10001",
SkillId = "fireball"
});
if (outcome.IsSuccess && outcome.Result == EventResult.ALLOW)
{
// 允许释放技能
}
当前回传内容只有:
EventResultIsCanceledErrorCode / ErrorMessage
不会自动回传整个事件对象上其他字段的最终改动。
🔧 API 参考
ContextLoader 接入
// ShrinkApp.Starter.Basic 组合根自动加入 ShrinkNetworkEventBusComponent。
// 组件注入 shrink.service.network 后注册,网络提供者撤回时注销。
显式接入
Standalone 或需要自定义 session 过滤时:
service.UseEventBusBridge(new ShrinkNetworkEventBusBridgeOptions
{
SessionFilter = (session, evt) => session.SessionId > 0,
DispatchScheduler = new ShrinkNetworkUnityMainThreadDispatchScheduler()
});
如果网络事件数量较大并且需要明确的每帧预算,使用 ShrinkNetworkDispatchQueue,在 Unity 主线程的 Update 中调用 PumpAsync(maxItems);队列满时默认拒绝,避免无界堆积。
发送扩展
session.PublishEventAsync<TEvent>(eventArgs, route = null)
session.RequestEventAsync<TEvent>(eventArgs, options = null)
service.BroadcastEventAsync<TEvent>(eventArgs, sessionFilter = null, route = null)
🏗️ 工作流
本地 EventBus.TriggerEvent(evt)
├─ 本地订阅链正常执行
├─ Bridge 监听 OnEventTriggered
├─ 识别为 [ShrinkNetworkEvent]
├─ 自动转发到在线 session
└─ 远端收到后重新进入 EventBus.TriggerEventAsync(evt)
请求型事件则额外带回:
远端 EventResult / IsCanceled / ErrorCode
✅ 最佳实践
- 广播型事件和请求型事件分开设计,不要一个类型同时混两种用途
- 高实时状态优先实现
IShrinkNetworkDeltaEvent - 需要“远端裁决”的事件显式标记
[HasResult] - 优先走
session.PublishEventAsync(...)/session.RequestEventAsync(...),不要在业务层到处直接调用底层 bridge
⚠️ 注意事项
- 核心网络程序集不反射发现桥接包;桥接生命周期只来自组合组件或显式 API
- 当前只回传
EventResult与取消状态,不自动同步事件对象其它字段改动 - 桥接层会抑制“远端收到后再次回传”的回环转发
- 如果你需要按目标 session 精细控制广播范围,使用
UseEventBusBridge(...)或BroadcastEventAsync(...)