diff --git a/GameFrameX.Core/Actors/Actor.cs b/GameFrameX.Core/Actors/Actor.cs index 152a8eee5..2ccd3aa0b 100644 --- a/GameFrameX.Core/Actors/Actor.cs +++ b/GameFrameX.Core/Actors/Actor.cs @@ -167,14 +167,34 @@ public async Task GetComponentAgentAsync(Type agentType, bool i } var agent = component.GetAgent(agentType); - if (!component.IsActive) + // 快速路径:只有整个激活流程结束才放行——IsActive 在激活一开始即置位, + // 激活进行中(读库/代理三段回调未完)时外部调用者必须排队等待,不能提前拿到 agent。 + if (!component.IsActivationCompleted) { - await SendAsyncWithoutCheck(() => ActivateComponentAsync(component, agent, compType)); + await SendAsyncWithoutCheck(() => ActivateComponentIfNeededAsync(component, agent, compType)); } return agent; } + /// + /// 在 actor 上下文内复检后再激活:排在前面的激活工作单元已完成(或当前是激活过程中的内联嵌套调用, + /// IsActive 已为 true)时直接返回,不重复执行激活逻辑。 + /// + /// 要激活的组件实例 + /// 组件对应的代理实例 + /// 组件类型,用于日志记录 + /// 表示异步操作的任务 + private Task ActivateComponentIfNeededAsync(BaseComponent component, IComponentAgent agent, Type compType) + { + if (component.IsActive) + { + return Task.CompletedTask; + } + + return ActivateComponentAsync(component, agent, compType); + } + /// /// 激活指定组件并依次调用其代理的激活生命周期方法 /// @@ -213,6 +233,8 @@ private async Task ActivateComponentAsync(BaseComponent component, IComponentAge throw; } } + // 与既有行为一致:激活失败也视为流程结束(不重试),等待方不再被阻塞。 + component.IsActivationCompleted = true; } /// diff --git a/GameFrameX.Core/Components/BaseComponent.cs b/GameFrameX.Core/Components/BaseComponent.cs index efb000a72..31c9c156d 100644 --- a/GameFrameX.Core/Components/BaseComponent.cs +++ b/GameFrameX.Core/Components/BaseComponent.cs @@ -54,6 +54,27 @@ internal long ActorId /// public bool IsActive { get; private set; } + /// + /// 激活流程(组件激活 + 代理三段激活回调)是否已全部完成。 + /// + /// + /// 由 actor 上下文写入,可能被 actor 外部线程读取,因此使用 volatile; + /// 与 (激活开始即置位)区分,供快速路径判断是否可以放行。 + /// Whether the whole activation flow (component activation plus the agent's three-phase + /// activation callbacks) has completed; written on the actor context and read from outside, + /// hence volatile. Distinct from (set at activation start). + /// + private volatile bool _isActivationCompleted; + + /// + /// 激活流程是否已全部完成 + /// + internal bool IsActivationCompleted + { + get { return _isActivationCompleted; } + set { _isActivationCompleted = value; } + } + /// /// 是否准备完毕 /// @@ -136,6 +157,7 @@ public virtual async Task InactiveAsync() finally { IsActive = false; + _isActivationCompleted = false; } }