NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Unit/GameUnitManager.cs

734 lines
25 KiB
C#

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
{
/// <summary>
/// 可操作单位
/// </summary>
public UnitContainer canControlUnits = new UnitContainer();
/// <summary>
/// 备战席的单位
/// </summary>
public UnitContainer prepareUnits = new UnitContainer();
/// <summary>
/// 战斗中的单位
/// </summary>
public UnitContainerWithTroop infightUnits = new UnitContainerWithTroop();
/// <summary>
/// 已死亡的单位
/// 注意这里不会有载具单位,载具单位死亡之后仍在存在于战斗中,只是处于损坏状态,可以被技能修复
/// </summary>
public UnitContainer deadUnits = new UnitContainer();
/// <summary>
/// 所有的单位,无论是否在备战席、战斗中、死亡,都能在这里找到
/// </summary>
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<string, int> _loadPathRecord = new Dictionary<string, int>();
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<GameUnit>)_OnAnyCharacterCellIndexChange);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_ENTER_UNITCONTAINER, (Action<GameUnit>)_OnAnyCharacterCellIndexChange);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_EXIT_UNITCONTAINER, (Action<EDExitUnitContainer>)_OnExitUnitContainer);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_DEAD, (Action<GameUnit>)_OnCharacterDead);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_READY, (Action<GameUnit>)_OnUnitEnterBattle);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_VEHICLE_DESTROY, (Action<NormalVehicle>)_OnVehicleDestroyed);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_UNIT_VISIBLE_CHANGE, (Action<GameUnit>)_OnUnitVisibleChange);
}
private void _UnRegistEvents()
{
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_CELLINDEX_CHANGE, (Action<GameUnit>)_OnAnyCharacterCellIndexChange);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_ENTER_UNITCONTAINER, (Action<GameUnit>)_OnAnyCharacterCellIndexChange);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_EXIT_UNITCONTAINER, (Action<EDExitUnitContainer>)_OnExitUnitContainer);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_DEAD, (Action<GameUnit>)_OnCharacterDead);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_READY, (Action<GameUnit>)_OnUnitEnterBattle);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_VEHICLE_DESTROY, (Action<NormalVehicle>)_OnVehicleDestroyed);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_UNIT_VISIBLE_CHANGE, (Action<GameUnit>)_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<GameUnit> 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<GameUnit> 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<GameUnit> _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<GameUnit> _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<GameUnit> _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<GameObject>(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<GameUnit> _PrepareEnemyCharacter(LevelData.NPCInfo npcInfo,
int troopId)
{
var nGuid = GUIDManager.GenGuid();
var dataConfig = CharacterDataHelper.CombineEnemyConfigData(npcInfo.id, npcInfo.index);
var createUnit = new Character.Character(nGuid, dataConfig, troopId);
if (!AssetManager.Instance.CanLocateAsset<GameObject>(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<Character.Character> 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<GameObject>(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<UnitBuild> 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<NormalVehicle> 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<BeProtectUnit> 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);
// 停止自动战斗AI
PVEManager.Instance.StopAI(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);
}
}
canControlUnits.Clear();
infightUnits.Clear();
prepareUnits.Clear();
deadUnits.Clear();
totalUnits.Clear();
_loadPathRecord.Clear();
canControlUnits = null;
infightUnits = null;
prepareUnits = null;
deadUnits = null;
totalUnits = null;
characterManager = null;
vehicleManager = null;
summonManager = null;
_loadPathRecord = null;
instance = null;
}
/// <summary>
/// 为AI搜索单位列表创建对象池
/// </summary>
private readonly Stack<List<GameUnit>> _tempListPool = new (4);
private List<GameUnit> GetTempList()
{
if (_tempListPool.Count > 0)
{
var list = _tempListPool.Pop();
list.Clear();
return list;
}
return new List<GameUnit>(64);
}
public void ReturnTempList(List<GameUnit> list)
{
list.Clear();
_tempListPool.Push(list);
}
/// <summary>
/// 查找所有敌人单位
/// </summary>
public List<GameUnit> SearchEnemies(GameUnit self)
{
var enemies = GetTempList();
if (self == null) return enemies;
characterManager.SearchEnemies(self, enemies);
vehicleManager.SearchEnemies(self.commonData.troopId, enemies);
return enemies;
}
/// <summary>
/// 查找所有友方单位
/// </summary>
public List<GameUnit> SearchFriends(GameUnit self)
{
var friends = GetTempList();
if (self == null) return friends;
characterManager.SearchFriends(self, friends);
vehicleManager.SearchFriend(self.commonData.troopId, friends);
return friends;
}
}
}