/*
 * 由SharpDevelop创建。
 * 用户： Administrator
 * 日期: 2018-11-16
 * 时间: 14:38
 *
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */

using System;
using MrWu.Debug;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Server.Data;
using Server.Pack;
using GameData;
using System.Text;
using GameDAL.FriendRoom;
using MrWu.core;
using Server.MQ;
using Server.Data.Module;
using Game.Player;
using MrWu.Basic;
using MrWu.Time;
using GameDAL;
using Newtonsoft.Json;
using Server.DB.Redis;
using GameMessage;
using ObjectModel.Game;
using Server.AliyunSDK.Logic;
using MessageData = GameData.MessageData;
using Server.Config;
using Server.Core;
using Server.DB.Sql;

namespace Server
{
    /// <summary>
    /// 桌子战斗结束
    /// </summary>
    /// <param name="StartTime">开战时间</param>
    public delegate void DeksWarOver(DateTime StartTime);


    /// <summary>
    /// 桌上玩家数量变化
    /// </summary>
    /// <param name="cnt"></param>
    /// <param name="isRobot"></param>
    public delegate void DeskPlayerChange(int cnt, bool isRobot);

    /// <summary>
    /// 桌子数据
    /// </summary>
    public abstract class Desk : IGameUtil, IGameBehavior<GamePack>, ICollection<PlayerDataAsyc>
    {
        /// <summary>
        /// 是否是比赛的桌子
        /// </summary>
        public bool IsMatchDesk;
        
        /// <summary>
        /// 是否正在恢复
        /// </summary>
        public bool waitRecover = false;

        /// <summary>
        /// 重连是否取消托管
        /// </summary>
        public virtual bool ReConnectCancelDeposit
        {
            get { return true; }
        }

        /// <summary>
        /// 战斗结束事件
        /// </summary>
        public virtual event DeksWarOver WarOverHandler;


        /// <summary>
        /// 玩家变化事件
        /// </summary>
        public virtual event DeskPlayerChange PlayerChangeHandler;

        public readonly CommonDeskData DeskOtherData = new CommonDeskData();
        
        /// <summary>
        /// 桌子信息
        /// </summary>
        public DeskInfo deskinfo { get; private set; }

        private readonly int mid;

        /// <summary>
        /// 桌子的索引
        /// </summary>
        public int id => mid;

        private int mRealPerson;

        /// <summary>
        /// 真人数量
        /// </summary>
        public int RealPerson => mRealPerson;

        /// <summary>
        /// 是否全真人且满人了
        /// </summary>
        public bool AllRealPerson
        {
            get { return RealPerson == PlayerCnt; }
        }

        /// <summary>
        /// 游戏模式
        /// </summary>
        public int gameMode
        {
            get { return ServerConfigManager.Instance.GameMode; }
        }

        protected DateTime mwarTime = DateTime.Now;

        /// <summary>
        /// 开战时间
        /// </summary>
        public DateTime warTime => mwarTime;

        public bool IsNearingOver
        {
            get;
            set;
        }

        #region 统计

        /// <summary>
        /// 总开战时间
        /// </summary>
        public long totalWarTime;

        /// <summary>
        /// 战斗次数
        /// </summary>
        public int warTimeCnt;

        #endregion

        /// <summary>
        /// 战斗超时时间
        /// </summary>
        public int warTimeOut
        {
            get { return ServerConfigManager.Instance.GoldDeskWarTimeOut; }
        }

        /// <summary>
        /// 上次未开战时玩家的人数
        /// </summary>
        protected int lastWiatPlayerCnt = 0;

        /// <summary>
        /// 桌子的状态
        /// 创建桌子时 桌子为闲置状态
        /// 当金币场排队时,或者朋友房等待人时 为排队状态
        /// </summary>
        public DeskState state { get; set; }

        /// <summary>
        /// 最大上桌的机器人数量
        /// </summary>
        public int MaxRobot
        {
            get { return tingConfig.DeskMaxRobotCnt; }
        }

        private int _halfPlayer = -1;

        /// <summary>
        /// 一半的最大玩家数量
        /// </summary>
        protected int halfPlayer
        {
            get
            {
                if (_halfPlayer < 0)
                    _halfPlayer = Count / 2;
                return _halfPlayer;
            }
        }

        private int _towThirds = -1;

        /// <summary>
        /// 最大玩家数量的三分之二
        /// </summary>
        protected int towThirds
        {
            get
            {
                if (_towThirds < 0)
                    _towThirds = 2 * Count / 3;
                return _towThirds;
            }
        }

        /// <summary>
        /// 玩家列表 必须是数组_需要位置固定
        /// </summary>
        protected PlayerDataAsyc[] pls;

        /// <summary>
        /// 获取桌上的一个玩家
        /// </summary>
        /// <param name="idx"></param>
        /// <returns></returns>
        public PlayerDataAsyc this[int idx]
        {
            get { return pls[idx]; }
        }

        /// <summary>
        /// 托管玩家列表
        /// </summary>
        public List<int> DepositList = new List<int>();

        protected readonly List<int> tempUserId = new List<int>();

        /// <summary>
        /// 当前的玩家数量
        /// </summary>
        public int PlayerCnt { get; protected set; }

        /// <summary>
        /// 厅管理
        /// </summary>
        public readonly TingManager ting;

        /// <summary>
        /// 厅配置
        /// </summary>
        public readonly Server.Config.TingConfig tingConfig;

        /// <summary>
        /// 
        /// </summary>
        public int tingid
        {
            get { return ting.id; }
        }

        /// <summary>
        /// //临时变量
        /// </summary>
        protected long moenyInterval;

        private GameDo mgamelogic;

        /// <summary>
        /// 游戏逻辑
        /// </summary>
        public GameDo gameLogic
        {
            get { return mgamelogic; }
        }

        /// <summary>
        /// 战斗数据记录
        /// </summary>
        public FightData fightdata { get; set; }

        /// <summary>
        /// 上次真人数量
        /// </summary>
        private int lastPlayerCount = -1;

        /// <summary>
        /// 上次所有玩家数量
        /// </summary>
        private int lastAllPlayerCount = -1;

        /// <summary>
        /// 上次上桌的概率
        /// </summary>
        private decimal robotProability = 1;

        protected readonly Random random;

        /// <summary>
        /// 房间ID
        /// </summary>
        public int RoomId;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ting"></param>
        /// <param name="tingConfig"></param>
        /// <param name="id"></param>
        /// <param name="info"></param>
        public Desk(TingManager ting, Server.Config.TingConfig tingConfig, int id, DeskInfo info = null)
        {
            this.ting = ting;
            this.tingConfig = tingConfig;
            this.mid = id;
            this.deskinfo = info;
            this.random = new Random(unchecked((int)DateTime.UtcNow.Ticks));
            if (isFriend)
                pls = new PlayerDataAsyc[info.rule.maxCnt];
            else
                pls = new PlayerDataAsyc[tingConfig.MaxPlayerCnt];
        }

        /// <summary>
        /// 设置桌子的信息
        /// </summary>
        /// <param name="info"></param>
        public void SetDeskInfo(DeskInfo info)
        {
            this.deskinfo = info;
            this.pls = new PlayerDataAsyc[info.rule.maxCnt];
            this.PlayerCnt = 0;
        }

        /// <summary>
        /// 清空桌子上的人
        /// </summary>
        public void ClearPlayer()
        {
            if (state != DeskState.Idle) return;
            for (int i = 0; i < pls.Length; i++)
            {
                if (pls[i] == null) continue;
                if (pls[i].isRobot) pls[i].RobotInit();
                pls[i] = null;
            }
        }

        /// <summary>
        /// 设置玩家的数量
        /// </summary>
        /// <param name="pl"></param>
        /// <param name="isquit"></param>
        public void PlayerChange(PlayerDataAsyc pl, bool isquit = false)
        {
            int cnt = 0;
            if (isquit)
            {
                cnt = -1;
                PlayerCnt--;
                if (!pl.isRobot)
                    mRealPerson--;
            }
            else
            {
                cnt = 1;
                PlayerCnt++;
                if (!pl.isRobot)
                    mRealPerson++;
            }

            if (PlayerChangeHandler != null)
                this.PlayerChangeHandler(cnt, pl.isRobot);
        }

        /// <summary>
        /// 玩家托管列表，有先后顺序
        /// </summary>
        public readonly List<int> DepositUserIds = new List<int>();

        public Action<int> DepositChangeHandler;
        
        /// <summary>
        /// 玩家托管状态发生变化
        /// </summary>
        public virtual void PlayerDepositChange(playerData pl)
        {
            if (pl == null)
            {
                return;
            }

            if (pl.seat >= 0 && pl.seat < pls.Length && pls[pl.seat] == pl)
            {
                if (pl.isDePosit)
                {
                    if (!DepositUserIds.Contains(pl.userid))
                    {
                        DepositUserIds.Add(pl.userid);
                    }
                }
                else
                {
                    DepositUserIds.Remove(pl.userid);
                }
            }
            
            DepositChangeHandler?.Invoke(pl.seat);
        }

        /// <summary>
        /// 桌子上有玩家的设备信息发生变化
        /// </summary>
        public virtual void ChangePosition()
        {
        }

        #region IGameWinMoney

        /// <summary>
        /// 赢的游戏币
        /// </summary>
        public Int64 winmoney { get; private set; }

        /// <summary>
        /// 税收的钱
        /// </summary>
        public Int64 taxmoney { get; private set; }

        /// <summary>
        /// 增加赢的游戏币
        /// </summary>
        /// <param name="money"></param>
        public void AddWinMoney(long money)
        {
            winmoney += money;
            ting.AddWinMoney(money);
        }

        /// <summary>
        /// 增加税收的钱
        /// </summary>
        /// <param name="money"></param>
        public void AddTaxMoney(long money)
        {
            taxmoney += money;
            ting.AddTaxMoney(money);
        }

        #endregion

        #region IGameBehavior

        /// <summary>
        /// 下一个处理者
        /// </summary>
        public IGameBehavior<GamePack> NextBehavior
        {
            get { return gameLogic; }
        }

        /// <summary>
        /// 是否开战
        /// </summary>
        public bool isWar
        {
            get { return NextBehavior.isWar; }
        }

        /// <summary>
        /// 开战
        /// </summary>
        public virtual void StartWar()
        {
            mwarTime = DateTime.Now;
            if ((state & DeskState.Queue) > 0)
            {
                //开战了一般来说就不能加入了
                ting.RemoveQueue(this);
            }

            //添加到战斗列表
            ting.AddWaring(this);
        }

        /// <summary>
        /// 处理子游戏包
        /// </summary>
        /// <param name="pack">包裹</param>
        public void DoZyxPack(GamePack pack)
        {
            NextBehavior.DoZyxPack(pack);
        }

        /// <summary>
        /// 服务器维护，发送禁止开战包
        /// </summary>
        public void SendNoWarPack()
        {
            PackHead head = PackHead.Create(GamePackAgreement.pack_error);
            SendAllPack(head, new TipInfo(0, 1));
            head.Dispose();
        }

        /// <summary>
        /// 重连
        /// </summary>
        /// <param name="seat"></param>
        public virtual void Reconnect(int seat)
        {
            if (ReConnectCancelDeposit)
            {
                GameManager.instance.DoTuoGuanCalc(pls[seat], false);
            }

            foreach (var item in pls)
            {
                if (item == null) continue;
                if (item.isRobot) continue;
                SendAllPlayerInfo(item);
            }

            SendOtherData(-1);
            
            if ((state & DeskState.War) > 0)
            {
                if (seat < -1 || PlayerCnt <= seat)
                {
                    Debug.Error("玩家重连时位置错误：" + PlayerCnt + "," + seat + "," + (pls[seat] == null));
                }

                NextBehavior.Reconnect(seat);
            }
        }

        /// <summary>
        /// 战斗结束
        /// </summary>
        public virtual void WarOver()
        {
            if (WarOverHandler != null)
                WarOverHandler(warTime);

            WarUpdateData();
        }

        /// <summary>
        /// 计算战斗时间
        /// </summary>
        public void AddWarTime()
        {
            long tmp = (long)(DateTime.Now - warTime).TotalSeconds;
            totalWarTime = totalWarTime + tmp; //战斗总时长
            warTimeCnt++; //战斗次数
        }

        /// <summary>
        /// 游戏结束更新玩家数据_去通知数据中心，改变游戏币
        /// </summary>
        public void WarUpdateData()
        {
            int len = pls.Length;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] == null || pls[i].isRobot)
                    continue;

                if (pls[i].moneyChange != 0 || pls[i].expChange != 0)
                {
                    long key = Debug.StartTiming();
                    PlayerDataChange pdc = PlayerDataChange.Create(pls[i].userid);
                    pdc.moneyChange = pls[i].moneyChange;
                    pdc.expChange = pls[i].expChange;
                    pdc.MoneyBak = pls[i].money;
                    PlayerFun.WritePlayerDataAsync(pdc);
                    Debug.Info("写数据时间:" + Debug.GetRunTime(key));
                    // Debug.ImportantLog($"玩家-deskid:{pls[i].deskid},userid:{pls[i].userid},moneyChange:{pls[i].moneyChange},expChange:{pls[i].expChange}");

                    pls[i].moneyChange = 0;
                    pls[i].expChange = 0;
                }
                else
                {
                    Debug.Info("玩家数据未变化:" + pls[i].userid);
                }
            }
        }


        /// <summary>
        /// 加载桌子
        /// </summary>
        public abstract bool LoadDesk();

        /// <summary>
        /// 玩家离线
        /// </summary>
        /// <param name="seat">某座位的玩家离线</param>
        public virtual void OutLine(int seat)
        {
            NextBehavior.OutLine(seat);
            if (isFriend) //朋友房,发送玩家离线包
                SendDeskInfoAll(GameSeverAgreement.friendLeave, new int[] { pls[seat].userid });

            SendPlayerOutLineChange(seat);
        }

        /// <summary>
        /// 某个座位的玩家退出了游戏
        /// </summary>
        /// <param name="seat">座位</param>
        public virtual void Quit(int seat)
        {
            NextBehavior.Quit(seat);
        }

        /// <summary>
        /// 玩家是否可以退出此桌子
        /// </summary>
        /// <param name="seat">座位</param>
        /// <returns></returns>
        public virtual bool CanQuit(int seat)
        {
            //判断玩家在不在桌子上, 不在桌子上肯定是不能退出的

            if (deskinfo != null && !deskinfo.noWar)
                return false;


            if ((state & DeskState.Idle) > 0)
            {
                Debug.Error("玩家怎么会在闲置的桌子中，服务器错误!");
                return false;
            }

            if (seat < 0)
            {
                Debug.Error("玩家不在这个桌子怎么退出桌子!" + seat);
                return false;
            }

            return NextBehavior.CanQuit(seat);
        }

        #endregion

        /// <summary>
        /// 设置游戏逻辑
        /// </summary>
        /// <param name="gd"></param>
        public void SetGameLogic(GameDo gd)
        {
            mgamelogic = gd;
        }

        #region ICollection

        /// <summary>
        /// 座位数量
        /// </summary>
        public int Count
        {
            get
            {
                if (!isFriend)
                    return tingConfig.MaxPlayerCnt;
                return deskinfo.rule.maxCnt;
            }
        }

        /// <summary>
        /// 只读的
        /// </summary>
        public bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        void ICollection<PlayerDataAsyc>.Add(PlayerDataAsyc item)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        void ICollection<PlayerDataAsyc>.Clear()
        {
        }

        /// <summary>
        /// 是否存在某玩家
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(PlayerDataAsyc item)
        {
            if (item == null)
                return false;
            if (item.seat < 0 || item.seat >= Count)
            {
                return false;
            }

            if (pls[item.seat] == null)
            {
                Debug.Warning("查询玩家数据时对应座位上的玩家不存在:" + item.ToString());
                return false;
            }

            return true;
        }

        /// <summary>
        /// 拷贝至array 数组中
        /// </summary>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        public void CopyTo(PlayerDataAsyc[] array, int arrayIndex)
        {
            Array.Copy(pls, 0, array, arrayIndex, Count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        bool ICollection<PlayerDataAsyc>.Remove(PlayerDataAsyc item)
        {
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        /// <summary>
        /// 迭代器
        /// </summary>
        /// <returns></returns>
        public IEnumerator<PlayerDataAsyc> GetEnumerator()
        {
            return new ArrayEnumerator<PlayerDataAsyc>(pls);
        }

        #endregion

        /// <summary>
        /// 检查玩家是否有与此ip相同的
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public bool CheckPlayersIP(string ip)
        {
            PlayerDataAsyc tmppl;
            int len = Count;
            for (int i = 0; i < len; i++)
            {
                tmppl = pls[i];
                if (tmppl == null) continue;
                if (tmppl.ip == ip)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 添加到玩家列表
        /// </summary>
        /// <returns>返回座位号,-1表示添加失败</returns>
        protected abstract int AddPlayerArray(PlayerDataAsyc pl, int roomid);

        /// <summary>
        /// 加入桌子
        /// </summary>
        /// <param name="pl">玩家</param>
        /// <param name="roomid">房间id</param>
        /// <returns>true 表示加入成功 false 表示加入失败</returns>
        public abstract bool AddPlayer(PlayerDataAsyc pl, int roomid);

        /// <summary>
        /// 从桌上移除玩家
        /// </summary>
        /// <param name="pl"></param>
        /// <returns></returns>
        public abstract bool RemovePlayer(PlayerDataAsyc pl);

        /// <summary>
        /// 检查房间是否是空房间
        /// </summary>
        /// <returns></returns>
        public virtual bool CheckRoomIsEmpty()
        {
            return RealPerson == 0; //真人数为0表示空房间
        }

        #region ITimerProcessor

        /// <summary>
        /// 游戏定时器
        /// </summary>
        public virtual void OnTime(int interval)
        {
            if ((state & DeskState.War) > 0)
            {
                if (waitRecover)
                {
                    return;
                }

                gameLogic.OnTime(interval);
            }
        }

        /// <summary>
        /// 秒级定时器
        /// </summary>
        public abstract void SecondTime();

        #endregion

        /// <summary>
        /// 准备
        /// </summary>
        public virtual void Ready(PlayerDataAsyc pl, bool isSendPack = false)
        {
            //玩家桌子deskid 是 -1 但却在桌子列表里头

            if (pl.deskid != id)
            {
                Debug.Error("准备出错不是本桌子:" + pl.deskid + "," + id + "," + pl.userid + "," + pl.id + "," + isSendPack);
                return;
            }

            if (pl.state != (int)PlayerState.Desk)
            {
                Debug.Warning("状态不对，不是在桌上状态！" + pl.userid + "," + pl.id + "," + pl.state);
                return;
            }
            else
            {
                pl.state = (int)PlayerState.Ready;
                if (isSendPack)
                    SendPlayerStateChange(pl.seat);

                Debug.Log("玩家准备好了:" + pl.userid);
            }
        }

        public virtual async void UsingHandTracker(PlayerDataAsyc pl,UsingHandTrackerData pack)
        {
            if (state != DeskState.War)
            {
                Debug.Info("桌子的状态不是开战。使用失败!");
                return;
            }
            
            //桌子信息
            if (deskinfo != null)
            {
                Debug.Info("朋友房桌子，不让使用记牌器!");
                return;
            }

            // //有比赛  比赛也让用
            // if (pl.MatchObj != null)
            // {
            //     Debug.Info("有比赛，不让使用记牌器");
            //     return;
            // }

            if(DeskOtherData.IsUsingHandTacker == null || pl.seat >= DeskOtherData.IsUsingHandTacker.Length)
            {
                Debug.Error("数据错误，记牌器数据未初始化!");
                return;
            }

            if (DeskOtherData.IsUsingHandTacker[pl.seat])
            {
                Debug.Info("正在使用记牌器，无需再次使用!");
                return;
            }

            //判断记牌器是否充足
            PropManager.UserPropData propData = await PropManager.Instance.GetUserPropDataAsync(pl.userid);
            if (DeskOtherData.IsUsingHandTacker[pl.seat])
            {
                Debug.Info("正在使用记牌器，无需再次使用!");
                return;
            }

            if (pack.ConsumeType != 2 && pack.ConsumeType != 1)
            {
                Debug.Info($"没有这种消耗类型:{pack.ConsumeType} {pl.userid}");
                return;
            }

            //钻石
            if (pack.ConsumeType == 2)
            {
                if (pl.MatchRoll < ConstConfigCategory.Instance.HandTrackerDiamondCnt)
                {
                    Debug.Info("使用记牌器失败，钻石不足!");
                    return;
                }
            }

            if (pack.ConsumeType == 1)
            {
                int handTracker = propData.GetPropCount(PropType.HandTracker);
                if (handTracker <= 0)
                {
                    Debug.Info("记牌器不足!");
                    return;
                }
            }
            
            DeskOtherData.IsUsingHandTacker[pl.seat] = true;
            SendOtherData(pl.seat);
            
            if (pack.ConsumeType == 1)
            {
                pack.ConsumeValue = 1;
                propData.AddProp(PropType.HandTracker, -pack.ConsumeValue,"使用记牌器");
                PropManager.Instance.SaveUserPropDataRedis(pl.userid, false);
            }else if (pack.ConsumeType == 2)
            {
                pack.ConsumeValue = ConstConfigCategory.Instance.HandTrackerDiamondCnt;
                PlayerDataChange pdc = PlayerDataChange.Create(pl.userid);
                pdc.MatchRollChange -= pack.ConsumeValue;
                _ = PlayerFun.WritePlayerDataAsync(pdc);
                pl.MatchRoll -= pack.ConsumeValue;
                propData.AddLog(ResName.Diamond,-pack.ConsumeValue,pl.MatchRoll,"使用记牌器");
            }
            SendUsingHandTrackerData(pl.seat,pack);
        }

        /// <summary>
        /// 发送桌子其他数据
        /// </summary>
        /// <param name="seat"></param>
        public void SendOtherData(int seat)
        {
            DeskOtherDataResponse response = DeskOtherDataResponse.Create(DeskOtherData);
            byte[] data = MessagePackHelper.Serialize(response);
            PackHead head = PackHead.Create(GameSeverAgreement.DeskOtherData);
            int len = pls.Length;
            string jsonData = null;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] == null) continue;

                if (seat != -1 && i != seat) continue;
                pls[i].SendPack2Client(head,data,false,ref jsonData);
            }
            
            response.Dispose();
            head.Dispose();
        }

        public void SendUsingHandTrackerData(int seat,UsingHandTrackerData response)
        {
            if (seat < 0 || seat >= pls.Length || pls[seat] == null)
            {
                return;
            }
            
            Debug.Info("发送使用记牌器数据!");
            byte[] data = MessagePackHelper.Serialize(response);
            PackHead head = PackHead.Create(GameSeverAgreement.UsingHandTracker);

            string jsonData = null;
            pls[seat].SendPack2Client(head,data,false,ref jsonData);
            head.Dispose();
        }

        /// <summary>
        /// 处理道具包
        /// </summary>
        /// <param name="pack"></param>
        /// <returns></returns>
        public virtual bool DoProps(GamePack pack)
        {
            PropsPack cp = JsonPack.GetData<PropsPack>(pack.JsonData);

            if (cp == null || cp.sendId <= 0 || cp.PropsId <= 0 || cp.Count <= 0)
            {
                Debug.Error("客户端发包错误:道具包无效:" + pack.JsonData);
                return true;
            }

            //应该还要扣除玩家身上的道具
            int ret = gameLogic.DoProps(cp);
            if(ret < -1)
                return false;

            if (ret == -1)
            {
                //发送给所有玩家
                SendAllPack(pack.Head, pack.JsonData);
            }
            else
            {
                SendPack(ret, pack.Head, pack.JsonData);
            }
            return false;
        }

        /// <summary>
        /// 处理聊天包
        /// </summary>
        /// <param name="pack">包裹</param>
        public bool DoChatPack(GamePack pack)
        {
            int ret = gameLogic.DoChatNewPack(pack);
            if (ret < -1)
                return true;
            
            int seat = pack.pl.seat;
            string jsondata = pack.JsonData;

            ChatPack cp = JsonPack.GetData<ChatPack>(jsondata);

            if (cp == null)
            {
                Debug.Error("客户端发包错误:聊天包没包体:" + jsondata);
                return true;
            }

            PackHead head = PackHead.Create();


            int roomid = pls[seat].roomid;

            int len = pls.Length;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] == null) continue;

                if (ret != -1 && i != ret) continue;
                
                if (!isFriend && gameMode != 1 && seat != i)
                {
                    //不是朋友房 且不是 百家乐
                    cp.sendName = pls[seat].shadows[pls[i].roomid].nickname;

                    Debug.Info("取影子的名字:" + seat + "," + i + "," + cp.sendName);
                }
                else
                {
                    cp.sendName = pls[seat].nickname;

                    Debug.Info("取真实名字:" + seat + "," + i + "," + cp.sendName);
                }

                head.packlx = GameSeverAgreement.chatDesk;
                GameNet.SendPack(pls[i], head, cp);
            }
            head.Dispose();

            return true;
        }

        #region IGameUtil

        /// <summary>
        /// 是否是朋友房
        /// </summary>
        public abstract bool isFriend { get; }

        /// <summary>
        /// 初始化
        /// </summary>
        public virtual void Init()
        {
            DepositUserIds.Clear();
        }

        /// <summary>
        /// 获取整数值数据
        /// </summary>
        /// <param name="lx">类型</param>
        /// <returns></returns>
        public virtual int GetIntValue(string lx)
        {
            switch (lx)
            {
                case "0": //桌上最大人数
                    Debug.Error("这个信息应该转至厅!");
                    return -1;
                case "1": //桌上当前人数
                    return PlayerCnt;
                case "2": //开战最小人数
                    Debug.Error("这个信息应该转至厅!");
                    break;
                case "3": //桌所在房间id
                    Debug.Error("废弃字段,桌子只属于厅!");
                    break;
                case "4": //规则idx 用的第几个规则,也就是第几个厅
                    return tingid;
                //Debug.Error("啥规则xxx");
                case "5": //是否开战中
                    if (isWar)
                        return 1;
                    return 0;
                case "6": //开战最大人数
                    Debug.Error("这个信息应该去问厅要!");
                    break;

                case "7": //是否朋友房桌子
                    return isFriend ? 1 : 0;

                case "8": //已完成局数 原来的gameint 6 - - 0
                    //Debug.Error("来包获取已完成的局数!");
                    if (isFriend)
                    {
                        Debug.Log("已完成的局数:" + deskinfo.overCnt);
                        return deskinfo.overCnt;
                    }

                    break;
                case "9": //当前局数-1 第几局
                    //Debug.Error("来包获取当前是第几局!");
                    if (isFriend)
                    {
                        Debug.Log("当前的局数:" + deskinfo.nowCnt);
                        return deskinfo.nowCnt - 1;
                    }

                    break;
                case "10": //是否是vip
                    Debug.Log("没有vip字段!");
                    break;
                case "11": //创建者id
                    if (isFriend)
                        return deskinfo.creatUserid;
                    break;
                case "12": //朋友房总盘数
                    if (isFriend)
                        return deskinfo.rule.warCnt;
                    break;
                case "13": //座位数量
                    //Debug.Error("这里注意--以前是固定数量,现在是动态!");
                    //Debug.Error("获取座位数量:" + isFriend + "," + deskinfo.rule.maxCnt);
                    if (isFriend)
                        return deskinfo.rule.maxCnt;
                    return Count;
                case "14": //创建类型  原0玩家 1竞技比赛 2代开   现在 0普通开  1代开房间  5竞技比赛创建房间
                    Debug.Info("字段值已改变，注意修改!");
                    if (isFriend)
                        return deskinfo.creatStyle;
                    break;
                // case "15"://是否托管代打房间
                //     AutoReady();
                //     break;
                case "16":
                    return id;
                case "20": //获取是否需要发牌，返回需要发牌的位置.位置从0开始，-1就不需要发牌
                    return -1;
                default:
                    Debug.Warning("未解析的absdjh:" + lx);
                    break;
            }

            return -1;
        }

        /// <summary>
        /// 获取字符串类型信息
        /// </summary>
        /// <param name="lx">lx</param>
        /// <returns></returns>
        public virtual string GetStringValue(string lx)
        {
            switch (lx)
            {
                case "0":
                    break;
                case "1":
                    break;
                case "2":
                    break;
                case "3":
                    break;
                case "4":
                    break;
                case "5": //获取朋友房桌子的规则 100个
                    if (isFriend)
                    {
                        Debug.Info("获取到朋友房规则:" + deskinfo.rule.roomrule);
                        return deskinfo.rule.roomrule;
                    }

                    break;
            }

            Debug.Error("暂时没有什么可以解析的!" + lx);
            return string.Empty;
        }

        /// <summary>
        /// 获取桌子数据
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public virtual object GetData(string tag)
        {
            return null;
        }

        #endregion

        /// <summary>
        /// 强行闪桌
        /// </summary>
        public void ForceWarOver()
        {
            if ((state & DeskState.War) == 0)
            {
                Debug.Warning("桌子当前未开战!");
                return;
            }

            Debug.Warning("强制结束房间!");
            gameLogic.WarOver();
        }

        #region 查找玩家

        /// <summary>
        /// 查某个玩家是否存在
        /// </summary>
        /// <param name="userid"></param>
        /// <returns>true 表示玩家在桌上 false 表示玩家不在桌 </returns>
        public bool Exists(int userid)
        {
            return FindPlayer(userid) >= 0;
        }

        /// <summary>
        /// 是否存在某个玩家
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool isExists(int id)
        {
            int len = pls.Length;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] != null && pls[i].id == id)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 查某个玩家是否存在
        /// </summary>
        /// <param name="pl">玩家数据</param>
        /// <returns>true 表示玩家在桌上 false 表示玩家不在桌上</returns>
        public bool Exists(PlayerDataAsyc pl)
        {
            return FindPlayer(pl) >= 0;
        }

        /// <summary>
        /// 查找一个玩家，返回座位号，如果桌子上没有这个玩家，则返回-1
        /// </summary>
        /// <param name="pl"></param>
        /// <returns>-1表示桌上没这个人,大于等于0表示玩家所在位置</returns>
        public int FindPlayer(PlayerDataAsyc pl)
        {
            return FindPlayer(pl.userid);
        }

        /// <summary>
        /// 查找一个玩家,返回座位号，如果桌子上没有这个玩家,则返回-1
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public int FindPlayer(int userid)
        {
            int len = pls.Length;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] == null) continue;
                if (pls[i].userid == userid)
                    return i;
            }

            return -1;
        }

        #endregion

        #region 发送数据包

        /// <summary>
        /// 发包给所有玩家
        /// </summary>
        /// <param name="head">包头</param>
        /// <param name="data">包数据</param>
        /// <param name="userid">排除谁</param>
        public void SendAllPack(PackHead head, object data = null, int userid = -1)
        {
            int len = Count;
            PlayerDataAsyc tmppl;
            int packlx = head.packlx;
            for (int i = 0; i < len; i++)
            {
                tmppl = pls[i];
                if (tmppl == null || tmppl.userid == userid) continue;
                head.packlx = packlx;
                GameNet.SendPack(tmppl, head, data);
            }
        }

        /// <summary>
        /// 发包给所有玩家
        /// </summary>
        /// <param name="head"></param>
        /// <param name="jsonmessage"></param>
        /// <param name="userid">排除谁</param>
        public void SendAllPack(PackHead head, string jsonmessage, int userid = -1)
        {
            int len = Count;
            PlayerDataAsyc tmppl;
            int packlx = head.packlx;
            for (int i = 0; i < len; i++)
            {
                tmppl = pls[i];
                if (tmppl == null || tmppl.userid == userid) continue;
                head.packlx = packlx;
                GameNet.SendPack(tmppl, head, jsonmessage);
            }
        }

        public void SendPack(int seat, PackHead head, string jsonMessage)
        {
            if (seat < 0 || seat >= Count)
            {
                return;
            }

            PlayerDataAsyc tmppl = pls[seat];
            if (tmppl != null)
            {
                GameNet.SendPack(tmppl, head, jsonMessage);
            }
        }

        /// <summary>
        /// 发送子游戏包
        /// </summary>
        /// <param name="seat">小于0发全桌</param>
        /// <param name="data">数据</param>
        /// <param name="native">原生代码</param>
        public virtual void SendZyxPack(int seat, byte[] data,bool native)
        {
            PackHead head = PackHead.Create(); //发送开战信号
            head.packlx = GameSeverAgreement.zyxPack;
            
            if ((state & DeskState.War) == 0)
            {
                Debug.Warning("未开战不能发送子游戏包!");
                return;
            }

            string jsonMessage = null;
            PlayerDataAsyc tempPlayer;
            int len = Count;
            for (int i = 0; i < len; i++)
            {
                if (seat < 0 || seat == i)
                {
                    tempPlayer = pls[i];
                    if (tempPlayer == null) continue;
                    tempPlayer.SendPack2Client(head,data,native,ref jsonMessage);
                }
            }

            if (seat >= Count)
            {
                Debug.Warning("发包位置大于桌子人数!" + seat + "," + PlayerCnt);
            }
                
            head.Dispose();
        }


        /// <summary>
        /// 发送添加玩家
        /// </summary>
        /// <param name="pl"></param>
        public virtual void SendAddPlayer(PlayerDataAsyc pl)
        {
            PackHead head = PackHead.Create();

            int len = Count;
            PlayerDataAsyc tmppl;
            for (int i = 0; i < len; i++)
            {
                tmppl = pls[i];
                if (tmppl == null || tmppl == pl || tmppl.isRobot) continue;
                head.packlx = GameSeverAgreement.deskPlayerInfo;

                //把替身信息发出去 是比赛桌，但是玩家没有参加比赛
                pl.UpdateShadow(tmppl.roomid,IsMatchDesk && !tmppl.IsJoinMatch);

                GameNet.SendPack(tmppl, head, GetAddPlayerPack(pl.seat, pl.currShadow,tmppl.ClientVer < VersionConfigCategory.Instance.CVersion48));
            }
            head.Dispose();
        }


        /// <summary>
        /// 获取增加玩家包裹
        /// </summary>
        /// <param name="index_">第几个位置</param>
        /// <param name="dt">玩家数据</param>
        /// <returns></returns>
        public static DeskPlayerData<PlayerDataAsyc> GetAddPlayerPack(int index_, PlayerDataAsyc dt,bool IsClone)
        {
            if (IsClone)
            {
                dt = dt.Clone();
            }
            return new DeskPlayerData<PlayerDataAsyc>()
            {
                style = 0,
                index = index_,
                datas = new playerData[] { dt }
            };
        }

        /// <summary>
        /// 移除一个玩家包裹
        /// </summary>
        /// <param name="index_">第几个玩家</param>
        /// <returns></returns>
        public static DeskPlayerData<PlayerDataAsyc> GetRemovePlayerPack(int index_)
        {
            return new DeskPlayerData<PlayerDataAsyc>()
            {
                style = 1,
                index = index_,
                datas = new playerData[0]
            };
        }

        /// <summary>
        /// 所有玩家数据
        /// </summary>
        /// <param name="dts">所有的玩家</param>
        /// <param name="roomid">房间编号</param>
        /// <returns></returns>
        protected DeskPlayerData<PlayerDataAsyc> GetAllPayerPack(PlayerDataAsyc[] dts, PlayerDataAsyc pl)
        {
            int roomid = pl.roomid;
            bool isClone = pl.ClientVer < VersionConfigCategory.Instance.CVersion48;
            bool isForceShdow = IsMatchDesk && !pl.IsJoinMatch;
            DeskPlayerData<PlayerDataAsyc> dp = new DeskPlayerData<PlayerDataAsyc>
            {
                style = 2
            };

            int len = dts.Length;
            dp.datas = new playerData[len];
            for (int i = 0; i < len; i++)
            {
                if (dts[i] != null)
                {
                    dts[i].UpdateShadow(roomid,(pl.userid != dts[i].userid) && isForceShdow);
                    
                    if (isClone)
                    {
                        dp.datas[i] = dts[i].currShadow.Clone();
                        dp.datas[i].roomid = CastleHelper.GetVirtualCastle(roomid);
                    }
                    else
                    {
                        dp.datas[i] = dts[i].currShadow;
                    }
                    
                    Debug.Info($"GetAllPayerPack {i} {isClone} {dp.datas[i].roomid}");
                    //Debug.Log("用户的ip地址:" + dts[i].ip + "," + dp.datas[i].ip);
                }
            }

            return dp;
        }

        /// <summary>
        /// 发送移除玩家包
        /// </summary>
        /// <param name="seat">座位</param>
        public virtual void SendRemovePlayer(int seat)
        {
            PackHead head = PackHead.Create();

            PlayerDataAsyc tmppl;


            for (int i = 0; i < Count; i++)
            {
                tmppl = pls[i];
                if (tmppl == null) continue;
                head.packlx = GameSeverAgreement.deskPlayerInfo;
                GameNet.SendPack(tmppl, head, GetRemovePlayerPack(seat));
            }
            head.Dispose();
        }

        /// <summary>
        /// 发送桌上所有玩家信息给玩家
        /// </summary>
        /// <param name="pl">发给哪个玩家</param>
        /// <param name="isSelf">是否只发自己的信息</param>
        public virtual void SendAllPlayerInfo(PlayerDataAsyc pl, bool isSelf = false)
        {
            PackHead head = PackHead.Create(GameSeverAgreement.deskPlayerInfo); // new ServerHead();
            Debug.Log("发送所有玩家信息：" + pl.tingid);

            if (isSelf)
            {
                PlayerDataAsyc[] tmppls = new PlayerDataAsyc[pls.Length];
                int len = pls.Length;
                int tmpcnt = 0;
                for (int i = 0; i < len; i++)
                {
                    if (pls[i] != null && pls[i].userid == pl.userid)
                    {
                        tmpcnt++;
                        tmppls[i] = pl;
                        break;
                    }
                }

                Debug.Log("发送所有玩家信息给自己:" + tmppls.Length + "," + tmpcnt);

                GameNet.SendPack(pl, head, GetAllPayerPack(tmppls, pl));
            }
            else
                GameNet.SendPack(pl, head, GetAllPayerPack(pls, pl));

            head.Dispose();
        }

        /// <summary>
        /// 发送开战信息
        /// </summary>
        protected virtual void SendStartWar()
        {
            PackHead head = PackHead.Create(GameSeverAgreement.startWar);
            Debug.Log("发送房间开战信号!");
            SendAllPack(head);
            head.Dispose();
        }

        /// <summary>
        /// 发送战斗结束
        /// </summary>
        protected virtual void SendWarOver()
        {
            PackHead head = PackHead.Create(GameSeverAgreement.warOver);
            SendAllPack(head,"");
            head.Dispose();
        }

        /// <summary>
        /// 发送战斗数据
        /// </summary>
        /// <param name="pl"></param>
        public virtual void SendWarOver(PlayerDataAsyc pl)
        {
            PackHead head = PackHead.Create(GameSeverAgreement.warOver);
            GameNet.SendPack(pl, head,"");
            head.Dispose();
        }

        /// <summary>
        /// 发送桌子信息给谁_朋友房使用
        /// </summary>
        /// <param name="pl"></param>
        /// <param name="packlx">包类型</param>
        /// <param name="otherint">其他参数</param>
        public virtual void SendDeskInfo(PlayerDataAsyc pl, int packlx = GameSeverAgreement.friendroominfo,
            int[] otherint = null)
        {
            PackHead head = PackHead.Create(packlx);

            if (otherint != null)
                head.otherInt = otherint;

            //Debug.Log("朋友房发包:" + pl.userid);
            GameNet.SendPack(pl, head, deskinfo);
            head.Dispose();
        }

        /// <summary>
        /// 发送桌子信息给所有玩家
        /// </summary>
        public virtual void SendDeskInfoAll(int packlx = GameSeverAgreement.friendroominfo, int[] otherint = null)
        {
            int len = PlayerCnt;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] != null)
                    SendDeskInfo(pls[i], packlx, otherint);
            }
        }

        /// <summary>
        /// 朋友房结束
        /// </summary>
        /// <param name="style">0某局结束 1所有局数打完 2开战过 提前解散 3朋友房超时解散(24小时内未打完) 4朋友房超时解散(1小时内还没满员) 5房主解散  6玩法被删除  7管理或者会长主动解散</param>
        public virtual void SendFriendRoomOver(int style)
        {
            int packlx = 0;
            switch (style)
            {
                case 0:
                    packlx = GameSeverAgreement.over_paiju;
                    break;
                case 1:
                    packlx = GameSeverAgreement.over_All;
                    break;
                case 2:
                    packlx = GameSeverAgreement.over_jiesan;
                    break;
                case 3:
                    packlx = GameSeverAgreement.over_timeout;
                    break;
                case 4:
                    packlx = GameSeverAgreement.over_timeout_nowar;
                    break;
                case 5:
                    packlx = GameSeverAgreement.over_fangzhu;
                    break;
                case 6:
                    packlx = GameSeverAgreement.wayDel;
                    break;
                case 7:
                    packlx = GameSeverAgreement.ClubDisBankCmd;
                    break;
                case 8:
                    packlx = GameSeverAgreement.ClubMatchDisBankDeskByBurs;
                    break;
                case 9:
                    packlx = GameSeverAgreement.DepositAutoDissolve;
                    break;
                default:
                    packlx = GameSeverAgreement.over_jiesan;
                    break;
            }

            int len = PlayerCnt;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] != null)
                    SendDeskInfo(pls[i], packlx);
            }
        }

        /// <summary>
        /// 发送朋友房中的玩家信息给所有玩家
        /// </summary>
        /// <param name="cmd">指令类型</param>
        /// <param name="userid">谁加入或者谁离开</param>
        /// <param name="nickname">昵称-提示用</param>
        public virtual void SendPlayersinfo(int cmd, int userid, string nickname)
        {
            FriendPlayersInfo fpi = new FriendPlayersInfo
            {
                style = cmd,
                userid = userid,
                nickname = nickname,
                players = deskinfo.pls,
                seat = deskinfo.seat,
                plsDis = deskinfo.plsDis,
                onceFight = deskinfo.OnceFight
            };

            PackHead head = PackHead.Create(GameSeverAgreement.friendroomplayers);
            SendAllPack(head, fpi, userid);
            head.Dispose();
        }

        /// <summary>
        /// 发送解散信息给所有玩家
        /// </summary>
        /// <param name="cmd">指令</param>
        /// <param name="userid">谁发起的指令</param>
        /// <param name="nickname">玩家昵称</param>
        public virtual void SendDisInfo(int cmd, int userid, string nickname)
        {
            DisInfo di = new DisInfo()
            {
                style = cmd,
                userid = userid,
                count = deskinfo.DisCount,
                nickname = nickname,
                requestCnt = deskinfo.RequestDissolveCnt,
                isDising = deskinfo.isDising
            };
            PackHead head = PackHead.Create(GameSeverAgreement.disbankinfo);
            SendAllPack(head, di);
            head.Dispose();
        }

        /// <summary>
        /// 发送立即战斗数据包
        /// </summary>
        public virtual void SendOnceFight()
        {
            if (deskinfo == null)
                return;
            PackHead head = PackHead.Create(GameSeverAgreement.questOnceFight);
            head.otherInt = deskinfo.OnceFight;
            SendAllPack(head, null);
            head.Dispose();
        }

        /// <summary>
        /// 发送玩家状态变化包
        /// </summary>
        /// <param name="seat">座位</param>
        public virtual void SendPlayerStateChange(int seat)
        {
            if (seat < 0 || seat >= pls.Length)
            {
                Debug.Error("桌子数据错误{0},{1}", seat, PlayerCnt);
                return;
            }

            pls[seat].UpdatePlayerState();
            PlayerStateChangePack pscp = new PlayerStateChangePack(seat, (int)pls[seat].state);
            PackHead head = PackHead.Create(GameSeverAgreement.playerStateChange);
            SendAllPack(head, pscp);
            head.Dispose();
        }

        public virtual void SendPlayerDePositChange(int seat)
        {
            if (seat < 0 || seat >= pls.Length)
            {
                Debug.Error("桌子数据错误{0},{1}", seat, PlayerCnt);
                return;
            }

            PlayerDePositChange pack = new PlayerDePositChange(seat, pls[seat].isDePosit);
            PackHead head = PackHead.Create(GameSeverAgreement.PlayerDepositChange);
            SendAllPack(head, pack);
            head.Dispose();
        }

        /// <summary>
        /// 发送离线变化状态
        /// </summary>
        /// <param name="seat"></param>
        public virtual void SendPlayerOutLineChange(int seat)
        {
            if (seat < 0 || seat >= pls.Length)
            {
                return;
            }

            OutLineChangePack plcp = new OutLineChangePack(seat, pls[seat].outline);
            PackHead head = PackHead.Create(GameSeverAgreement.OutLineChange);
            SendAllPack(head, plcp);
            head.Dispose();
        }

        #endregion

        /// <summary>
        /// 消息数据
        /// </summary>
        /// <param name="data"></param>
        public void DoMessageData(MessageData data)
        {
            PackHead head = PackHead.Create(GamePackAgreement.DoMessgae);
            SendAllPack(head, data); //发给全桌的人
            head.Dispose();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string StateToString()
        {
            string result = string.Empty;
            if ((DeskState.Idle & this.state) > 0)
            {
                result += "闲置/";
            }

            if ((DeskState.Queue & this.state) > 0)
            {
                result += "排队中/";
            }

            if ((DeskState.War & this.state) > 0)
            {
                result += "开战中/";
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("是否朋友房:");
            sb.Append(this.deskinfo != null);
            sb.Append(Environment.NewLine);
            sb.Append("桌子id:");
            sb.Append(this.id);
            sb.Append(Environment.NewLine);
            sb.Append("上次等待开战的玩家数量：");
            sb.Append(this.lastWiatPlayerCnt);
            sb.Append(Environment.NewLine);
            sb.Append("玩家数量:");
            sb.Append(this.PlayerCnt);
            sb.Append(Environment.NewLine);
            sb.Append("是否是全部真人:");
            sb.Append(this.AllRealPerson);
            sb.Append(Environment.NewLine);
            sb.Append("真人数量:");
            sb.Append(this.RealPerson);
            sb.Append(Environment.NewLine);
            sb.Append("房间状态:");
            sb.Append(StateToString());
            sb.Append(Environment.NewLine);
            sb.Append("税收:");
            sb.Append(taxmoney);
            sb.Append(Environment.NewLine);
            sb.Append("所属厅:");
            sb.Append(tingid);
            sb.Append(Environment.NewLine);
            sb.Append("赢的游戏币:");
            sb.Append(winmoney);
            sb.Append(Environment.NewLine);
            sb.Append("开战时间:");
            sb.Append(warTime.TimeToString());
            sb.Append(Environment.NewLine);

            PlayerDataAsyc tmppl;

            for (int i = 0; i < Count; i++)
            {
                tmppl = pls[i];
                if (tmppl == null) continue;
                sb.Append("玩家:");
                sb.Append(i);
                sb.Append(Environment.NewLine);
                sb.Append("userid:");
                sb.Append(tmppl.userid);
                sb.Append(Environment.NewLine);
                sb.Append("nickName:");
                sb.Append(tmppl.nickname);
                sb.Append(Environment.NewLine);
                sb.Append("isRobot:");
                sb.Append(tmppl.isRobot);
                sb.Append(Environment.NewLine);
            }

            return sb.ToString();
        }

        /// <summary>
        /// 加减钱
        /// </summary>
        /// <param name="seat">座位</param>
        /// <param name="lx">类型</param>
        /// <param name="num">类型</param>
        public abstract void IncMoney(int seat, int lx, int num);

        /// <summary>
        /// 玩家变化
        /// </summary>
        /// <param name="seat"></param>
        /// <param name="pl"></param>
        public void ChangePlayer(int seat, PlayerDataAsyc pl)
        {
            pls[seat] = pl;
            pl.seat = seat;
        }

        /// <summary>
        /// 发送设备信息
        /// </summary>
        public void SendDeviceInfo()
        {
            int len = pls.Length;
            //设备信息
            DeviceInfo[] deviceInfos = new DeviceInfo[len];
            for (int i = 0; i < len; i++)
            {
                if (pls[i] != null)
                {
                    deviceInfos[i] = pls[i].device;
                }
            }

            PackHead head = PackHead.Create();

            for (int i = 0; i < len; i++)
            {
                if (pls[i] == null)
                    continue;
                head.packlx = GameSeverAgreement.DeviceInfoChange;
                GameNet.SendPack(pls[i], head, deviceInfos, false);
            }

            Debug.Info("有玩家的定位信息发生变化,更新玩家的设备信息!");

            head.Dispose();
        }

        /// <summary>
        /// 解散房间
        /// </summary>
        /// <param name="dskInfo">桌子信息</param>
        /// <param name="style">解散类型</param>
        public static void DisBank(DeskInfo dskInfo, int style = -1)
        {
            dskInfo.closeTime = DateTime.Now;

            if (!dskInfo.noWar)
            {
                Debug.Info("竞技比赛房间解散:" + dskInfo.creatUserid);
                SendFightRecordToClub(dskInfo, style);
            }
            if (dskInfo.creatStyle == 5)
            {
                WayManager.instance.DelDeskInfo(dskInfo.creatUserid, dskInfo.wayid, dskInfo.weiyima);
            }


            Room.DeleteRoom(dskInfo); //操作redis
        }
        
        

        /// <summary>
        /// 加载内存数据
        /// </summary>
        /// <param name="data"></param>
        public abstract void LoadMem(byte[] data, bool isOld);


        /// <summary>
        /// 加载内存成功,朋友房使用
        /// </summary>
        public virtual void LoadMemSuccess()
        {
        }

        /// <summary>
        /// 恢复桌子数据
        /// </summary>
        /// <param name="weiyima"></param>
        /// <param name="wayId"></param>
        /// <param name="isSave"></param>
        public static void SendFightScore(string weiyima, string wayId, bool isSave = false)
        {

            var dt = GameDB.Instance.selectDb(dbbase.game2018,"RoomData",null,$"weiyima={weiyima}");
            var pls = GameDB.Instance.selectDb(dbbase.game2018, "Room_Player", null, $"roomweiyima={weiyima}");
            
            
            FightScore fs = new FightScore();
            fs.weiyima = dt.Rows[0]["weiyima"].ToString();
            fs.wayid = wayId;
            fs.clubid = int.Parse(dt.Rows[0]["createid"].ToString());
            fs.roomnum = int.Parse(dt.Rows[0]["roomnum"].ToString());
            fs.CardNum = int.Parse(dt.Rows[0]["fangka"].ToString());// dskinfo.overCnt <= 0 ? 0 : dskinfo.fangka; //打完才计算房卡
            fs.warCnt = int.Parse(dt.Rows[0]["warcnt"].ToString());// dskinfo.rule.warCnt;
            fs.overCnt = int.Parse(dt.Rows[0]["overCnt"].ToString());// dskinfo.overCnt; //完整的打了多少盘
            fs.game_serid = int.Parse(dt.Rows[0]["gameid"].ToString());
            fs.Style = int.Parse(dt.Rows[0]["createStyle"].ToString());// style;
            int capping = int.Parse(dt.Rows[0]["Capping"].ToString());
            Debug.Info("game_serid:" + fs.game_serid);

            fs.startTime = DateTime.Parse(dt.Rows[0]["createTime"].ToString());// dskinfo.CreateTime;
            fs.endTime = DateTime.Parse(dt.Rows[0]["closeTime"].ToString()); // dskinfo.closeTime;

            int len = int.Parse(dt.Rows[0]["mincnt"].ToString());
            int _len = int.Parse(dt.Rows[0]["maxcnt"].ToString());
            if (len != _len)
            {
                Debug.Error("人数不对!");
                return;
            }

            decimal beishu = decimal.Parse(dt.Rows[0]["peilv"].ToString());
            
            Debug.Info($"beishu:{beishu}");
            fs.scores = new FightScore.Player[len];
            //decimal beishu = (decimal)dskinfo.rule.peilv;

            
            
            int cnt = 0;
            for (int i = 0; i < len; i++)
            {
                var row = pls.Rows[i];
                int id = int.Parse(row["playerid"].ToString());
                if (id != i)
                {
                    Debug.Error("位置不对!");
                    return;
                }
               // if (dskinfo.pls[i] != null)
                {
                    fs.scores[i] = new FightScore.Player();
                    fs.scores[i].userid = int.Parse(row["userid"].ToString());// dskinfo.pls[i].userid;
                    fs.scores[i].name = row["nickname"].ToString();// dskinfo.pls[i].nickName;
                    fs.scores[i].clubId = int.Parse(row["clubid"].ToString());// dskinfo.pls[i].ClubId;
                    fs.scores[i].photo = "0";
                    //把头像换成性别给客户端使用。
                    //if (dskinfo.SumBurs != null && dskinfo.SumBurs.Count > 0)
                    {
                        fs.scores[i].score = decimal.Parse(row["allScore"].ToString());
                    }

                    cnt++;
                }
            }

            decimal[] score = new decimal[len];
            for (int i = 0; i < len; i++)
            {
                score[i] = fs.scores[i].score * beishu;
                Debug.Info($"玩家的分:{score[i]}");
            }
            
            
            score = Room.CalcCapping(score, capping);
            for (int i = 0; i < len; i++)
            {
                fs.scores[i].score = score[i];
            }

            if (cnt != len)
            {
                FightScore.Player[] lst = new FightScore.Player[cnt];
                cnt = 0;
                for (int i = 0; i < len; i++)
                {
                    if (fs.scores[i] != null)
                    {
                        lst[cnt++] = fs.scores[i];
                    }
                }

                fs.scores = lst;
            }
            
            string jsondata = JsonConvert.SerializeObject(fs);
            Debug.Info($"json:{jsondata}");

            if (isSave)
            {
                PackHead head = PackHead.Create(ServerPackAgreement.ClubFightRecord);
                GlobalMQ.instance.DeliveryEveryOne((int)ModuleType.ClubModule, GlobalMQ.CreateMessage(head, fs), true,
                    true);
            }
        }
        
        /// <summary>
        /// 发送战绩给竞技比赛
        /// </summary>
        public static void SendFightRecordToClub(DeskInfo dskinfo, int style = -1)
        {
            int len = dskinfo.pls.Length;
            FightScore fs = new FightScore();

            fs.weiyima = dskinfo.weiyima;
            fs.wayid = dskinfo.wayid;
            fs.clubid = dskinfo.creatUserid;
            fs.roomnum = int.Parse(dskinfo.roomNum);
            fs.CardNum = dskinfo.overCnt <= 0 ? 0 : dskinfo.fangka; //打完才计算房卡
            fs.warCnt = dskinfo.rule.warCnt;
            fs.overCnt = dskinfo.overCnt; //完整的打了多少盘
            fs.game_serid = ServerConfigManager.Instance.GameId;
            fs.Style = style;
            fs.DisUserId = dskinfo.DisUserId;
            Debug.Info("game_serid:" + fs.game_serid);

            fs.startTime = dskinfo.CreateTime;
            fs.endTime = dskinfo.closeTime;
           
            fs.scores = new FightScore.Player[len];
            decimal beishu = (decimal)dskinfo.rule.peilv;

            int cnt = 0;
            for (int i = 0; i < len; i++)
            {
                if (dskinfo.pls[i] != null)
                {
                    fs.scores[i] = new FightScore.Player();
                    fs.scores[i].userid = dskinfo.pls[i].userid;
                    fs.scores[i].name = dskinfo.pls[i].nickName;
                    fs.scores[i].clubId = dskinfo.pls[i].ClubId;
                    fs.scores[i].photo = !string.IsNullOrWhiteSpace(dskinfo.pls[i].photo)
                        ? dskinfo.pls[i].photo
                        : dskinfo.pls[i].sex.ToString();
                    //把头像换成性别给客户端使用。
                    if (dskinfo.SumBurs != null && dskinfo.SumBurs.Count > 0)
                    {
                        fs.scores[i].score = dskinfo.SumBurs[i].Score;
                    }

                    cnt++;
                }
            }

            if (dskinfo.SumBurs == null || dskinfo.SumBurs.Count <= 0)
            {
                foreach (var bur in dskinfo.burs)
                {
                    for (int i = 0; i < len; i++)
                    {
                        if (fs.scores[i] == null)
                            continue;
                        fs.scores[i].score += bur.playScore[i] * beishu;
                    }
                }
            }

            if (cnt != len)
            {
                FightScore.Player[] lst = new FightScore.Player[cnt];
                cnt = 0;
                for (int i = 0; i < len; i++)
                {
                    if (fs.scores[i] != null)
                    {
                        lst[cnt++] = fs.scores[i];
                    }
                }

                fs.scores = lst;
            }

            if (dskinfo.creatStyle == 5)
            {
                PackHead head = PackHead.Create(ServerPackAgreement.ClubFightRecord);
                GlobalMQ.instance.DeliveryEveryOne((int)ModuleType.ClubModule, GlobalMQ.CreateMessage(head, fs), true,
                    true);
                TestManager.Instance.AddGameFightData(fs);
                head.Dispose();
            }

            try
            {
//上传日志
                int cnt1 = dskinfo.nowCnt != 0 ? dskinfo.nowCnt : dskinfo.overCnt;
                FriendRoomFightFileInfo info = new FriendRoomFightFileInfo { weiyima = dskinfo.weiyima, overCnt = cnt1, endTime = dskinfo.closeTime };
                //保存回放数据
                FightRecordManager.Instance.SaveRoomInfo(dskinfo.weiyima, info);

                if (dskinfo.creatStyle != 5)
                {
                    string content = JsonPack.GetJson(fs);
                    List<WarFriendItemData> datas = new List<WarFriendItemData>();
                    for (int i = 0; i < dskinfo.pls.Length; i++)
                    {
                        if (dskinfo.pls[i] != null)
                        {
                            datas.Add(new WarFriendItemData()
                            {
                                UserId = dskinfo.pls[i].userid,
                                GameId = ServerConfigManager.Instance.ClientId,
                                WeiYiMa = dskinfo.weiyima,
                                Content = content
                            });
                        }
                    }
            
                    WarRecordSLSManager.Instance.ReportFriendAsync(datas);
                }
            }
            catch (Exception e)
            {
                Debug.Error($"保存朋友房日志:{e.Message}");
            }
        }

        /// <summary>
        /// 检查玩家是否有资格解散
        /// </summary>
        /// <param name="pl"></param>
        public bool CheckDisbank(PlayerDataAsyc pl)
        {
            if (!isFriend)
            {
                Debug.Error("不是朋友房，怎么解散桌子!");
                return false;
            }

            if (deskinfo.creatStyle == 0 || deskinfo.creatStyle == 1)
            {
                //普通房间或者代开房间
                if (deskinfo.creatUserid == pl.userid)
                {
                    //是本人创建的
                    if (deskinfo.noWar)
                    {
                        //没开战过
                        return true;
                    }
                }
            }

            return false;
        }

        public virtual void DisBank(int style = -1)
        {
            //朋友房完成解散
            //bool isOverBank = deskinfo.overCnt == deskinfo.rule.warCnt;
            gameLogic.DisBank(style);
        }

        /// <summary>
        /// 解散房间
        /// </summary>
        /// <param name="style">解散类型</param>
        public void DisBankAfter(int style = -1)
        {
            Debug.Info("解散房间,修改redis数据!");
            DisBank(deskinfo, style);

            if (deskinfo.nowCnt > 0)
            {
                //战斗中,保存战斗记录
                Room.SaveFightRecord(deskinfo, fightdata, style);
            }

            Debug.Info("修改玩家数据!");

            PlayerDataAsyc pl;
            for (int i = 0; i < Count; i++)
            {
                pl = pls[i];
                if (pl == null)
                    continue;

                PlayerChange(pl, true);
                if (!GameManager.instance.isExistsRoom(pl.roomid))
                {
                    Debug.Warning("玩家的房间数据错误：" + pl.roomid + "," + pl.userid + "," + pl.nickname);
                }
                else
                {
                    var room = GameManager.instance.FindRoom(pl.roomid);
                    room.SetRoomPlayerCnt(pl, true);
                }

                pl.seat = -1; //退出游戏
                pl.deskid = -1;
                pl.roomid = -1;
                pl.tingid = -1;
                pl.friendRoomNum = -1;
                pl.friendWeiYiMa = null;
                pl.state = (int)PlayerState.INGame;
                //发送玩家信息
                GameManager.instance.QuitGame(pl, "DisBank", deskinfo.noWar);
            }
        }

        /// <summary>
        /// 回收房间
        /// </summary>
        public virtual List<PlayerDataAsyc> RecoverRoom()
        {
            if ((state & DeskState.War) > 0)
            {
                Debug.Warning("开战中的房间无法回收snajknkj");
                return null;
            }

            List<PlayerDataAsyc> result = new List<PlayerDataAsyc>();
            int len = Count;
            for (int i = 0; i < len; i++)
            {
                if (pls[i] != null)
                {
                    result.Add(pls[i]);
                    PlayerChange(pls[i], true);
                    pls[i] = null;
                }
            }

            return result;
        }

        /// <summary>
        /// 百家乐机器人上桌
        /// </summary>
        public virtual bool RobotJoin()
        {
            if (MaxRobot <= 0) //不要机器人
                return false;

            decimal dec = 0;
            //人数没变化,和上次上桌概率一样
            if (lastAllPlayerCount == PlayerCnt && lastPlayerCount == RealPerson)
            {
                dec = robotProability;
            }
            else
            {
                //重新计算

                lastAllPlayerCount = PlayerCnt;
                lastPlayerCount = RealPerson;

                if (lastAllPlayerCount > towThirds)
                {
                    dec = 0;
                }
                else
                {
                    dec = MaxRobot - (lastAllPlayerCount - lastPlayerCount);

                    dec = dec / MaxRobot;
                    dec = dec * dec;

                    if (lastAllPlayerCount > halfPlayer)
                        dec = dec * (1 - ((decimal)lastAllPlayerCount / Count));
                }
            }

            if (dec < 0)
                dec = 0;

            //计算概率上桌
            return dec != 0 && BaseFun.Probability((double)dec);
        }

        public virtual void Close()
        {
            if (state == DeskState.War && deskinfo != null && fightdata != null && fightdata.fightPack.Count > 0)
            {
                try
                {
                    Debug.Info("保存战绩!!!");
                    if (!Directory.Exists("fightRecord"))
                    {
                        Directory.CreateDirectory("fightRecord");
                    }

                    string jsonData = JsonConvert.SerializeObject(fightdata);
                    //desk.deskinfo.weiyima, desk.deskinfo.burs.Count, onedata
                    string fileName =
                        $"{RedisDictionary.friendRoomfightRecord}{deskinfo.burs.Count}:{deskinfo.weiyima}";
                    fileName = fileName.Replace(":", "");
                    File.WriteAllText($"fightRecord/{fileName}", jsonData);
                }
                catch (Exception e)
                {
                    Debug.Error($"保存回放数据报错:{e.Message}");
                }
            }
        }
    }
}