Files
hjha-server/GlobalSever/Data/PlayerFun.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

443 lines
14 KiB
C#

/********************************
*
* 作者:吴隆健
* 创建时间: 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
{
/// <summary>
/// 玩家锁定信息
/// </summary>
public class PlayerLockInfo
{
/// <summary>
/// 被锁的模块信息
/// </summary>
public ModuleUtile util;
/// <summary>
/// 玩家的serid
/// </summary>
public int gameid;
/// <summary>
/// 玩家的客户端id
/// </summary>
public int clientid;
/// <summary>
/// 被锁的在的游戏名称
/// </summary>
public string name;
/// <summary>
/// 是否是朋友房
/// </summary>
public bool isFriend;
}
/// <summary>
/// 玩家操作
/// </summary>
public class PlayerFun
{
/*
* 玩家数据 在登录游戏/仓库是 加锁 在退出游戏/仓库 时解锁
* 中途可能出现宕, 在玩家登录其他游戏时,检查锁定信息,若锁定的游戏确认宕机则解锁玩家
*
* */
/// <summary>
/// 被锁的玩家列表
/// </summary>
private const string LockKey = "Game:LockPlayer:";
/// <summary>
/// 获取玩家锁定的key
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public static string GetKey(int userid)
{
return LockKey + userid;
}
/// <summary>
/// 锁定玩家
/// </summary>
/// <param name="userid"></param>
/// <param name="util"></param>
/// <param name="gameid"></param>
/// <param name="clientid"></param>
/// <param name="name"></param>
/// <param name="isFriend"></param>
/// <returns></returns>
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);
}
/// <summary>
/// 修改锁信息
/// </summary>
/// <param name="userid"></param>
/// <param name="lockInfo"></param>
/// <returns></returns>
public static bool EditorLockPlayer(int userid, PlayerLockInfo lockInfo)
{
string key = GetKey(userid);
return redisManager.db.StringSet(key, JsonPack.GetJson(lockInfo), null, When.Exists);
}
/// <summary>
/// 获取玩家锁定信息
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public static Task<PlayerLockInfo> GetPlayerLockInfoAsync(int userid)
{
return Task.Run(() => GetPlayerLockInfo(userid));
}
/// <summary>
/// 获取玩家锁定信息
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public static PlayerLockInfo GetPlayerLockInfo(int userid)
{
string key = GetKey(userid);
string value = redisManager.db.StringGet(key);
return GetPlayerLockInfo(value);
}
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static PlayerLockInfo GetPlayerLockInfo(string value)
{
if (string.IsNullOrEmpty(value))
return null;
return JsonPack.GetData<PlayerLockInfo>(value);
}
/// <summary>
/// 解锁玩家 当玩家是朋友房加锁的 只能有本模块去解锁,不然要使用 force
/// </summary>
/// <param name="userid">解锁的玩家userid</param>
/// <param name="myUtil"></param>
/// <param name="force"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 异步获取玩家数据
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public static Task<playerData> GetPlayerDataAsync(int userid)
{
return Task<playerData>.Factory.StartNew(
() => GetPlayerData(userid)
);
}
/// <summary>
/// 写玩家数据
/// </summary>
/// <param name="pdc"></param>
//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();
}
/// <summary>
/// 保存玩家数据
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
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();
}
/// <summary>
/// 把变化的数据添加到玩家数据上
/// </summary>
/// <param name="pl"></param>
/// <param name="pdc"></param>
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;
}
/// <summary>
/// 获取玩家数据
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
///
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public static Tuple<bool, playerData> 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<bool, playerData>(true, pl);
}
/// <summary>
/// 保存玩家数据
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 写入玩家数据
/// </summary>
/// <param name="pdc"></param>
/// <returns></returns>
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);
}
/// <summary>
///
/// </summary>
/// <param name="pdc"></param>
public static Task WritePlayerDataAsync(PlayerDataChange pdc)
{
if (pdc.userid > 0)
return Task.Run(() => WritePlayerData(pdc));
else
{
ReferencePool.Recycle(pdc);
return Task.CompletedTask;
}
}
}
}