/********************************
*
* 作者:吴隆健
* 创建时间: 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;
}
}
}
}