using System; using System.Collections.Generic; using Code.Scripts.Gameplay.PlaneShadow; using Cysharp.Threading.Tasks; using Framework; using Gameplay.Building; using Gameplay.Building.Data; using Gameplay.Character; using Gameplay.Character.Utils; using Gameplay.Common; using Gameplay.Level; using Gameplay.Level.Data; using Gameplay.PlayerSkill.Data; using Gameplay.Summon; using Gameplay.Unit.Data; using Gameplay.Vehicle; using Gameplay.Vehicle.Impl; using PhxhSDK; using UnityEngine; namespace Gameplay.Unit { public class GameUnitManager { /// /// 备战席的单位 /// public UnitContainer prepareUnits = new UnitContainer(); /// /// 战斗中的单位 /// public UnitContainerWithTroop infightUnits = new UnitContainerWithTroop(); /// /// 已死亡的单位 /// 注意这里不会有载具单位,载具单位死亡之后仍在存在于战斗中,只是处于损坏状态,可以被技能修复 /// public UnitContainer deadUnits = new UnitContainer(); /// /// 所有的单位,无论是否在备战席、战斗中、死亡,都能在这里找到 /// public UnitContainer totalUnits = new UnitContainer(); public CharacterManager characterManager; public VehicleManager vehicleManager; public SummonManager summonManager; private bool _needUpdateTargets; public static GameUnitManager instance { get; private set; } public bool enableLog = false; private Dictionary _loadPathRecord = new Dictionary(); public static void CreateInstance() { instance = new GameUnitManager(); instance.Init(); } private GameUnitManager() { characterManager = new CharacterManager(); vehicleManager = new VehicleManager(); summonManager = new SummonManager(); } public void Init() { _needUpdateTargets = true; _RegistEvents(); } public void RecordLoadPath(string path) { if (_loadPathRecord.ContainsKey(path)) { _loadPathRecord[path]++; } else { _loadPathRecord.Add(path, 1); } } private void _RegistEvents() { EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_CELLINDEX_CHANGE, (Action)_OnAnyCharacterCellIndexChange); EventManager.Instance.Register(EventManager.EventName.INFIGHT_ENTER_UNITCONTAINER, (Action)_OnAnyCharacterCellIndexChange); EventManager.Instance.Register(EventManager.EventName.INFIGHT_EXIT_UNITCONTAINER, (Action)_OnExitUnitContainer); EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_DEAD, (Action)_OnCharacterDead); EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_READY, (Action)_OnUnitEnterBattle); EventManager.Instance.Register(EventManager.EventName.INFIGHT_VEHICLE_DESTROY, (Action)_OnVehicleDestroyed); EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_VISIBLE_CHANGE, (Action)_OnUnitVisibleChange); } private void _UnRegistEvents() { EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_CELLINDEX_CHANGE, (Action)_OnAnyCharacterCellIndexChange); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_ENTER_UNITCONTAINER, (Action)_OnAnyCharacterCellIndexChange); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_EXIT_UNITCONTAINER, (Action)_OnExitUnitContainer); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_DEAD, (Action)_OnCharacterDead); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_READY, (Action)_OnUnitEnterBattle); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_VEHICLE_DESTROY, (Action)_OnVehicleDestroyed); EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_VISIBLE_CHANGE, (Action)_OnUnitVisibleChange); } private void _OnUnitVisibleChange(GameUnit unit) { _needUpdateTargets = true; } private void _OnVehicleDestroyed(NormalVehicle unit) { _needUpdateTargets = true; } private void _OnUnitEnterBattle(GameUnit unit) { _needUpdateTargets = true; } private void _OnCharacterDead(GameUnit deadCharacter) { _needUpdateTargets = true; } private void _OnAnyCharacterCellIndexChange(GameUnit unit) { _needUpdateTargets = true; } private void _OnExitUnitContainer(EDExitUnitContainer ed) { _needUpdateTargets = true; } // public async UniTask PrepareUnits() // { // var selectTeam = TeamEditManager.Instance.GetSelectTeam(); // var cIds = selectTeam.GetCharacterIDs(); // for (int i = 0; i < cIds.Length; i++) // { // var cId = cIds[i]; // var cInfo = CharacterDataInfoManager.Instance.GetCharacterInfo(cId); // if (cInfo == null) // { // DebugUtil.LogError("不存在的角色id: {0}", cId); // continue; // } // await PrepareCharacter(cInfo, ETroopsId.Self); // } // // var vIds = selectTeam.GetVehicleIDs(); // for (int i = 0; i < vIds.Length; i++) // { // var vId = vIds[i]; // var vInfo = VehicleCultivateDataManager.Instance.GetVehicleCultivateData(vId); // if (vInfo == null) // { // DebugUtil.LogError("不存在的载具id: {0}", vId); // continue; // } // await PrepareVehicle(vInfo, ETroopsId.Self); // } // } private void _PrepareUnit(GameUnit unit) { PlaneShadowManager.instance.AddUnit(unit); prepareUnits.Add(unit); totalUnits.Add(unit); if (enableLog) { DebugUtil.LogG($"单位:{unit.GetUnitDesc()} 已进入备战席"); } } public int GetTroopUnitAliveCount(int troopID) { var unitList = infightUnits.GetListByTroop(troopID); if (unitList == null) return 0; var result = 0; foreach (var unit in unitList) { if (!unit.statusData.isDead) result++; } return result; } public async UniTask PrepareSelfNpc(LevelData.NPCInfo npcInfo) { var monsterConfig = TableManager.Instance.Tables.Monster.GetOrDefault(npcInfo.id); if (monsterConfig == null) { DebugUtil.LogError($"不存在的怪物配置:{npcInfo.id}"); return null; } switch (monsterConfig.NpcType) { case ENpcType.SELF_VEHICLE: return await _PrepareSelfNpcVehicle(npcInfo, ETroopsId.Self); case ENpcType.SELF_CHARACTER: return await _PrepareSelfNpcCharacter(npcInfo, ETroopsId.Self); default: DebugUtil.LogError($"未知的npc类型:{monsterConfig.NpcType}"); return null; } } public async UniTask PrepareEnemyNpc(LevelData.NPCInfo npcInfo) { var monsterConfig = TableManager.Instance.Tables.Monster.GetOrDefault(npcInfo.id); switch (monsterConfig.NpcType) { case ENpcType.ENEMY_CHARACTER: return await _PrepareEnemyCharacter(npcInfo, ETroopsId.Enemy); case ENpcType.ENEMY_VEHICLE: return await _PrepareNpcEnemyVehicle(npcInfo, ETroopsId.Enemy); } DebugUtil.LogError($"未知的npc类型:{monsterConfig.NpcType}"); return null; } private async UniTask _PrepareNpcEnemyVehicle(LevelData.NPCInfo npcInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = VehicleDataHelper.CombineMonsterConfigData(npcInfo); var createUnit = new NormalVehicle(nGuid, dataConfig, troopId); await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } private async UniTask _PrepareSelfNpcVehicle(LevelData.NPCInfo npcInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = VehicleDataHelper.CombineMonsterConfigData(npcInfo); var createUnit = new NormalVehicle(nGuid, dataConfig, troopId); createUnit.commonData.canControl = false; await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } private async UniTask _PrepareSelfNpcCharacter(LevelData.NPCInfo npcInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = CharacterDataHelper.CombineSelfNpcConfigData(npcInfo); var createUnit = new Character.Character(nGuid, dataConfig, troopId); if (!AssetManager.Instance.CanLocateAsset(createUnit.runtimeData.configData.modelPath)) { DebugUtil.LogError($"无法定位资源:{createUnit.runtimeData.configData.modelPath}"); return null; } // npc不可控制 createUnit.commonData.canControl = false; await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } private async UniTask _PrepareEnemyCharacter(LevelData.NPCInfo npcInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = CharacterDataHelper.CombineEnemyConfigData(npcInfo.id, npcInfo.index, npcInfo.level); var createUnit = new Character.Character(nGuid, dataConfig, troopId); if (!AssetManager.Instance.CanLocateAsset(createUnit.runtimeData.configData.modelPath)) { DebugUtil.LogError($"无法定位资源:{createUnit.runtimeData.configData.modelPath}"); return null; } await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } public async UniTask PrepareCharacter(CharacterDataInfo cInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = CharacterDataHelper.CombineConfigData(cInfo); var createUnit = new Character.Character(nGuid, dataConfig, troopId); if (!AssetManager.Instance.CanLocateAsset(createUnit.runtimeData.configData.modelPath)) { DebugUtil.LogError($"无法定位资源:{createUnit.runtimeData.configData.modelPath}"); return null; } await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } public async UniTask PrepareBuild(int buildId, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = BuildDataHelper.CombineConfigData(buildId); var createUnit = UnitBuildFactory.CreateBuild(dataConfig, nGuid, troopId); await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } public async UniTask PrepareVehicle(VehicleCultivateData vInfo, int troopId) { var nGuid = GUIDManager.GenGuid(); var dataConfig = VehicleDataHelper.CombineConfigData(vInfo); var createUnit = new NormalVehicle(nGuid, dataConfig, troopId); await createUnit.CreateAsync(); await createUnit.Prepare(); _PrepareUnit(createUnit); return createUnit; } // public async UniTask PrepareBeProtectUnit(int unitId) // { // var nGuid = GUIDManager.GenGuid(); // var dataConfig = BeProtectDataHelper.CombineData(unitId); // var createUnit = new BeProtectUnit(nGuid, ETroopsId.Self, dataConfig); // await createUnit.CreateAsync(); // await createUnit.Prepare(); // // _PrepareUnit(createUnit); // return createUnit; // } public BaseSummon PrepareSummon(int summondId, GameUnit creator) { var createSummon = SummonFactory.CreateSummon(summondId, creator); _PrepareUnit(createSummon); return createSummon; } // 将单位移动到备战席 public void MoveUnitToPrepare(uint unitGuid) { var unit = infightUnits.Search(unitGuid); if (unit == null) { DebugUtil.LogError("不存在的单位:{0}", unitGuid); return; } // 判断是否已经开展 if (LevelManager.Instance.CurrentLevel.isInBattle) { unit.ExitBattle(); } unit.BackPrepare(); // 转移 infightUnits.Remove(unit); prepareUnits.Add(unit); // 如果有选中,则取消选中-修复bug:选中单位回到备战席后,选中状态仍然存在 if (LevelManager.Instance.CurrentLevel.selectUnit == unit) { LevelManager.Instance.CurrentLevel.UnSelectUnit(); } EventManager.Instance.Send(EventManager.EventName.INFIGHT_UNIT_REMOVE, unit); // 单独给UI那边发一个事件,用于更新UI EventManager.Instance.Send(EventManager.EventName.INFIGHT_BACK_PREPARE, unit); _RemoveFromFightHandles(unit); if (enableLog) { DebugUtil.LogG($"单位:{unit.GetUnitDesc()} 从战斗列表回到备战席"); } _needUpdateTargets = true; } // 将到位移动到战斗中,并指定位置 public void MoveUnitToFight(uint unitGuid, int cellIndex, float yaw) { var unit = prepareUnits.Search(unitGuid); if (unit == null) { DebugUtil.LogError("不存在的单位:{0}", unitGuid); return; } // 设置位置 unit.SetPosAndYaw(cellIndex, yaw); unit.Ready(); // 判断是否已经开战 if (LevelManager.Instance.CurrentLevel.isInBattle) { unit.EnterBattle(); } // 转移 prepareUnits.Remove(unit); infightUnits.Add(unit); switch (unit.gameunitType) { case EGameUnitType.Character: if (unit is Character.Character character) characterManager.AddCharacter(character); break; case EGameUnitType.Vehicle: if (unit is NormalVehicle vehicle) vehicleManager.AddVehicle(vehicle); break; } if (enableLog) { DebugUtil.LogG($"单位:{unit.GetUnitDesc()} 已进入战斗序列"); } _needUpdateTargets = true; } public void EnterBattle() { _needUpdateTargets = true; for (int i = 0; i < infightUnits.count; i++) { var unit = infightUnits.GetByIndex(i); unit.EnterBattle(); } } public void ReviveUnit(uint unitId, UnitReviveData reviveData) { var unit = deadUnits.Search(unitId); if (unit == null) { DebugUtil.LogError("不存在的单位:{0}", unitId); return; } if (unit is Character.Character character) { character.Revive(reviveData); // 转移 deadUnits.Remove(unit); prepareUnits.Add(unit); // 发送事件 EventManager.Instance.Send(EventManager.EventName.INFIGHT_REBORN_UNIT, unit); if (enableLog) { DebugUtil.LogG($"单位:{unit.GetUnitDesc()} 已复活"); } } else { DebugUtil.LogError("设计上只支持角色复活"); } } public void LogicUpdate(float dt) { if (_needUpdateTargets) { _lastUnit = null; _isInTargetsUpdate = true; _needUpdateTargets = false; } if (_isInTargetsUpdate) { _UpdateTargets(); } for (int i = 0; i < infightUnits.count; i++) { var unit = infightUnits.GetByIndex(i); unit.LogicUpdate(dt); if (unit.needRemove) { _RemoveFromFight(unit); i--; } } } public void MoveLogicUpdate(float dt) { for (int i = 0; i < infightUnits.count; i++) { var unit = infightUnits.GetByIndex(i); unit.MoveLogicUpdate(dt); } } private void _RemoveFromFight(GameUnit unit) { if (enableLog) { DebugUtil.LogG($"单位:{unit.GetUnitDesc()} 已移除"); } unit.ExitBattle(); infightUnits.Remove(unit); EventManager.Instance.Send(EventManager.EventName.INFIGHT_UNIT_REMOVE, unit); _RemoveFromFightHandles(unit); var deadToList = _CheckDeadToList(unit); if (deadToList) { deadUnits.Add(unit); } else { // 销毁 unit.Dispose(); } _needUpdateTargets = true; } private bool _CheckDeadToList(GameUnit unit) { // 目前只有己方角色才会进入死亡列表 if (unit.gameunitType == EGameUnitType.Character) { if (unit is Character.Character character && character.commonData.troopId == ETroopsId.Self) { return true; } } return false; } private void _RemoveFromFightHandles(GameUnit unit) { switch (unit.gameunitType) { case EGameUnitType.Character: if (unit is Character.Character character) characterManager.RemoveCharacter(character); break; case EGameUnitType.Vehicle: if (unit is NormalVehicle vehicle) vehicleManager.RemoveVehicle(vehicle); break; } } private bool _isInTargetsUpdate; private GameUnit _lastUnit; private int _maxOneFrameCount = 10; private void _UpdateTargets() { if (infightUnits.count == 0) return; if (_lastUnit == null) { _lastUnit = infightUnits.GetByIndex(0); } var continueCount = 0; var isFindLastUnit = false; for (int i = 0; i < infightUnits.count; i++) { var unit = infightUnits.GetByIndex(i); if (unit == _lastUnit) { isFindLastUnit = true; } if (!isFindLastUnit) { continue; } _lastUnit = unit; unit.UpdateTargets(); continueCount++; if (continueCount >= _maxOneFrameCount) { break; } } if (!isFindLastUnit) { _lastUnit = null; } if (_lastUnit == infightUnits.unitList[^1]) { _isInTargetsUpdate = false; } } public void Dispose() { _UnRegistEvents(); for (int i = 0; i < infightUnits.count; i++) { var unit = infightUnits.GetByIndex(i); // unit.ExitBattle(); unit.Dispose(); } for (int i = 0; i < prepareUnits.count; i++) { var unit = prepareUnits.GetByIndex(i); unit.Dispose(); } for (int i = 0; i < deadUnits.count; i++) { var unit = deadUnits.GetByIndex(i); unit.Dispose(); } // unload foreach (var kv in _loadPathRecord) { var path = kv.Key; var count = kv.Value; for (int i = 0; i < count; i++) { AssetManager.Instance.Unload(path); } } infightUnits.Clear(); prepareUnits.Clear(); deadUnits.Clear(); totalUnits.Clear(); _loadPathRecord.Clear(); infightUnits = null; prepareUnits = null; deadUnits = null; totalUnits = null; characterManager = null; vehicleManager = null; summonManager = null; _loadPathRecord = null; instance = null; } /// /// 查找所有敌人单位 /// public List SearchEnemies(GameUnit self) { var enemies = new List(); if (self == null) return enemies; characterManager.SearchEnemies(self, enemies); var vehicles = vehicleManager.SearchEnemies(self.commonData.troopId); if (vehicles != null) enemies.AddRange(vehicles); return enemies; } /// /// 查找所有友方单位 /// public List SearchFriends(GameUnit self) { var friends = new List(); if (self == null) return friends; characterManager.SearchFriends(self, friends); var vehicles = vehicleManager.SearchFriend(self.commonData.troopId); if (vehicles != null) friends.AddRange(vehicles); return friends; } } }