Fronted Behavior System
Fronted Behavior System
本文描述 Designer v3 前台行为动画的当前架构。行为文档属于活动布局包,正常运行时只读取活动包中的 v3 behavior 文件。
源码入口:HostManager、Host、动画 runtime、行为模型。插件注册与 publisher 示例统一见 SDK,本文负责事件消费、图与生命周期。
Behavior animation runtime
每个窗口的行为文件位于:
FrontedBehaviors/{WindowTypeName}.behaviors.json控件通过稳定的 BehaviorGuid 关联行为。控件重命名不会改变该身份;复制控件时生成新的 BehaviorGuid;删除控件时清理对应行为。
行为分为 OneShot、Loop 和 Transition。节点图由 FrontedNodeGraphRuntime 执行,属性写入和动画由 IFrontedAnimationRuntime 及 IAnimatablePropertyAdapterRegistry 完成。动画目标通过稳定控件身份和显式 TargetLayer 解析,不使用临时行为标签。
flow.if 的事件字段选择器显示本地化字段名和稳定路径,例如“是否存在上一个角色
(Event.HasOldCharacter)”,但节点 JSON 只保存稳定路径。运行时解析 Event.*、StartEvent.* 和 StopEvent.* 时兼容 payload 中的无前缀键及对应带前缀键;
Transition payload 会同时提供两种形式。条件无法解析时,图执行日志会记录路径和
可用 payload 键;设计器预览缺少事件上下文时也会明确提示。
| TargetLayer | 目标 |
|---|---|
Control | 控件根元素 |
Content | 控件主要内容元素 |
OverlayAbove | 控件上方运行时动画层 |
OverlayBelow | 控件下方运行时动画层 |
Business event integration
IFrontedEventBus 是行为触发的统一入口。FrontedSharedDataBehaviorEventBridge 把共享数据和赛事业务事件转换为显式事件 payload;FrontedBehaviorTriggerEvaluator 根据事件类型和过滤规则决定是否触发行为。
后台引导高亮变化与清除不暴露为前台行为触发器。前台引导动画只使用 Guidance.StepChanged。过滤器比较显式 payload 字段,不依赖 UI 文本或临时标签。
Plugin semantic events
插件语义事件通过 AddFrontedBehaviorEvents<TPlugin>() 注册 Designer 元数据,通过 IFrontedBehaviorEventPublisher<TPlugin> 发布。PackageId 由 FrontedPluginRegistrationContext 在 PluginBase.Initialize(...) 期间自动绑定;插件只处理 local EventId。稳定身份为:
plugin:<PackageId>/<LocalEventId>FrontedBehaviorEventCatalog 是实例级 DI singleton,合并宿主 Attribute events、显式内置 events 与所有 FrontedBehaviorEventRegistration。Designer Window、Behavior Panel 和 Graph Animation Editor 使用同一实例,不创建看不到插件 registration 的运行时目录。内置 CLR event 的 [FrontedBehaviorEvent] / [FrontedBehaviorEventPayload] discovery 继续保留。
插件 publisher 对事件注册和 payload schema 做校验,把枚举规范化为稳定名称,把 Guid/日期规范化为 invariant 字符串,然后构造 FrontedBehaviorEvent 并进入已有 IFrontedEventBus。WebRenderer 已监听同一总线,因此没有插件专用 IPC 或第二条 runtime event channel。
事件描述符使用 FrontedBehaviorEventUsage 区分 EventBus 与 Transition 两条运行时链路,不区分 OneShot、Loop Start 和 Loop Stop。普通插件事件统一属于 EventBus,因此同一个事件可用于这三种 EventBus 触发位置。Transition 不从 EventBus 消费普通插件事件,而由 IFrontedTransitionOrchestrator 驱动;因此插件事件不出现在 Transition selector 中。
插件缺失时,behavior JSON 中的 canonical EventType、Filters 和 Graph 原样保留。Designer 为未知 canonical EventType 建立只读语义的 Missing plugin event 选项,并继续保留未知 payload filter path。插件 registration 在后续启动恢复后,目录会按同一个 EventType 自动重新识别,无读取期补字段或 migration。
Loop lifecycle
StartGraph
-> LoopGraph repeated execution
-> StopGraph
-> cleanupLoop 的 LoopPolicy 默认 RepeatCount=-1(无限)、IntervalMs=0、ReentryPolicy=IgnoreIfRunning、StopMode=RunStopGraph、ResetOnStop=true。重复触发按策略处理:IgnoreIfRunning 不重启,InterruptPrevious 取消旧生命周期并启动新实例;Queue/AllowParallel 虽是公开枚举值,当前 Host 仅 warning 并忽略重入,不实现排队或并行。AutoReverse 字段当前未被 runtime 消费,不应描述为可用反向循环。
停止模式区分 StopImmediately、CompleteCurrentIteration、RunStopGraph、HoldCurrentState。前两种需结合当前图阶段取消/完成;RunStopGraph 先取消活动 Start/Loop 再执行停止图,Hold 保留当前结果且不 reset。StopGraph 无 start、校验失败或执行完成时抑制 reset,避免用基础值覆盖停止图结果或掩盖错误;ResetOnStop 也不能在宿主 Dispose 后创建新 session。LoopGraph 失败停止循环,不能形成无间隔重试。
窗口关闭、布局重载、活动包切换或行为被删除时取消所有图阶段并清理动画状态;业务 StopTrigger 与整个宿主 lifetime 取消不可混为同一个停止事件。
HostManager 只允许同一窗口最新 Attach 请求注册;Detach/Dispose 使尚在异步加载的旧请求失效。宿主释放要取消全部图阶段、退订事件并清理 session;loop finally 与迟到动画动作不得在 Dispose 后 Reset 并复活 session。窗口侧协调用于 Hide/Show/关闭,见窗口运行时。
Transition lifecycle
IFrontedTransitionOrchestrator 串联来源状态退出和目标状态进入动画,并在重入、取消、窗口关闭和包切换时终止旧 transition。Transition 不拥有第二份比赛状态,状态变化仍以 ISharedDataService 和显式事件 payload 为权威源。
Transition 的顺序固定为 ExitGraph -> commit -> EnterGraph。其中 commit 是实际比赛状态变更点,必须在 WPF UI Dispatcher 上执行;SmartBP 等后台识别线程只能通过 ICharacterSelectionService / IFrontedTransitionOrchestrator 调用服务层,由服务层负责切回 UI 线程,不能直接修改 CurrentGame。
Behavior package files
package/
├── manifest.json
├── FrontedLayouts/
│ └── BpWindow.json
└── FrontedBehaviors/
└── BpWindow.behaviors.json导出器复制请求选定源包(缺省活动包)的 behavior 文件;导入器、package manager 和删除流程将 behavior 文件与布局包一起处理。legacy .bpui 转换不在普通 v3 runtime 中增加 legacy behavior fallback。
Designer integration
Designer 的行为面板编辑当前选中控件的行为列表、触发器、过滤器和节点图。编辑结果进入同一 dirty tracking、Undo/Redo、保存、导入和导出流程。
flow.if 保持兼容的 Left / Operator / Right 存储结构,但 Designer 会按当前行为和图阶段从FrontedBehaviorEventCatalog 构造条件字段。布尔字段使用 true / false 选择器,枚举字段保存稳定枚举名,
数字字段使用数字编辑器;可选操作符也会按字段类型收窄。OneShot 使用 Trigger.EventType,Transition 的
ExitGraph / EnterGraph 使用 TransitionTrigger.EventType,Loop 的 StartGraph / LoopGraph 使用StartTrigger.EventType。Loop StopGraph 合并所有 StopTrigger 的 Event.* 字段,并额外提供StartEvent.* 以读取启动循环时捕获的事件负载。
运行时条件路径含义:
| 路径 | 含义 |
|---|---|
Event.* | 当前图阶段的事件负载;Loop StopGraph 中是实际匹配的停止事件 |
StartEvent.* | Loop 启动事件负载 |
StopEvent.* | Loop 停止事件负载 |
Context.TriggerEventType / Context.CurrentControlDisplayName | 图执行上下文元数据 |
属性动画必须通过已注册 adapter。新增可动画属性时,应实现或扩展 IAnimatablePropertyAdapter,并保证捕获基础值、设置值、动画和 reset 的语义一致。
GaussianBlurRadius 是像素单位、最小为 0 的可动画属性。静态半径由控件外观中的 GaussianBlurRadius 保存;效果经 V3 Host 创建的独立包装链应用,不覆盖内容自身 Effect:内容先渲染,再高斯模糊、发光、阴影。缺插件 placeholder 使用 renderer 的效果包装。模糊不会改变 DesiredSize 或 RenderSize,但可扩展到布局边界外,并可能被父级 ClipToBounds 裁剪。
flow.parallel 使用 BranchCount 保存并行任务数,默认值为 3,允许范围为 1 到 20。分支输出使用稳定端口名 Branch1 到 Branch20;运行时仅执行当前数量范围内已连接的分支,并在全部完成后从 Out 继续。旧图未保存 BranchCount 时继续按 3 个分支处理。设计器减小任务数时会移除超出新范围的分支连接,避免保存不可见连线。
数值事件值与运算
动作节点的 Value、From 和 To 保持原有字面量写法,同时可接收 number 值端口。值节点包含数值常量、事件数值,以及四则、取模、取负、abs、min、max、clamp、round、floor、ceil;值图按动作执行时需求值,不参与 flow。已连接值端口优先于字面量。
数值属性也可写受限表达式,例如 =clamp(Event.PlayerIndex / 10, 0, 1)。表达式只支持数值、括号、上述数值函数与 Event.* / StartEvent.* / StopEvent.* 变量,使用 invariant culture,绝不执行脚本或任意 .NET 代码。表达式或数值图无法解析、除零或得到非有限数值时,runtime 记录 warning、跳过当前动作并继续后续 flow;旧字面量行为文件不会被转换或改写。
节点图属性面板中的普通数字字段使用 WPF-UI NumberBox。数值范围、整数要求和动画属性元数据约束由基于 CommunityToolkit.Mvvm ObservableValidator 的属性编辑 ViewModel 校验,验证通过后才写回节点 JSON。允许百分比表达式的动画字段继续使用文本输入。Value、From、To 的手填值原样保存并直接支持像素值或带 % 的百分比,不依赖单位字段。只有数值端口已连接时,行为节点才显示并要求对应的 ValueInputUnit、FromInputUnit 或 ToInputUnit;数据节点只输出无单位数值。百分比仅适用于支持相对长度的属性(如 ClipInsetRight),运行时会把连接值写成 % 值。此时对应手填值会禁用,避免与外部输入产生歧义。行为文档加载不会补写或改写任何单位字段;缺少已连接端口的单位会作为图校验错误处理。
Runtime services
| 服务 | 职责 |
|---|---|
IFrontedBehaviorService | 读取和保存 behavior 文档 |
IFrontedEventBus | 发布宿主与插件共用的显式前台事件 |
IFrontedBehaviorEventPublisher<TPlugin> | 校验并发布当前插件已注册的局部语义事件 |
FrontedBehaviorEventCatalog | 合并内置与插件事件元数据,并按 SupportedUsages 提供 Designer 选项 |
FrontedBehaviorTriggerEvaluator | 执行触发过滤 |
IFrontedNodeGraphRuntime | 执行节点图 |
IFrontedAnimationRuntime | 应用属性和动画 |
IAnimatablePropertyAdapterRegistry | 解析属性 adapter |
FrontedBehaviorRuntimeHostManager | 管理窗口 runtime host 生命周期 |
IFrontedTransitionOrchestrator | 管理 transition 生命周期 |
正常运行时只从活动包读取 behavior 文件。不要在 layout service、window service 或 renderer 中添加旧 behavior 文件、旧 canvas 或旧用户布局 fallback。
