using System; using System.Collections.Generic; using System.Linq; using Base; using Entity; using Map; using Prefab; using UnityEngine; using UnityEngine.SceneManagement; namespace Managers { public class EntityManage : Utils.MonoSingleton, ITick { // --- 新增:维度感知的实体存储结构 --- // 外层字典:DimensionId -> 内层字典 // 内层字典:FactionKey -> LinkedList private Dictionary>> _dimensionFactionEntities = new(); // --- 新增:当前场景中活跃的维度实例 --- private Dictionary _activeDimensions = new(); // --- 新增:维度感知的层级缓存 --- // DimensionId -> LayerName -> Transform private Dictionary> _dimensionLayerCache = new(); // --- 待添加实体列表,现在包含 DimensionId --- private List> _pendingAdditions = new(); // Item1: DimensionId, Item2: FactionKey, Item3: EntityPrefab // --- 现有预制体 (保持不变) --- public EntityPrefab characterPrefab; public EntityPrefab buildingPrefab; public EntityPrefab bulletPrefab; public EntityPrefab defaultEntityPrefab; public void RegisterDimension(Dimension dimension) { if (dimension == null || string.IsNullOrEmpty(dimension.DimensionId)) { Debug.LogError("Attempted to register a null or invalid Dimension."); return; } if (_activeDimensions.TryGetValue(dimension.DimensionId, out var existingDimension)) { if (existingDimension == dimension) { // 【逻辑修改】如果是同一个实例重复注册,只做信息提示,不警告 Debug.Log($"Dimension with ID '{dimension.DimensionId}' already registered with the same instance. Skipping re-registration."); return; // 已经注册且是同一个实例,直接返回 } else { // 【逻辑修改】如果是不同实例但ID相同,这是严重错误 Debug.LogError( $"CRITICAL ERROR: Dimension with ID '{dimension.DimensionId}' is already registered with a DIFFERENT instance ({existingDimension.name} vs {dimension.name}). This indicates a duplicate DimensionId in the scene. The new instance will overwrite the old one, which may lead to unexpected behavior. Please ensure all Dimension objects have unique IDs."); // 允许覆盖,但以错误日志形式提示,强制开发者修复场景配置。 } } _activeDimensions[dimension.DimensionId] = dimension; Debug.Log($"Dimension '{dimension.DimensionId}' registered with EntityManage."); // 为新注册的维度初始化其数据结构 // 这些检查是必要的,以防止在重复注册时清空现有数据。 if (!_dimensionFactionEntities.ContainsKey(dimension.DimensionId)) { _dimensionFactionEntities[dimension.DimensionId] = new Dictionary>(); } if (!_dimensionLayerCache.ContainsKey(dimension.DimensionId)) { _dimensionLayerCache[dimension.DimensionId] = new Dictionary(); } } /// /// 从实体管理器注销一个维度。 /// /// 要注销的维度实例。 public void UnregisterDimension(Dimension dimension) { if (dimension == null || string.IsNullOrEmpty(dimension.DimensionId)) { Debug.LogError("Attempted to unregister a null or invalid Dimension."); return; } if (_activeDimensions.Remove(dimension.DimensionId)) { // 当维度被注销时,清理其所有相关的实体和层级缓存 _dimensionFactionEntities.Remove(dimension.DimensionId); _dimensionLayerCache.Remove(dimension.DimensionId); // 【逻辑修改】立即清理_pendingAdditions中属于该维度的实体 // 创建一个新列表来存储不属于该维度的实体 var remainingPendingAdditions = new List>(); foreach (var pending in _pendingAdditions) { if (pending.Item1 == dimension.DimensionId) { // 销毁实体GameObject if (pending.Item3 != null && pending.Item3.gameObject != null) // 增加gameObject的null检查 { Destroy(pending.Item3.gameObject); } } else { remainingPendingAdditions.Add(pending); } } _pendingAdditions = remainingPendingAdditions; // 更新_pendingAdditions列表 } } /// /// 根据ID获取一个活跃的维度实例。 /// /// 维度的唯一标识符。 /// 对应的 Dimension 实例,如果不存在则为 null。 public Dimension GetDimension(string dimensionId) { _activeDimensions.TryGetValue(dimensionId, out var dimension); return dimension; } // --- 查找实体 (现在维度感知) --- /// /// 在指定维度中,根据派系键查找所有实体。 /// /// 维度的唯一标识符。 /// 派系键。 /// 指定派系下的实体列表,如果未找到则返回空列表。 public LinkedList FindEntitiesByFaction(string dimensionId, string factionKey) { if (_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict)) { if (factionDict.TryGetValue(factionKey, out var entities)) { return entities; } } return new LinkedList(); // 如果未找到,返回一个空列表 } // --- Tick 方法 (现在维度感知) --- public void Tick() { // 遍历每个活跃的维度 foreach (var dimensionEntry in _dimensionFactionEntities.ToList()) // ToList() 避免在迭代时修改字典 { var dimensionId = dimensionEntry.Key; var factionDict = dimensionEntry.Value; // 检查维度对象本身是否仍然活跃在场景中 // 注意:这里检查的是 _activeDimensions,确保 Dimension 对象实例仍然存在且被管理器追踪。 if (!_activeDimensions.ContainsKey(dimensionId)) { Debug.LogWarning( $"Skipping Tick for dimension '{dimensionId}' as its Dimension object is no longer active. Clearing its entities."); _dimensionFactionEntities.Remove(dimensionId); // 移除已失效维度的实体数据 _dimensionLayerCache.Remove(dimensionId); // 移除已失效维度的层级缓存 continue; } foreach (var faction in factionDict) { var entitiesToRemove = new List(); var currentEntities = faction.Value.ToList(); // 创建副本以避免在迭代时修改列表 foreach (var entityPrefab in currentEntities) { // 检查实体预制体或其内部实体是否已销毁或死亡 if (entityPrefab == null || entityPrefab.entity == null || entityPrefab.entity.IsDead) { entitiesToRemove.Add(entityPrefab); } else { ITick itike = entityPrefab.entity; itike.Tick(); } } // 删除所有标记为死亡的实体 foreach (var entityToRemove in entitiesToRemove) { faction.Value.Remove(entityToRemove); if (entityToRemove != null) // 确保它没有被外部销毁 { Destroy(entityToRemove.gameObject); } } } } // 处理待添加实体 (现在维度感知) if (_pendingAdditions.Any()) { foreach (var pending in _pendingAdditions) { var dimensionId = pending.Item1; var factionKey = pending.Item2; var entityPrefab = pending.Item3; // 再次检查维度是否活跃,防止在添加前维度被注销 if (!_dimensionFactionEntities.ContainsKey(dimensionId)) { Debug.LogError( $"Attempted to add entity '{entityPrefab.name}' to unregistered or inactive dimension '{dimensionId}'. Entity will be destroyed."); if (entityPrefab != null) Destroy(entityPrefab.gameObject); continue; } var factionDict = _dimensionFactionEntities[dimensionId]; if (!factionDict.ContainsKey(factionKey)) { factionDict[factionKey] = new LinkedList(); } factionDict[factionKey].AddLast(entityPrefab); } _pendingAdditions.Clear(); } } /// /// 根据给定的Def生成实体对象(内部通用方法)。 /// /// 实体所属的维度ID。 /// 要实例化的预制体 /// 生成位置 /// 实体定义对象 /// 额外的初始化操作(如子弹方向设置) /// 成功时返回EntityPrefab组件,失败时返回null private EntityPrefab GenerateEntityInternal( string dimensionId, // 新增参数:维度ID GameObject prefab, Vector3 pos, Data.EntityDef def, Action extraInit = null) { // 验证维度是否活跃 if (!_activeDimensions.TryGetValue(dimensionId, out var dimension)) { Debug.LogError($"Cannot generate entity: Dimension '{dimensionId}' is not active or registered."); return null; } // 获取或创建实体所属的层级Transform,并确保其在维度根下 var parentLayer = EnsureLayerExists(dimensionId, "DefaultEntityLevel"); // 使用一个默认层级名称 if (parentLayer == null) { Debug.LogError($"Failed to get or create parent layer for entity in dimension '{dimensionId}'."); return null; } GameObject instantiatedEntity = null; try { // 实例化实体,并将其父级设置为维度下的层级Transform instantiatedEntity = Instantiate(prefab, pos, Quaternion.identity, parentLayer); var entityComponent = instantiatedEntity.GetComponent(); if (!entityComponent) { throw new InvalidOperationException( $"EntityPrefab component missing on: {instantiatedEntity.name}"); } entityComponent.Init(def); extraInit?.Invoke(entityComponent); var factionKey = def.attributes.defName ?? "default"; // 假设 attributes.defName 是派系键 _pendingAdditions.Add(Tuple.Create(dimensionId, factionKey, entityComponent)); // 添加维度ID return entityComponent; } catch (System.Exception ex) { if (instantiatedEntity) Destroy(instantiatedEntity); Debug.LogError($"Entity generation failed in dimension '{dimensionId}': {ex.Message}\n{ex.StackTrace}"); return null; } } /// /// 动态创建层(如果层不存在),现在是维度感知的。 /// 每个维度有自己的层级结构,根在 Dimension.DimensionRoot 下。 /// /// 维度的唯一标识符。 /// 要确保存在的层级名称。 /// 层级Transform,如果维度不存在或其根Transform为空则返回null。 private Transform EnsureLayerExists(string dimensionId, string layerName) { // 尝试从维度层级缓存中获取 if (!_dimensionLayerCache.TryGetValue(dimensionId, out var layerCacheForDimension)) { Debug.LogError( $"Dimension '{dimensionId}' not found in layer cache. This should not happen if dimension is registered."); return null; } if (layerCacheForDimension.TryGetValue(layerName, out var layerTransform)) { return layerTransform; } // 如果缓存中没有,尝试在维度根下查找 var dimension = GetDimension(dimensionId); if (dimension == null || dimension.DimensionRoot == null) { Debug.LogError( $"Dimension '{dimensionId}' or its root transform is null. Cannot create layer '{layerName}'."); return null; } layerTransform = dimension.DimensionRoot.Find(layerName); if (!layerTransform) { // 如果层不存在,动态创建并将其父级设置为维度的根Transform var layerObject = new GameObject(layerName); layerTransform = layerObject.transform; layerTransform.SetParent(dimension.DimensionRoot); } // 将新创建的层加入缓存 layerCacheForDimension[layerName] = layerTransform; return layerTransform; } // --- 公共生成方法 (现在维度感知) --- /// /// 在指定维度中,根据PawnDef生成普通实体。 /// public void GenerateEntity(string dimensionId, Data.EntityDef entityDef, Vector3 pos) { if (!characterPrefab) { Debug.LogError("characterPrefab is null! Assign a valid prefab."); GenerateDefaultEntity(dimensionId, pos); return; } if (entityDef == null) { Debug.LogError("EntityDef is null! Cannot generate entity."); GenerateDefaultEntity(dimensionId, pos); return; } var result = GenerateEntityInternal( dimensionId, characterPrefab.gameObject, pos, entityDef ); if (!result) GenerateDefaultEntity(dimensionId, pos); } /// /// 在指定维度中,生成建筑实体(位置使用Vector3Int)。 /// public void GenerateBuildingEntity(string dimensionId, Data.BuildingDef buildingDef, Vector3Int pos) { if (!buildingPrefab) { Debug.LogError("buildingPrefab is null! Assign a valid prefab."); GenerateDefaultEntity(dimensionId, pos); return; } if (buildingDef == null) { Debug.LogError("BuildingDef is null! Cannot generate building."); GenerateDefaultEntity(dimensionId, pos); return; } var worldPos = new Vector3(pos.x, pos.y, pos.z); var result = GenerateEntityInternal( dimensionId, buildingPrefab.gameObject, worldPos, buildingDef ); if (!result) GenerateDefaultEntity(dimensionId, worldPos); } /// /// 在指定维度中,生成子弹实体(含方向设置)。 /// public void GenerateBulletEntity(string dimensionId, Data.BulletDef bulletDef, Vector3 pos, Vector3 dir, Entity.Entity source = null) { if (!bulletPrefab) { Debug.LogError("bulletPrefab is null! Assign a valid prefab."); GenerateDefaultEntity(dimensionId, pos); return; } if (bulletDef == null) { Debug.LogError("BulletDef is null! Cannot generate bullet."); GenerateDefaultEntity(dimensionId, pos); return; } var result = GenerateEntityInternal( dimensionId, bulletPrefab.gameObject, pos, bulletDef, // 子弹特有的方向设置 entityComponent => entityComponent.entity.SetTarget(pos + dir) ); // 确保 result 不为 null 且 entity 是 Bullet 类型 if (result != null && result.entity is Bullet bullet) { bullet.bulletSource = source; if (source != null) bullet.affiliation = source.affiliation; // 确保 source 不为 null } if (!result) GenerateDefaultEntity(dimensionId, pos); } /// /// 在指定维度中,生成默认实体(错误回退)。 /// public void GenerateDefaultEntity(string dimensionId, Vector3 pos) { if (!_activeDimensions.ContainsKey(dimensionId)) { Debug.LogError( $"Cannot generate default entity: Dimension '{dimensionId}' is not active or registered."); return; } var parentLayer = EnsureLayerExists(dimensionId, "DefaultEntityLevel"); if (parentLayer == null) { Debug.LogError($"Failed to get parent transform for default entity in dimension '{dimensionId}'."); return; } var entity = Instantiate(defaultEntityPrefab, pos, Quaternion.identity, parentLayer); var entityComponent = entity.GetComponent(); const string factionKey = "default"; _pendingAdditions.Add(Tuple.Create(dimensionId, factionKey, entityComponent)); entityComponent.DefaultInit(); } // --- 单例生命周期与场景切换处理 --- protected override void OnStart() { SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } /// /// 场景加载完成时的回调。 /// 清理旧场景的实体数据,并重新扫描新场景中的维度。 /// private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _dimensionFactionEntities.Clear(); // 清理所有维度下的实体数据 _dimensionLayerCache.Clear(); // 清理所有维度下的层级缓存 _pendingAdditions.Clear(); // 清理待添加实体列表 _activeDimensions.Clear(); // 清理活跃维度列表,因为旧场景的维度对象已被销毁 } private void Start() { if (defaultEntityPrefab == null) { var pre = Resources.Load("Default/DefaultEntity"); if (pre != null) { defaultEntityPrefab = pre.GetComponent(); } else { Debug.LogError( "Failed to load DefaultEntity prefab from Resources/Default/DefaultEntity. Please ensure it exists at 'Assets/Resources/Default/DefaultEntity.prefab'."); } } } } }