/******************************** * * 作者:吴隆健 * 创建时间: 2019/7/5 11:23:27 * ********************************/ using System; using System.Threading; using System.Threading.Tasks; using GameData; using Server.Core; using Server.Data.Module; using Server.DB.Redis; using Server.MQ; using Server.Pack; using StackExchange.Redis; using Debug = MrWu.Debug.Debug; namespace Server.Data { /// /// 玩家锁定信息 /// public class PlayerLockInfo { /// /// 被锁的模块信息 /// public ModuleUtile util; /// /// 玩家的serid /// public int gameid; /// /// 玩家的客户端id /// public int clientid; /// /// 被锁的在的游戏名称 /// public string name; /// /// 是否是朋友房 /// public bool isFriend; } /// /// 玩家操作 /// public class PlayerFun { /* * 玩家数据 在登录游戏/仓库是 加锁 在退出游戏/仓库 时解锁 * 中途可能出现宕, 在玩家登录其他游戏时,检查锁定信息,若锁定的游戏确认宕机则解锁玩家 * * */ /// /// 被锁的玩家列表 /// private const string LockKey = "Game:LockPlayer:"; /// /// 获取玩家锁定的key /// /// /// public static string GetKey(int userid) { return LockKey + userid; } /// /// 锁定玩家 /// /// /// /// /// /// /// /// public static bool LockPlayer(int userid, ModuleUtile util, int gameid, int clientid, string name, bool isFriend) { string key = GetKey(userid); PlayerLockInfo lockInfo = new PlayerLockInfo() { util = util, gameid = gameid, clientid = clientid, name = name, isFriend = isFriend }; return redisManager.db.StringSet(key, JsonPack.GetJson(lockInfo), null, When.NotExists); } /// /// 修改锁信息 /// /// /// /// public static bool EditorLockPlayer(int userid, PlayerLockInfo lockInfo) { string key = GetKey(userid); return redisManager.db.StringSet(key, JsonPack.GetJson(lockInfo), null, When.Exists); } /// /// 获取玩家锁定信息 /// /// /// public static Task GetPlayerLockInfoAsync(int userid) { return Task.Run(() => GetPlayerLockInfo(userid)); } /// /// 获取玩家锁定信息 /// /// /// public static PlayerLockInfo GetPlayerLockInfo(int userid) { string key = GetKey(userid); string value = redisManager.db.StringGet(key); return GetPlayerLockInfo(value); } /// /// /// /// /// private static PlayerLockInfo GetPlayerLockInfo(string value) { if (string.IsNullOrEmpty(value)) return null; return JsonPack.GetData(value); } /// /// 解锁玩家 当玩家是朋友房加锁的 只能有本模块去解锁,不然要使用 force /// /// 解锁的玩家userid /// /// /// public static bool UnLockPlayer(int userid, ModuleUtile myUtil, bool force = false) { #if DEBUG Debug.Info($"UnLockPlayer {userid}"); #endif string key = GetKey(userid); string value = redisManager.db.StringGet(key); var lockInfo = GetPlayerLockInfo(value); if (lockInfo == null) return true; //没被锁 var db = redisManager.GetDataBase(); bool r = !lockInfo.isFriend || force; if (!r) { //只能本模块可以解锁 r = myUtil.Equals(lockInfo.util); } if (r) { //解锁玩家 var tran = db.CreateTransaction(); tran.AddCondition(Condition.StringEqual(key, value)); tran.KeyDeleteAsync(key); r = tran.Execute(); } return r; } /// /// 异步获取玩家数据 /// /// /// public static Task GetPlayerDataAsync(int userid) { return Task.Factory.StartNew( () => GetPlayerData(userid) ); } /// /// 写玩家数据 /// /// //public static async Task WritePlayerData(Game.Data.PlayerDataChange pdc) { public static void WritePlayerDataOnDataCenter(GameData.PlayerDataChange pdc) { PackHead head = PackHead.Create(); head.userid = pdc.userid; head.packlx = ServerPackAgreement.WritePlayerData; GlobalMQ.instance.DeliveryEveryOne((int)ModuleType.DataCenter, GlobalMQ.CreateMessage(head, pdc), true, true); head.Dispose(); } /// /// 保存玩家数据 /// /// /// public static void SavePlayerDataOnDataCenter(int userid) { Thread thread = new Thread( () => { //保存玩家数据 PackHead head = PackHead.Create(); head.userid = userid; head.packlx = ServerPackAgreement.SavePlayerData; GlobalMQ.instance.Call_EveryOne((int)ModuleType.DataCenter, head, null); head.Dispose(); } ); thread.Start(); } /// /// 把变化的数据添加到玩家数据上 /// /// /// public static void PlayerAddChangeData(playerData pl, GameData.PlayerDataChange pdc) { pl.money += pdc.moneyChange; pl.coupon += pdc.couponChange; pl.exp += pdc.expChange; pl.fangka += pdc.fangkaChange; pl.gold += pdc.goldChange; pl.MatchRoll += pdc.MatchRollChange; } /// /// 获取玩家数据 /// /// public static playerData GetPlayerData(int userid) { //第一次读取 var result = ReadPlayerData(userid); if (!result.Item1) { //不成功,尝试第二次读取 result = ReadPlayerData(userid); if (result.Item1) { //成功 result.Item2.isUpper = 1; } else { //还是不成功,发到 DataCenter 请求读取 Debug.Warning($"PlayerFun GetPlayerData {userid} 第二次读取还未成功!"); //return GetPlayerDataOnDataCenter(userid); return result.Item2; } } return result.Item2; } /// /// /// /// /// public static Tuple ReadPlayerData(int userid) { playerData pl = new playerData(); try { //这是RPC方式 //3种情况 //1.redis 有 且与 sql版本一致 直接返回 redis中的数据 //2.redis 有 而与 sql版本不一致 sql数据+redis增量返回 -> 异步更新 redis 原始数据+版本 //3.redis 无 直接取 sql数据 -> 异步更新 redis原始数据 + 版本 pl.userid = userid; //拿到redis 数据 ,没拿到 ver 就是-1 拿到则有信息 GameData.PlayerDataChange pdc; int ver = PlayerDataManager.LoadRedisPlayerData(pl, out pdc); //如果 ver 与数据库版本不一致 则会从新加载 并更新redis if (!PlayerDataManager.LoadSqlPlayerData(pl, ver, pdc)) { Debug.Warning("加载玩家失败!" + ver + ",没有这个玩家:" + pl.userid); pl = null; } ReferencePool.Recycle(pdc); } catch (Exception e) { Debug.Error("读取玩家数据时出错!" + userid + "," + e.ToString()); pl = null; } return new Tuple(true, pl); } /// /// 保存玩家数据 /// /// /// public static Thread SavePlayerData(int userid) { Thread thread = new Thread( () => { var succ = PlayerDataManager.SaveToSql(userid); if (!succ) { Debug.Warning($"PlayerFun SavePlayerData {userid} 第二次读取还未成功!"); //发送到 DataCenter 请求保存操作 SavePlayerDataOnDataCenter(userid); } } ); thread.Start(); return thread; } /// /// 写入玩家数据 /// /// /// public static bool WritePlayerDataInternal(GameData.PlayerDataChange pdc) { bool isOk = true; Debug.ImportantLog("写库:" + pdc.ToString()); //写入成功了 if (PlayerDataManager.WriteToRedis(pdc)) { //LastWriteList.Add(pdc.userid); Debug.ImportantLog("写库完成!"); } else { //写入失败,先冲sql中加载数据 //再写 playerData pl = new playerData() { userid = pdc.userid }; if (!PlayerDataManager.LoadSqlPlayerData(pl, -1, null)) { Debug.Error("没有这个玩家,无法写库:" + pl.userid); return isOk; } else { if (!PlayerDataManager.WriteToRedis(pdc)) { Debug.Fatal($"还是写库失败!!! 把包退回去! {pdc.ToString()}"); isOk = false; //if (msg != null) // msg.NAck(false, true); } else { //LastWriteList.Add(pdc.userid); } } } return isOk; } private static void WritePlayerData(PlayerDataChange pdc) { if (pdc.userid < 0) return; bool isOk = false; try { isOk = WritePlayerDataInternal(pdc); } catch (Exception ex) { Debug.Error("WritePlayerData: " + ex); } if (!isOk) { Debug.Warning($"PlayerFun WritePlayerData {pdc.userid} 未成功!"); try { //发送到 DataCenter 请求写入操作 WritePlayerDataOnDataCenter(pdc); } catch (Exception ex) { Debug.Error("WritePlayerDataOnDataCenter: " + ex); } } ReferencePool.Recycle(pdc); } /// /// /// /// public static Task WritePlayerDataAsync(PlayerDataChange pdc) { if (pdc.userid > 0) return Task.Run(() => WritePlayerData(pdc)); else { ReferencePool.Recycle(pdc); return Task.CompletedTask; } } } }