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() 
 | 
    { 
 | 
        ulong exAttr1 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr1); 
 | 
        ulong 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(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
} 
 |