649 lines
22 KiB
C#
649 lines
22 KiB
C#
using cfg.LegionBattleCfg;
|
||
using Cysharp.Threading.Tasks;
|
||
using Framework;
|
||
using Gameplay.LegionBattle.Unit;
|
||
using Gameplay.Net;
|
||
using Google.Protobuf.Collections;
|
||
using NLDPB;
|
||
using PhxhSDK;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace Gameplay.LegionBattle
|
||
{
|
||
public sealed partial class LegionBattle : IUpdatable, ILoadable
|
||
{
|
||
/// <summary>
|
||
/// 军团信息字典,key:军团阵营,value:军团数据
|
||
/// </summary>
|
||
private Dictionary<BattlefieldActorCamp, LegionData> dicLegionData;
|
||
/// <summary>
|
||
/// 玩家棋子字典,key:玩家id,value:玩家单位
|
||
/// </summary>
|
||
private Dictionary<uint, LegionBattleActorUnit> dicActorUnit;
|
||
/// <summary>
|
||
/// 建筑数据字典,key:建筑所在格子索引,value:建筑数据
|
||
/// </summary>
|
||
private Dictionary<int, LegionBuildingData> dicBuildingData;
|
||
/// <summary>
|
||
/// 军团战战斗数据池
|
||
/// </summary>
|
||
private Queue<LegionBattleFightData> queueFightDataPool;
|
||
/// <summary>
|
||
/// 军团战战斗数据
|
||
/// </summary>
|
||
private Dictionary<uint, LegionBattleFightData> dicFightingData;
|
||
/// <summary>
|
||
/// 安全区索引
|
||
/// </summary>
|
||
private HashSet<int> setSafeZoneIndex;
|
||
|
||
#region 属性
|
||
/// <summary>
|
||
/// 所有建筑数据
|
||
/// </summary>
|
||
public IEnumerable<LegionBuildingData> BuildingDatas
|
||
{
|
||
get
|
||
{
|
||
foreach (LegionLevelData.Building building in LevelData.Buildings)
|
||
{
|
||
if (dicBuildingData.TryGetValue(building.position, out LegionBuildingData buildingData))
|
||
yield return buildingData;
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 所有玩家数据
|
||
/// </summary>
|
||
public IEnumerable<LegionActorData> ActorDatas
|
||
{
|
||
get
|
||
{
|
||
foreach (LegionBattleActorUnit unit in dicActorUnit.Values)
|
||
{
|
||
yield return unit.Data;
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 军团战关卡数据
|
||
/// </summary>
|
||
public LegionLevelData LevelData { get; private set; }
|
||
/// <summary>
|
||
/// 军团战地图配置数据
|
||
/// </summary>
|
||
public DataLegionBattleMap MapCfg { get; private set; }
|
||
/// <summary>
|
||
/// 战报数据列表
|
||
/// </summary>
|
||
public List<LegionBattleReportData> ListReportData { get; private set; }
|
||
/// <summary>
|
||
/// 战场结束时间
|
||
/// </summary>
|
||
public DateTime EndTime { get; private set; }
|
||
/// <summary>
|
||
/// 玩家自己的阵营
|
||
/// </summary>
|
||
public BattlefieldActorCamp MyCamp { get; private set; } = BattlefieldActorCamp.BacNone;
|
||
/// <summary>
|
||
/// 建筑数量
|
||
/// </summary>
|
||
public int BuildingCount { get { return LevelData.Buildings.Count; } }
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 更新所有单位
|
||
/// </summary>
|
||
public void UpdateUnit(float dt)
|
||
{
|
||
foreach (LegionBattleActorUnit unit in dicActorUnit.Values)
|
||
{
|
||
unit.LogicUpdate(dt);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除数据
|
||
/// </summary>
|
||
public void ClearInfo()
|
||
{
|
||
if (null != dicLegionData)
|
||
{
|
||
dicLegionData.Clear();
|
||
dicLegionData = null;
|
||
}
|
||
|
||
if (null != dicActorUnit)
|
||
{
|
||
foreach (var i in dicActorUnit.Values)
|
||
{
|
||
i.Dispose();
|
||
}
|
||
|
||
dicActorUnit.Clear();
|
||
dicActorUnit = null;
|
||
}
|
||
|
||
if (null != dicBuildingData)
|
||
{
|
||
dicBuildingData.Clear();
|
||
dicBuildingData = null;
|
||
}
|
||
|
||
if (null != dicFightingData)
|
||
{
|
||
dicFightingData.Clear();
|
||
dicFightingData = null;
|
||
}
|
||
|
||
if (null != queueFightDataPool)
|
||
{
|
||
queueFightDataPool.Clear();
|
||
queueFightDataPool = null;
|
||
}
|
||
|
||
if (null != dicHexesData)
|
||
{
|
||
dicHexesData.Clear();
|
||
dicHexesData = null;
|
||
}
|
||
|
||
if (null != ListReportData)
|
||
{
|
||
ListReportData.Clear();
|
||
ListReportData = null;
|
||
}
|
||
|
||
if (null != setSafeZoneIndex)
|
||
{
|
||
setSafeZoneIndex.Clear();
|
||
setSafeZoneIndex = null;
|
||
}
|
||
}
|
||
|
||
#region 更新数据
|
||
/// <summary>
|
||
/// 初始化军团数据
|
||
/// </summary>
|
||
public void InitLegionData(int mapId, uint startTime, int timeLength, MSG_LB_Legion legionA, MSG_LB_Legion legionB)
|
||
{
|
||
foreach (DataLegionBattleMap dataLegionBattleMap in TableManager.Instance.Tables.LegionBattleMap.DataList)
|
||
{
|
||
if (dataLegionBattleMap.ID == mapId)
|
||
{
|
||
MapCfg = dataLegionBattleMap;
|
||
break;
|
||
}
|
||
}
|
||
|
||
EndTime = CommonUtils.GetTimeByTimestamp(startTime).AddSeconds(timeLength);
|
||
|
||
if (null == ListReportData)
|
||
ListReportData = new List<LegionBattleReportData>();
|
||
|
||
if (null == dicLegionData)
|
||
dicLegionData = new Dictionary<BattlefieldActorCamp, LegionData>();
|
||
|
||
if (null == dicFightingData)
|
||
dicFightingData = new Dictionary<uint, LegionBattleFightData>();
|
||
|
||
if (null == queueFightDataPool)
|
||
queueFightDataPool = new Queue<LegionBattleFightData>();
|
||
|
||
LegionData legionAInfo = new(BattlefieldActorCamp.CampA);
|
||
legionAInfo.InitData(legionA);
|
||
dicLegionData.Add(BattlefieldActorCamp.CampA, legionAInfo);
|
||
|
||
LegionData legionBInfo = new(BattlefieldActorCamp.CampB);
|
||
legionBInfo.InitData(legionB);
|
||
dicLegionData.Add(BattlefieldActorCamp.CampB, legionBInfo);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化军团战玩家数据
|
||
/// </summary>
|
||
public void InitActorUnit(MSG_LB_Actor data)
|
||
{
|
||
if (null == dicActorUnit)
|
||
dicActorUnit = new Dictionary<uint, LegionBattleActorUnit>();
|
||
|
||
foreach (var kv in dicLegionData)
|
||
{
|
||
if (kv.Value.DicMember.TryGetValue(data.Id, out LegionActorData memberData))
|
||
{
|
||
memberData.CopyData(data);
|
||
break;
|
||
}
|
||
}
|
||
|
||
#region 记录玩家自己属于哪个阵营
|
||
if (Actor.Instance.Base.GetProp(ActorProp.ActorId) == data.Id)
|
||
{
|
||
foreach (var kv in dicLegionData)
|
||
{
|
||
if (kv.Value.DicMember.TryGetValue(data.Id, out _))
|
||
{
|
||
MyCamp = kv.Key;
|
||
LegionBattleManager.Debug($"玩家属于{MyCamp}阵营");
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化军团战建筑信息
|
||
/// </summary>
|
||
public void InitBuildingData(MSG_LB_Building data)
|
||
{
|
||
if (!dicBuildingData.TryGetValue((int)data.Index, out LegionBuildingData buildingData))
|
||
return;
|
||
|
||
buildingData.CopyData(data);
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleBuilding, buildingData.Index);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化战报数据
|
||
/// </summary>
|
||
public void InitReportData(RepeatedField<MSG_CombatRecord> listReportData)
|
||
{
|
||
foreach (MSG_CombatRecord reportData in listReportData)
|
||
{
|
||
ListReportData.Add(new LegionBattleReportData(reportData));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新军团战玩家数据
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <param name="info"></param>
|
||
public void UpdateActorData(MSG_LB_ActorUpdate info)
|
||
{
|
||
if (!dicActorUnit.TryGetValue(info.Id, out LegionBattleActorUnit actorUnit))
|
||
return;
|
||
|
||
actorUnit.AsynData(info);
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleActor, info.Id);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过id更新军团战玩家数据
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <param name="command"></param>
|
||
/// <param name="x"></param>
|
||
/// <param name="z"></param>
|
||
/// <param name="pathX"></param>
|
||
/// <param name="pathZ"></param>
|
||
public void UpdateActorInfoById(uint id, BattlefieldActorCommand command, int x, int z, RepeatedField<uint> pathX, RepeatedField<uint> pathZ)
|
||
{
|
||
if (!dicActorUnit.TryGetValue(id, out LegionBattleActorUnit actorUnit))
|
||
return;
|
||
|
||
actorUnit.AsynData(command, x, z, pathX, pathZ);
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleActor, id);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过索引更新军团战建筑信息
|
||
/// </summary>
|
||
public void UpdateBuildingInfoByIndex(int index, BattlefieldActorCamp camp, int defCount, int total, RepeatedField<uint> actorIds)
|
||
{
|
||
LegionBuildingData buildingData = dicBuildingData[index];
|
||
BattlefieldActorCamp oldCamp = buildingData.CurCamp;
|
||
buildingData.CopyData(camp, defCount, total, actorIds);
|
||
|
||
if (oldCamp != buildingData.CurCamp) // 阵营变化时刷新格子颜色
|
||
{
|
||
if (BattlefieldActorCamp.BacNone == oldCamp)
|
||
{
|
||
if(1 == buildingData.AttackedTotal)
|
||
UI_LegionBattleNoticeController.Open(E_LegionBattleNotice.BaseChange, index).Forget();
|
||
}
|
||
else if (BattlefieldActorCamp.BacNone != buildingData.CurCamp)
|
||
UI_LegionBattleNoticeController.Open(E_LegionBattleNotice.BaseChange, index).Forget();
|
||
}
|
||
|
||
if (0 != buildingData.DefenceCount && 0 == buildingData.DefenceCount % 3)
|
||
UI_LegionBattleNoticeController.Open(E_LegionBattleNotice.ContinuousDef, index).Forget();
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleBuilding, index);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新格子信息
|
||
/// </summary>
|
||
/// <param name="pos"></param>
|
||
/// <param name="camp"></param>
|
||
public void UpdateHexes(RepeatedField<int> listX, RepeatedField<int> listY, RepeatedField<int> listCamp)
|
||
{
|
||
for (int i = 0; i < listX.Count; ++i)
|
||
{
|
||
if (!dicHexesData.TryGetValue(new Vector2Int(listX[i], listY[i]), out LegionBattleHexesData hexesData))
|
||
return;
|
||
|
||
hexesData.SetCamp((BattlefieldActorCamp)listCamp[i]);
|
||
UpdateCellColorByIndex(hexesData);
|
||
}
|
||
|
||
UpdateCellLine();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置军团战分数
|
||
/// </summary>
|
||
/// <param name="aScore"></param>
|
||
/// <param name="bScore"></param>
|
||
public void SetScore(int aScore, int bScore)
|
||
{
|
||
dicLegionData[BattlefieldActorCamp.CampA].SetScore(aScore);
|
||
dicLegionData[BattlefieldActorCamp.CampB].SetScore(bScore);
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleScore);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新建筑分数
|
||
/// </summary>
|
||
/// <param name="camp"></param>
|
||
/// <param name="pos"></param>
|
||
/// <param name="score"></param>
|
||
public void UpdateBuildingScore(BattlefieldActorCamp camp, Vector2Int pos, int score)
|
||
{
|
||
if (null == Map)
|
||
return;
|
||
|
||
if (BattlefieldActorCamp.BacNone == camp)
|
||
return;
|
||
|
||
int index = Map.BlockPosition2TGSCellIndex(pos);
|
||
LegionBattleBuildingScoreData buildingScoreData = new(camp, index, score);
|
||
|
||
LegionBattleManager.Debug($"更新军团战建筑得分数据,阵营:{camp},建筑索引:{index},得分:{score}");
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleBuildingScore, buildingScoreData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始战斗(进入集结状态)
|
||
/// </summary>
|
||
public async void FightStart(uint id, uint passTime, RepeatedField<uint> attacks, RepeatedField<uint> defences, uint buildingX, uint buildingY)
|
||
{
|
||
if (dicFightingData.TryGetValue(id, out LegionBattleFightData fightData))
|
||
fightData.UpdateData(attacks, defences);
|
||
else
|
||
{
|
||
if (queueFightDataPool.Count > 0)
|
||
fightData = queueFightDataPool.Dequeue();
|
||
else
|
||
fightData = new LegionBattleFightData();
|
||
|
||
fightData.InitData(passTime * 0.001f, attacks, defences, new Vector2Int((int)buildingX, (int)buildingY));
|
||
dicFightingData.Add(id, fightData);
|
||
}
|
||
|
||
#region 进入集结
|
||
foreach (uint actorId in fightData.ListAttackId)
|
||
{
|
||
if (!TryGetActorData(actorId, out LegionActorData actorData))
|
||
continue;
|
||
|
||
actorData.IsAssemble = true;
|
||
actorData.IsAttack = true;
|
||
actorData.FightId = id;
|
||
}
|
||
|
||
foreach (uint actorId in fightData.ListDefenceId)
|
||
{
|
||
if (!TryGetActorData(actorId, out LegionActorData actorData))
|
||
continue;
|
||
|
||
actorData.IsAssemble = true;
|
||
actorData.IsAttack = false;
|
||
actorData.FightId = id;
|
||
|
||
if (actorId == Actor.Instance.Base.GetProp(ActorProp.ActorId))
|
||
await UI_LegionBattleBreatheController.Open(true);
|
||
}
|
||
|
||
if (!fightData.IsAttackActor)
|
||
{
|
||
fightData.BuildingData.IsAssemble = true;
|
||
fightData.BuildingData.FightId = id;
|
||
}
|
||
#endregion
|
||
|
||
LegionBattleManager.Debug($"战斗id为{id}的集结开始, {attacks}集结攻击");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 战斗结束
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <param name="actorId"></param>
|
||
/// <param name="targets"></param>
|
||
public void FightOver(uint id, int attack, int def, float result, DateTime time,
|
||
BattlefieldActorCamp attackCamp, BattlefieldActorCamp defCamp, Vector2Int buildingPos,
|
||
bool isAttackLiving, bool isDefenceLiving, bool isAttackEscape, bool isDefenceEscape)
|
||
{
|
||
if (!dicFightingData.TryGetValue(id, out LegionBattleFightData fightData))
|
||
{
|
||
DebugUtil.LogError($"军团战战斗id:{id}不存在");
|
||
return;
|
||
}
|
||
|
||
#region 退出集结
|
||
foreach (uint actorId in fightData.ListAttackId)
|
||
{
|
||
if (!TryGetActorData(actorId, out LegionActorData actorData))
|
||
continue;
|
||
|
||
actorData.IsAssemble = false;
|
||
}
|
||
|
||
foreach (uint actorId in fightData.ListDefenceId)
|
||
{
|
||
if (!TryGetActorData(actorId, out LegionActorData actorData))
|
||
continue;
|
||
|
||
actorData.IsAssemble = false;
|
||
}
|
||
|
||
if (!fightData.IsAttackActor)
|
||
fightData.BuildingData.IsAssemble = false;
|
||
#endregion
|
||
|
||
LegionBattleReportData reportData = new(attack, def, result, fightData, time, attackCamp, defCamp,
|
||
isAttackLiving, isDefenceLiving, isAttackEscape, isDefenceEscape);
|
||
ListReportData.Add(reportData);
|
||
|
||
dicFightingData.Remove(id);
|
||
fightData.Clear();
|
||
queueFightDataPool.Enqueue(fightData);
|
||
|
||
EventManager.Instance.Send(EventManager.EventName.UpdateLegionBattleReport, reportData); // 更新军团战战报
|
||
}
|
||
#endregion
|
||
|
||
#region 获取数据
|
||
/// <summary>
|
||
/// 尝试获取军团数据
|
||
/// </summary>
|
||
public bool TryGetLegionData(BattlefieldActorCamp camp, out LegionData legionData)
|
||
{
|
||
if (!dicLegionData.TryGetValue(camp, out legionData))
|
||
return false;
|
||
|
||
if (null == legionData)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试获取玩家数据
|
||
/// </summary>
|
||
/// <param name="actorId"></param>
|
||
/// <param name="actorData"></param>
|
||
/// <returns></returns>
|
||
public bool TryGetActorData(uint actorId, out LegionActorData actorData)
|
||
{
|
||
if (!dicActorUnit.TryGetValue(actorId, out LegionBattleActorUnit actorUnit))
|
||
{
|
||
actorData = null;
|
||
|
||
return false;
|
||
}
|
||
|
||
if (null == actorUnit)
|
||
{
|
||
actorData = null;
|
||
return false;
|
||
}
|
||
|
||
actorData = actorUnit.Data;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过阵营获取玩家数据列表
|
||
/// </summary>
|
||
public void GetActorDataListByCamp(BattlefieldActorCamp camp,ref List<LegionActorData> listActorData)
|
||
{
|
||
if (null == listActorData)
|
||
listActorData = new List<LegionActorData>();
|
||
else
|
||
listActorData.Clear();
|
||
|
||
if (!dicLegionData.TryGetValue(camp, out LegionData legionData)) // 通过阵营获取军团数据
|
||
return;
|
||
|
||
foreach (uint actorId in legionData.DicMember.Keys)
|
||
{
|
||
if(dicActorUnit.TryGetValue(actorId, out LegionBattleActorUnit actorUnit))
|
||
listActorData.Add(actorUnit.Data);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过索引尝试获取建筑数据
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <param name="buildingData"></param>
|
||
/// <returns></returns>
|
||
public bool TryGetBuildingDataByIndex(int index, out LegionBuildingData buildingData)
|
||
{
|
||
return dicBuildingData.TryGetValue(index, out buildingData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否安全区
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <returns></returns>
|
||
public bool IsSafeZone(int index)
|
||
{
|
||
return setSafeZoneIndex.Contains(index);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取集结倒计时
|
||
/// </summary>
|
||
/// <param name="fightId"></param>
|
||
/// <returns></returns>
|
||
public float GetFightCDByID(uint fightId)
|
||
{
|
||
if (!dicFightingData.TryGetValue(fightId, out LegionBattleFightData fightData))
|
||
return 0f;
|
||
|
||
float fightTime = 0f;
|
||
foreach (DataLegionBattleCombatParam param in TableManager.Instance.Tables.LegionBattleCombatParam.DataList)
|
||
{
|
||
if (CombatParam.BattleTiming != param.ID)
|
||
continue;
|
||
|
||
fightTime = param.ParamInt1;
|
||
break;
|
||
}
|
||
|
||
TimeSpan timeSpan = fightData.StartFightTime.AddMilliseconds(fightTime) - CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
|
||
|
||
return timeSpan.Seconds + 1;
|
||
}
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 加载关卡数据
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private async UniTask LoadLevelData()
|
||
{
|
||
string levelDataPath = CommonUtils.GetLegionBattleLevelData(MapCfg.LevelData);
|
||
TextAsset textAsset = await AssetManager.Instance.LoadAssetAsync<TextAsset>(levelDataPath);
|
||
if (null == textAsset)
|
||
{
|
||
DebugUtil.LogError($"(军团战)关卡数据路径有误: {levelDataPath}");
|
||
return;
|
||
}
|
||
|
||
LevelData = JsonUtility.FromJson<LegionLevelData>(textAsset.text);
|
||
|
||
#region 记录安全区
|
||
setSafeZoneIndex = new();
|
||
foreach (int index in LevelData.BornPosA)
|
||
{
|
||
setSafeZoneIndex.Add(index);
|
||
}
|
||
foreach (int index in LevelData.BornPosB)
|
||
{
|
||
setSafeZoneIndex.Add(index);
|
||
}
|
||
#endregion
|
||
|
||
if (null == dicBuildingData)
|
||
dicBuildingData = new Dictionary<int, LegionBuildingData>();
|
||
|
||
#region 所有地格记录是否有建筑
|
||
foreach (LegionLevelData.Building building in LevelData.Buildings)
|
||
{
|
||
if (!dicBuildingData.TryGetValue(building.position, out LegionBuildingData buildingData))
|
||
buildingData = new LegionBuildingData(building, LevelData.Width, LevelData.Height, Map);
|
||
|
||
foreach (int index in buildingData.SetAllIndex)
|
||
{
|
||
dicBuildingData[index] = buildingData;
|
||
}
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载玩家
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private async UniTask LoadActor()
|
||
{
|
||
await UniTask.WaitUntil(() => { return null != dicActorUnit; });
|
||
|
||
foreach (var legionKV in dicLegionData)
|
||
{
|
||
foreach (var actorKV in legionKV.Value.DicMember)
|
||
{
|
||
if (!actorKV.Value.IsBattleActor) // 排除不能进入军团战的玩家
|
||
continue;
|
||
|
||
LegionBattleActorUnit legionBattleUnit = new(actorKV.Key, actorKV.Value);
|
||
dicActorUnit.Add(actorKV.Key, legionBattleUnit);
|
||
await legionBattleUnit.CreateAsync();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |