joywayer and Claude Opus 5
0f676b0e88
feat(ai): Build() 校验「非终态必须有出口」,堵住零报错的永久卡死
...
BrainBuilder.Build() 此前只做正向校验——边指向的态是否已声明(RequireState
的同款关切);反向从不检查。一个已声明却没有任何出边的非终态,会让敌人进去
就永久停在那里,且全程零报错。计划里点名的风险点是 BossFragments.PhaseTransition:
它按设计不自带出边,出口全靠调用方补挂,漏一条就把 Boss 锁死。
做法:AiState 加 IsTerminal,StateBuilder 加 .Terminal() 显式标记,
AiStateFragments.Terminal() 自带该标记;Build() 对「非终态且无出口」抛异常。
「有出口」的判定比计划原话严一档,两点都是照 AiRuntime 的实际行为定的:
- 自转换不算——Switch 对 Target == 当前态直接 return false,根本出不去;
- 全局转换不算——全局事件边要外部推信号才触发,不是自主出口。把它算作出口,
等于让「只有死了才出得去」的死角通过校验,而那恰是本校验要暴露的东西。
校验放在 Build() 而非各生产入口:生产的完整图装配点是 AiScript.GetOrBuildGraph
与 AiRecipeSO 两处,放 Build() 能让将来新增的入口默认受保护。代价是模块单测
需要一条别的路——单个 IUnawareModule / IEngagementModule 按设计只声明自己的态,
升级边由 PerceptionSkeleton 事后挂,单独构建时的死角是正常中间态而非缺陷。
为此加 BuildPartial():跳过本项校验,其余照旧。
测试侧按语义分两类处理,没有一刀切:
- 概念上确实是终态的(Dead)标 .Terminal(),保留 Build() 的全量校验;
- 隔离验证单个模块/片段的部分图改用 BuildPartial();
- AiScriptTests / AiDefinitionRegistryTests 的夹具经 GetOrBuildGraph 走生产
Build(),给桩汇态补了回边——这两条本就该验完整图。
- 断言 Build() 因别的原因抛异常的用例原样保留。
PerceptionSkeleton 与嘲风图建的都是完整图,无需改动即通过——这本身就是覆盖。
验证:编译 0 错;EditMode 269/269(264 + 新增 5)。
加校验后曾有 49 条既有测试变红,全部为上述两类夹具,逐条按语义修正后转绿。
变异验证:注释掉 ChaoFengAi 里 PhaseTx 的 txDone 出边后,ChaoFengAiTests
8 条全部变红,报错精确点名 'PhaseTransition';还原后复验 269/269。
本改动之前,同样的删除是零报错的——Boss 会静默锁死在过渡态,
这正是本校验存在的理由。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-31 13:21:07 +08:00
joywayer and Claude Opus 5
eaba54ea76
feat(ai): Boss 图共享片段 + 竞技场锚点 + AiSignal.Engaged
...
BossFragments:阶段过渡 / 逼近选招 / 移动到锚点三个静态建态片段。
ApproachAttackEngagement 的建态逻辑提为 internal static Declare(态名参数化),
模块路径与 Boss 图路径共用同一份行为,Boss 可建多组(地面组/空中组)。
锚点坐标经 IBossControl.AnchorAt / DistanceToAnchor 暴露,不走黑板——
EnemyAiBrain._context 是私有的(BossBase 无从写入),且 ResetScratch 会清黑板
带来隐式时序约束。锚点本就是 Boss 专属知识,归 Boss facet 更直。
锚点漏配 / 下标越界显式抛,不回退到自身位置。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 14:32:32 +08:00
joywayer and Claude Opus 5
2a1ada4388
fix(ai): 应用 Task 1+2 代码审查意见
...
ResourceFull 未挂 BossResource 时改为显式抛——原先静默返回 false,
是 CLAUDE.md 第 6 条禁止的下游兜底,且与紧邻的 Boss facet 行为不一致。
FakeBossControl.DistanceToAnchor 不再忽略 index。测试改用 TearDown 清理
(本项目关闭了 Domain/Scene Reload,失败断言会把物体永久留在打开的场景里)。
BeginPhaseTransition 去掉死的默认参数;接口补充重入契约说明。
顺带去重:FakeAiContext 实现 IEnemyActor,删除两个测试内的本地 Ctx 副本
——一个接口成员改动要同步三份是复发性成本。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 12:31:39 +08:00
joywayer and Claude Opus 5
3665504a58
feat(ai): 新增 IBossControl facet——Boss 阶段状态经 IAiContext 供图读取
...
非 Boss 敌人访问 IAiContext.Boss 显式抛 InvalidOperationException,
不返回空对象掩盖小怪图误挂 Boss 边的错误。BossResource 补 IsFull 供图条件边判定。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 12:15:54 +08:00
joywayer
afcc0b10ee
fix(enemy): 配方校验改用一次性 builder 探测,不再干扰共享图缓存
2026-07-30 08:33:53 +08:00
joywayer
ecdb0040cb
feat(editor): 敌人 AI 配方脚手架向导;AssignModules 改名并失效缓存
...
- AiRecipeSO 新增 protected InvalidateGraph(),子类装配模块后调用以丢弃缓存图,
避免改动要等到下次进 Play 才生效的静默陈旧图问题。
- PerceptionRecipeSO.SetModulesForTests 改名为 AssignModules(向导也要用它装配模块,
旧名字具有误导性),并在装配后调用 InvalidateGraph。
- 新增 EnemyAiRecipeWizard:按 AssetFolderSpec 定名定路径创建感知型 AI 配方资产
(Assets/_Game/Data/Enemies/{EnemyID}/ENM_{EnemyID}_Ai.asset),已存在则选中不覆盖。
- PerceptionRecipeSoTests 同步改名调用点,并新增测试钉住"装配后缓存必须失效"契约。
2026-07-29 15:28:25 +08:00
joywayer
426fa3601d
fix(enemy): EnemyAiBrain 配置守卫不随重新启用蒸发,注册表消重
2026-07-29 15:23:49 +08:00
joywayer
57cbaacf2c
feat(enemy): EnemyAiBrain 支持配方资产/AiScript id 二选一解析
2026-07-29 14:56:54 +08:00
joywayer and Claude Opus 5
04f644969b
fix(ai): AiRecipeSO.OnEnable 改 protected virtual,防子类静默遮蔽
...
留作 private 时,子类另写一个 OnEnable 会遮蔽它(Unity 只调最派生的),
PlayModeResetHook 注册从此不发生且零报错——关闭域重载下即表现为
"改了配方进 Play 仍跑旧图"。T13 的 PerceptionRecipeSO 是第一个子类,
在它出现前先堵住。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-29 14:36:22 +08:00
joywayer
6d8db95046
feat(ai): IAiDefinition + AiRecipeSO 配方基类(含关闭域重载的缓存重置)
2026-07-29 14:32:45 +08:00
joywayer
894ae99984
test(ai): 补测经 AiStateFragments 的跨模块状态撞名,State() 补引导注释
2026-07-29 12:11:07 +08:00
joywayer
80fdc36762
feat(ai): BrainBuilder.DeclareState——重复声明状态即报错,防模块间同名静默覆盖
...
State() 仍保持宽松(有则取),用于给已声明的态挂边;DeclareState() 只用于
首次声明行为,重复声明同名状态会抛异常。AiStateFragments 的四个建态原语
(Locomotion/Ability/AbilityOnce/Terminal)改用 DeclareState。同时给
IEngagementModule/IDeathModule/IUnawareModule 补充不变量说明。
2026-07-29 12:01:19 +08:00
joywayer
fd238b71f1
refactor(ai): AiSignal 8→1,删除零发送方零消费方的死枚举
2026-07-29 11:14:29 +08:00
joywayer
e76d6bc118
feat(ai): BrainBuilder.RequireState——未声明状态挂边时构建期报错
2026-07-29 11:08:23 +08:00
joywayer
297f9d2968
feat(enemy): IEnemyLocomotion 增加 Pursue 寻路逼近原语(RunSpeed)
2026-07-24 12:23:43 +08:00
joywayer
702df35efd
feat(enemy): ICombatant 增加 HasEligibleAttack/UseBestAttack + EnemyBase 构建选择器
2026-07-24 12:20:54 +08:00
joywayer and Claude Opus 4.8
1ab0521061
refactor(ai): IAiContext.Mover→Locomotion,删除 IMover
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-10 12:14:53 +08:00
joywayer and Claude Opus 4.8
0a7312e9bc
feat(ai): 新增 IEnemyLocomotion 接口与 LocomotionMode/PatrolStrategy 枚举
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-10 11:55:41 +08:00
joywayer and Claude Opus 4.8
6c27993e09
feat(ai): 敌人感知↔状态模型——待机/警觉/追击/巡逻 + 可复用感知状态机
...
感知门面 EnemyBase.InChaseZone(追逐/aggro)/InVisionZone(视野/los,缺省回退aggro),纯查询;
转换逻辑归 AI 层: 新增可复用 PerceptionStateMachine(统一规则,HasAlert/视野缺省自动降级);
规则: 未发现进视野→警觉, 进追逐→追击(委托能力), 追击脱离视野→巡逻(永不回警觉,再进视野再警觉).
EnemyStatsSO.HasAlertState 勾选项; ContactChaseAbility 改纯执行器(退出由AI中断); E001 用可复用件.
PlayMode 验证四态转换全通过.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-09 15:10:39 +08:00
joywayer and Claude Opus 4.8
4ce798ea6e
refactor(ai): E001 AI 重写为纯决策层,符合设计并委托能力模块
...
依据小怪设计文档重构 E001 状态机 Idle_Disguise→Skill_Start→Skill_Loop→Skill_End→Move_Patrol:
追击移动/接触伤害全部委托 e001_chase(ContactChaseAbility),AI 不再裸 MoveTo。
新增 ISensor.DetectsPlayer(视线OR近身,对齐设计)、IMover.UseChase/PatrolSpeed、
IEnemyActor.SetPhase(AI 声明阶段、EnemyBase 播动画)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 16:51:47 +08:00
joywayer and Claude Opus 4.8
63e241af92
fix(ai): AiRuntime 自转换设为no-op(根治死亡双发Died再入) + EnemyBase.OnSpawn复位brain.enabled + 测试
...
Switch 对 target==当前态直接 no-op(不重跑Exit/Enter),循环改为 if(Switch(t))return true;
OnSpawn 复用时恢复被 QuotaManager 裁剪禁用的 brain。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 16:26:28 +08:00
joywayer
683a2d9ffb
feat(ai): AiDefinitionRegistry——反射按id提供共享AiGraph(关域重载重置)
2026-07-03 14:55:42 +08:00
joywayer
11e4c9f1ea
refactor(ai): 终审收尾——删死字段/事件转换刷新IsSuspended + 局部事件与双实例独立性测试
2026-07-03 14:33:23 +08:00
joywayer
d01df7b5f0
feat(ai): AiRuntime 事件转换(push,不受门限制)+trace触发原因+池复用测试
2026-07-03 14:23:28 +08:00
joywayer
5ad26b16e8
perf(ai): AiRuntime 热路径去装箱/弱表一次注册 + 补 OnExit/Entry OnEnter 测试
2026-07-03 14:20:19 +08:00
joywayer
cdd1053bec
feat(ai): AiRuntime 条件转换+IsControllable让位门+状态计时+trace+Reset
2026-07-03 14:13:36 +08:00
joywayer
0253fd15ca
refactor(ai): BrainGraph Task4 审查修复——删死字段/Global空目标校验/AiState只读转换
2026-07-03 14:09:43 +08:00
joywayer
6f9fa8c4b8
feat(ai): BrainGraph AiGraph + BrainBuilder(fluent, 显式标签, 目标校验)
2026-07-03 14:04:51 +08:00
joywayer
3d6cef1f41
feat(ai): BrainGraph Transition/AiState/TransitionRecord 数据结构
2026-07-03 14:00:27 +08:00
joywayer
7281c5cf6e
feat(ai): BrainGraph 能力接口(ISensor/IMover/ICombatant/IActorVitals)+IAiContext
2026-07-03 13:58:52 +08:00
joywayer
db5bd019f8
feat(ai): BrainGraph 核心程序集 + AiSignal + Blackboard(可自省)
2026-07-03 13:56:11 +08:00