using System.Collections.Generic;
using UnityEngine;
using BaseGames.Core.Events;
namespace BaseGames.Enemies
{
///
/// 敌人 BehaviorTree 配额管理器(架构 07_EnemyModule §13)。
/// 每 REBALANCE_INTERVAL 帧,按到玩家距离排序已注册敌人,
/// 仅对最近的 _maxActiveBehaviorTrees 个敌人启用 BT。
/// 挂载在场景管理器 GameObject 上(每场景一个实例)。
///
public class EnemyQuotaManager : MonoBehaviour
{
[SerializeField, Min(1)] private int _maxActiveBehaviorTrees = 12;
[Tooltip("PlayerController.Start() 广播此频道,替代 FindWithTag")]
[SerializeField] private TransformEventChannelSO _onPlayerSpawned;
private const int REBALANCE_INTERVAL = 10;
private int _frameCount;
// _registeredSet 用于 O(1) 重复检测,_registered List 用于 Sort
private readonly HashSet _registeredSet = new();
private readonly List _registered = new();
private readonly Dictionary _indexMap = new();
// 排序临时缓冲区:预计算每个敌人到玩家的距离,避免 Sort 比较器内重复 Vector3 运算(O(n logn) → O(n))
private readonly List<(EnemyBase enemy, float sqDist)> _sortTemp = new();
// 缓存玩家 Transform
private Transform _playerTransform;
private readonly CompositeDisposable _subs = new();
private void OnEnable()
{
_onPlayerSpawned?.Subscribe(OnPlayerSpawned).AddTo(_subs);
}
private void OnDisable() => _subs.Clear();
private void OnPlayerSpawned(Transform playerTransform)
=> _playerTransform = playerTransform;
// ── 注册 / 注销 ───────────────────────────────────────────────────
public void Register(EnemyBase enemy)
{
if (enemy != null && _registeredSet.Add(enemy))
{
_indexMap[enemy] = _registered.Count;
_registered.Add(enemy);
}
}
public void Unregister(EnemyBase enemy)
{
if (enemy == null || !_registeredSet.Remove(enemy)) return;
int idx = _indexMap[enemy];
int last = _registered.Count - 1;
if (idx != last)
{
var moved = _registered[last];
_registered[idx] = moved;
_indexMap[moved] = idx;
}
_registered.RemoveAt(last);
_indexMap.Remove(enemy);
}
// ── Unity 生命周期 ────────────────────────────────────────────────
private void Update()
{
if (++_frameCount % REBALANCE_INTERVAL == 0)
Rebalance();
}
// ── 内部 ──────────────────────────────────────────────────────────
private void Rebalance()
{
int n = _registered.Count;
if (n == 0) return;
var playerPos = _playerTransform != null ? _playerTransform.position : Vector3.zero;
// ① 预计算距离(O(n) Vector3 运算,而非在比较器内重复执行 O(n logn) 次)
_sortTemp.Clear();
for (int i = 0; i < n; i++)
{
var e = _registered[i];
float sqd = e != null
? (e.transform.position - playerPos).sqrMagnitude
: float.MaxValue;
_sortTemp.Add((e, sqd));
}
// ② 对临时列表排序(比较器只做 float 比较,无额外 Vector3 开销)
_sortTemp.Sort(static (a, b) => a.sqDist.CompareTo(b.sqDist));
// ③ 将排序结果写回 _registered,同步重建 _indexMap(修复排序后索引过期的 bug)
for (int i = 0; i < n; i++)
{
var e = _sortTemp[i].enemy;
_registered[i] = e;
if (e != null) _indexMap[e] = i;
}
#if GRAPH_DESIGNER
for (int i = n - 1; i >= 0; i--)
{
var enemy = _registered[i];
if (enemy == null) { _registered.RemoveAt(i); continue; }
var bt = enemy.BehaviorTree;
bool active = i < _maxActiveBehaviorTrees;
if (bt != null && bt.enabled != active)
{
bt.enabled = active;
// 同步暂停/恢复 SensorToolkit Sensor,避免远处敌人无效 tick
enemy.SensorHub?.SetSuspended(!active);
}
}
#endif
}
}
}