using System.Collections.Generic;
|
using UnityEngine;
|
using LitJson;
|
using System;
|
|
public class BattleManager : GameSystemManager<BattleManager>
|
{
|
public StoryBattleField storyBattleField = null;
|
|
// 同时只能有一场战斗在进行 guid, battlefield
|
protected Dictionary<string, BattleField> battleFields = new Dictionary<string, BattleField>();
|
|
protected LogicUpdate logicUpdate = new LogicUpdate();
|
|
public Action<string, BattleField> onBattleFieldCreate;
|
|
public Action<string, BattleField> onBattleFieldDestroy;
|
|
public override void Init()
|
{
|
base.Init();
|
logicUpdate.Start(Run);
|
DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
|
}
|
|
public override void Release()
|
{
|
base.Release();
|
logicUpdate.Destroy();
|
DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
|
}
|
|
protected void OnPlayerLoginOk()
|
{
|
long exAttr1 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr1);
|
long exAttr2 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr2);
|
|
int MapID = 1;
|
int FuncLineID = (int)exAttr2;
|
|
CreateStoryBattle(MapID, FuncLineID, null, null);
|
}
|
|
// 上游戏的时候 等战斗阵容更新完毕 创建主线副本 敌方的数据可以暂时不显示 己方表现为睡觉
|
// 如果主线副本存在 那么维持当前的副本不变
|
protected void CreateStoryBattle(int MapID, int FuncLineID, JsonData extendData, List<TeamBase> blueTeamList = null)
|
{
|
if (null == storyBattleField)
|
{
|
var redTeamList = new List<TeamBase>();
|
|
TeamBase storyTeam = TeamManager.Instance.GetTeam(TeamType.Story);
|
|
redTeamList.Add(storyTeam);
|
|
CreateBattleField(string.Empty, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
|
}
|
else
|
{
|
// storyBattleField
|
}
|
}
|
|
public void OnBattleClose(BattleField _battleField)
|
{
|
|
}
|
|
#region 截断网络派发包 只收入当前包的后续 b425是主线的 非主线的包并不会走b425
|
private bool allow = true;
|
|
private Queue<GameNetPackBasic> packQueue = new Queue<GameNetPackBasic>();
|
|
public bool IsCanDistributePackage(GameNetPackBasic _package)
|
{
|
if (_package is HB425_tagSCTurnFightReportSign)
|
{
|
HB425_tagSCTurnFightReportSign pkg = _package as HB425_tagSCTurnFightReportSign;
|
|
// 0-战报片段开始;1-战报片段结束;
|
if (pkg.Sign == 0)
|
{
|
allow = false;
|
}
|
else
|
{
|
allow = true;
|
|
// 发送战报片段结束包
|
AnalysisPackQueueAndDistribute();
|
|
}
|
}
|
else
|
{
|
if (!allow)
|
{
|
packQueue.Enqueue(_package);
|
}
|
}
|
|
return allow;
|
}
|
|
protected int continousEmptyCount = 0; // 连续空包计数
|
|
protected void AnalysisPackQueueAndDistribute()
|
{
|
// 建议前端做一个防范机制:当连续多次请求得到空的战斗片段封包时(不包含B425标记的开始跟结束封包,即开始跟中间没有任何封包),强制自动帮玩家回城休息,
|
// 原因可能前后端数据不一致bug(比如战锤可能后端没有了,前端认为还有)或者 后端有bug导致没有处理战斗
|
// 为防止死循环,可强制回城休息,让玩家重新点击关卡战斗或挑战boss,
|
// 正常情况下在战锤足够时理论上都可以一直循环刷怪,如果连续多次没有战斗片段封包,比如限制个连续10次以内,就可以理解为异常了
|
|
const int MaxContinousEmptyCount = 10; // 连续空包最大次数
|
|
List<GameNetPackBasic> packQueueSnapshot = new List<GameNetPackBasic>(packQueue);
|
|
List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>();
|
HashSet<int> skipIndexes = new HashSet<int>();
|
|
// 这里已经是按照Dequeue的顺序了
|
for (int i = 0; i < packQueueSnapshot.Count; i++)
|
{
|
if (skipIndexes.Contains(i)) continue;
|
|
GameNetPackBasic pack = packQueueSnapshot[i];
|
|
// 碰到B421 截断 往下收集b421里的全部内容
|
if (pack is HB421_tagMCTurnFightObjAction)
|
{
|
HB421_tagMCTurnFightObjAction b421Pack = pack as HB421_tagMCTurnFightObjAction;
|
|
List<GameNetPackBasic> b421PackList = new List<GameNetPackBasic>();
|
i++; // 跳过当前的B421包
|
|
for (; i < packQueueSnapshot.Count; i++)
|
{
|
GameNetPackBasic nextPack = packQueueSnapshot[i];
|
if (nextPack is HB421_tagMCTurnFightObjAction)
|
{
|
// 遇到了其他B421 启动角色的Action开始,
|
// B421后再碰到B421一定是有一个人的行动结束了 回退一个位置
|
i--;
|
break;
|
}
|
else
|
{
|
b421PackList.Add(nextPack);
|
skipIndexes.Add(i); // 标记已被合包
|
}
|
}
|
|
// 可能没用了 主要就是利用一下skill的combine 暂留 看之后还有没有别的需求
|
CustomB421ActionPack actionPack = CustomB421ActionPack.CreateB421ActionPack(GetGUID(b421Pack.packUID), b421PackList);
|
|
newPackList.Add(actionPack);
|
}
|
else
|
{
|
newPackList.Add(pack);
|
}
|
}
|
|
// 防范机制:连续多次没有战斗片段封包时自动回城
|
if (newPackList.Count == 0)
|
{
|
continousEmptyCount++;
|
Debug.LogWarning($"连续空战斗片段封包次数:{continousEmptyCount}");
|
if (continousEmptyCount >= MaxContinousEmptyCount)
|
{
|
Debug.LogError("连续多次没有战斗片段封包,自动回城休息!");
|
MainFightRequest(0); // 0-停止战斗回城
|
continousEmptyCount = 0;
|
packQueue.Clear();
|
return;
|
}
|
}
|
else
|
{
|
continousEmptyCount = 0; // 有包就重置
|
}
|
|
// b421跟b426的包已经处理完了
|
packQueue = new Queue<GameNetPackBasic>(newPackList);
|
|
DistributeNextPackage();
|
}
|
|
// 专属于主线战斗的派发
|
public bool DistributeNextPackage()
|
{
|
if (packQueue.Count > 0)
|
{
|
GameNetPackBasic pack = packQueue.Dequeue();
|
|
if (pack is CustomHB426CombinePack)
|
{
|
CustomHB426CombinePack combinePack = pack as CustomHB426CombinePack;
|
combinePack.Distribute();
|
}
|
else if (pack is CustomB421ActionPack)
|
{
|
CustomB421ActionPack actionPack = pack as CustomB421ActionPack;
|
actionPack.Distribute();
|
}
|
else
|
{
|
PackageRegedit.Distribute(pack);
|
}
|
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
public void OnConnected()
|
{
|
if (!allow)
|
{
|
allow = true;
|
packQueue.Clear();
|
|
// 重新发送要上一组战斗包的请求
|
// TODO YYL
|
}
|
}
|
|
#endregion
|
|
#region 战报部分
|
|
protected Dictionary<string, Queue<GameNetPackBasic>> battleReportDict = new Dictionary<string, Queue<GameNetPackBasic>>();
|
|
protected Dictionary<string, List<ulong>> battlePackRelationList = new Dictionary<string, List<ulong>>();
|
|
public void PushPackage(string guid, GameNetPackBasic vNetPack)
|
{
|
Queue<GameNetPackBasic> queue = null;
|
|
if (!battleReportDict.TryGetValue(guid, out queue))
|
{
|
queue = new Queue<GameNetPackBasic>();
|
}
|
|
queue.Enqueue(vNetPack);
|
|
List<ulong> uidList = null;
|
|
if (!battlePackRelationList.TryGetValue(guid, out uidList))
|
{
|
uidList = new List<ulong>();
|
}
|
|
uidList.Add(vNetPack.packUID);
|
}
|
|
public BattleField GetBattleField(ulong packUID)
|
{
|
return GetBattleField(GetGUID(packUID));
|
}
|
|
public BattleField GetBattleField(string guid)
|
{
|
BattleField battleField = null;
|
battleFields.TryGetValue(guid, out battleField);
|
return battleField;
|
}
|
|
public string GetGUID(ulong packUID)
|
{
|
foreach (var kv in battlePackRelationList)
|
{
|
if (kv.Value.Contains(packUID))
|
{
|
return kv.Key;
|
}
|
}
|
return string.Empty;
|
}
|
|
public void DistributeNextReportPackage(string guid)
|
{
|
Queue<GameNetPackBasic> queue = null;
|
|
if (!battleReportDict.TryGetValue(guid, out queue))
|
{
|
Debug.LogError("DistributeNextReportPackage could not find queue for guid : " + guid);
|
return;
|
}
|
|
PackageRegedit.Distribute(queue.Dequeue());
|
|
if (queue.Count <= 0)
|
{
|
battleReportDict.Remove(guid);
|
battlePackRelationList.Remove(guid);
|
}
|
}
|
#endregion
|
|
public BattleField CreateBattleField(string guid, int MapID, int FuncLineID, JsonData extendData, List<TeamBase> redTeamList, List<TeamBase> blueTeamList)
|
{
|
BattleField battleField = null;
|
|
if (battleFields.TryGetValue(guid, out battleField))
|
{
|
Debug.LogError("战场已存在 先进行销毁");
|
battleField.Destroy();
|
}
|
|
battleField = BattleFieldFactory.CreateBattleField(guid, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
|
|
onBattleFieldCreate?.Invoke(guid, battleField);
|
|
if (string.IsNullOrEmpty(guid))
|
{
|
storyBattleField = (StoryBattleField)battleField;
|
}
|
|
battleFields.Add(guid, battleField);
|
|
battleField.Init(MapID, FuncLineID, extendData, redTeamList, blueTeamList);
|
|
return battleField;
|
}
|
|
public void DestroyBattleField(BattleField battleField)
|
{
|
if (battleField == null)
|
{
|
Debug.LogError("DestroyBattleField called with null battleField");
|
return;
|
}
|
|
onBattleFieldDestroy?.Invoke(battleField.guid, battleField);
|
|
string guid = battleField.guid;
|
|
if (battleFields.ContainsKey(guid))
|
{
|
battleFields.Remove(guid);
|
}
|
|
if (storyBattleField == battleField)
|
{
|
storyBattleField = null;
|
}
|
|
GameObject.DestroyImmediate(battleField.battleRootNode.gameObject);
|
}
|
|
|
// 目前支持 BYTE ReqType; // 0-停止战斗回城;1-设置消耗倍值;2-挑战关卡小怪;3-挑战关卡boss;4-继续战斗;
|
// 0-停止战斗回城 - 玩家主动点击回城时发送
|
// 1-设置消耗倍值 - 玩家设置消耗倍值,对应到玩家FightPoint的值
|
// 2-挑战关卡小怪 - 玩家点击开始战斗时发送,仅从休息状态到开始战斗时发送即可
|
// 3-挑战关卡boss - 玩家请求挑战该关卡boss时发送
|
// 4-继续战斗 - 玩家主线战斗中(包含主线小怪、主线boss),前端表现完后端同步的战斗片段后,可再回复该值,后端会根据战斗逻辑及流程自动回复下一段的战斗片段封包,一直循环
|
public void MainFightRequest(byte reqType, uint reqValue = 0)
|
{
|
CB413_tagCSMainFightReq req = new CB413_tagCSMainFightReq();
|
req.ReqType = reqType;
|
req.ReqValue = reqValue;
|
|
GameNetSystem.Instance.SendInfo(req);
|
}
|
|
|
public void Run()
|
{
|
foreach (var battleField in battleFields)
|
{
|
battleField.Value?.Run();
|
}
|
}
|
|
}
|