/********************************
*
* 作者:吴隆健
* 创建时间: 2019/7/3 13:06:48
*
********************************/
using GameData;
using GameDAL.Game;
using MrWu.Debug;
using Server.DB.Redis;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Data;
using MrWu.Time;
using System.Threading;
using Server.Data;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Server.Core;
using Server.DB.Sql;
/////
///// 玩家数据管理
/////
namespace Server
{
///
///
///
public class PlayerDataManager
{
///
///
///
public static PlayerDataManager instance { get; private set; }
private PlayerDataManager()
{
}
static PlayerDataManager()
{
instance = new PlayerDataManager();
}
#region player redis 字段
///
/// 玩家的userid 字段
///
public const string useridField = "userid";
///
/// 用户名
///
public const string UserNameField = "UserName";
///
/// 玩家昵称
///
public const string nickNameField = "NickName";
///
/// 数据版本
///
public const string verField = "ver";
///
/// 玩家金额字段
///
public const string moneyField = "money";
///
/// 游戏币变化字段
///
public const string moneyChangeField = "moneyChange";
///
/// 金币字段名
///
public const string goldFiled = "Glod";
///
/// 金币变化字段名
///
public const string goldChangeField = "GlodChange";
///
/// 性别字段名
///
public const string sexField = "Sex";
///
/// 地区字段
///
public const string areaField = "Area";
///
/// 经验字段
///
public const string expField = "hjha_Exp";
///
/// 经验变化字段
///
public const string expChangeField = "expChange";
///
/// 玩家的奖券字段
///
public const string couponField = "coupon";
///
/// 奖券变化字段名
///
public const string couponChangeField = "couponChange";
///
/// 房卡字段名
///
public const string fangkaField = "fangka";
///
/// 房卡变化字段名
///
public const string FangKaChangeField = "fangkaChange";
///
/// 用户类型
///
public const string UserTypeField = "UserType";
///
/// 代理字段
///
public const string DailiField = "daili";
///
/// 防沉迷字段
///
public const string PiField = "pi";
///
/// 比赛卷字段
///
public const string MatchRollField = "mmnn";
///
/// 比赛卷变化字段
///
public const string MatchRollChangeField = "mmnnChange";
///
/// 推广的标识
///
public const string platTagField = "platTag";
///
/// 用户头像对应的字段
///
public const string HeadField = "hjha_LeagueId";
///
/// 平台类型
///
public const string PlatEnumField = "hjha_fy_Value";
///
/// 在redis中的玩家列表
///
public const string PlayerListKey = "Game:PlayerLRU:Players";
#endregion
///
/// 获取玩家的数据的key
///
///
///
public static string GetKey(int userid)
{
return RedisPlayerDataKeyPrefix + userid;
}
///
/// redis中玩家数据的key
///
public const string RedisPlayerDataKeyPrefix = "Game:PlayerData:";
///
/// 头像
///
public const string AvatarFidle = "avatar";
///
/// 从redis中加载玩家数据
///
///
/// 变化量
///
public static int LoadRedisPlayerData(playerData pl, out PlayerDataChange cgdata)
{
var changeData = PlayerDataChange.Create(pl.userid);
cgdata = changeData;
//-1表示为加载到玩家
int result = -1;
string key = GetKey(pl.userid);
//临时变量
long tmplong;
int tmpint;
var fields = redisManager.db.HashGetAll(key);
if (fields == null) //redis 中没有玩家数据
return result;
foreach (var he in fields)
{
switch (he.Name)
{
case nickNameField:
pl.nickname = he.Value;
break;
case UserNameField:
pl.UserName = he.Value;
break;
case moneyField:
if (he.Value.TryParse(out tmplong))
{
pl.money = tmplong;
}
else
{
Debug.Error("错误错误,玩家游戏币数据竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case moneyChangeField:
if (he.Value.TryParse(out tmplong))
{
changeData.moneyChange = tmplong;
}
else
{
Debug.Error("错误错误,玩家的游戏币变化值竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case goldFiled:
if (he.Value.TryParse(out tmpint))
{
pl.gold = tmpint;
}
else
{
Debug.Error("错误错误,玩家的金币数据竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case goldChangeField:
if (he.Value.TryParse(out tmpint))
{
changeData.goldChange = tmpint;
}
else
{
Debug.Error("错误错误,玩家的游戏币数据竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case sexField:
if (he.Value.TryParse(out tmpint))
{
pl.sex = tmpint;
}
else
{
Debug.Error("错误错误,玩家的性别字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case areaField:
pl.area = he.Value;
break;
case expField:
if (he.Value.TryParse(out tmpint))
{
pl.exp = tmpint;
}
else
{
Debug.Error("错误错误,玩家的经验字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case expChangeField:
if (he.Value.TryParse(out tmpint))
{
changeData.expChange = tmpint;
}
else
{
Debug.Error("错误错误,玩家的经验字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case couponField:
if (he.Value.TryParse(out tmpint))
{
pl.coupon = tmpint;
}
else
{
Debug.Error("错误错误,玩家的奖券字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case couponChangeField:
if (he.Value.TryParse(out tmpint))
{
changeData.couponChange = tmpint;
}
else
{
Debug.Error("错误错误,玩家的奖券变化字段竟然不是数值 userid:{0} vlaue:{1}", pl.userid, he.Value);
}
break;
case fangkaField:
if (he.Value.TryParse(out tmpint))
{
pl.fangka = tmpint;
}
else
{
Debug.Error("错误错误,玩家的房卡字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case FangKaChangeField:
if (he.Value.TryParse(out tmpint))
{
changeData.fangkaChange = tmpint;
}
else
{
Debug.Error("错误错误,玩家的房卡变化值字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case UserTypeField:
if (he.Value.TryParse(out tmpint))
{
pl.userType = tmpint;
}
else
{
Debug.Error("asckjagbshdbashbsmbaxas :" + he.Value);
}
break;
case AvatarFidle:
pl.avatar = he.Value;
break;
case DailiField:
tmpint = 0;
if (he.Value.TryParse(out tmpint))
pl.daili = tmpint;
else
Debug.Error("错误错误,玩家代理字段竟然不是数值 userid{0} value{1}", pl.userid, he.Value);
break;
case PlatEnumField:
tmpint = 0;
if (he.Value.TryParse(out tmpint))
pl.PlatEnum = tmpint;
else
Debug.Error("错误错误,玩家代理字段竟然不是数值 userid{0} value{1}", pl.userid, he.Value);
break;
case PiField:
pl.pi = he.Value;
break;
case platTagField:
pl.platTag = he.Value;
break;
case HeadField:
tmpint = 0;
if (he.Value.TryParse(out tmpint))
{
pl.HeadType = tmpint;
}
else
{
Debug.Error("错误错误,玩家的头像字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case MatchRollField:
tmpint = 0;
if (he.Value.TryParse(out tmpint))
{
pl.MatchRoll = tmpint;
}
else
{
Debug.Error("错误错误,玩家的比赛卷字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case MatchRollChangeField:
if (he.Value.TryParse(out tmpint))
{
changeData.MatchRollChange = tmpint;
}
else
{
Debug.Error("错误错误,玩家的比赛卷变化值字段竟然不是数值 userid:{0} value:{1}", pl.userid, he.Value);
}
break;
case "RegTime":
string temp = he.Value;
try
{
pl.RegTime = string.IsNullOrWhiteSpace(temp) ? default(DateTime) : Convert.ToDateTime(temp);
}
catch
{
pl.RegTime = default(DateTime);
}
break;
}
}
PlayerFun.PlayerAddChangeData(pl, changeData);
result = 1;
return result;
}
///
/// 加载玩家数据如果 sql中的ver 与 参数 ver 不一致 更新redis 以及 pl 原始数据 并添加版本ver信息
///
//加载sql 数据 并更新 redis 数据
public static bool LoadSqlPlayerData(playerData pl, int ver, PlayerDataChange pdc)
{
int userid = pl.userid;
string key = GetKey(pl.userid);
DataSet ds = PlayerDB.ReadPlayerData(pl.userid, !string.IsNullOrEmpty(pl.pi));
if (ds.Tables == null || ds.Tables.Count < 1 || ds.Tables[0].Rows.Count <= 0)
{
//版本一致,数据取redis 原来的数据
return false; //redis 中的版本 与数据库中的版本一致 则有玩家, 版本不一致却没数据,表示没有这个用户
}
//读取玩家数据
DataTable gameTable = ds.Tables[0];
//昵称
string db_nickname;
//地区
string db_area;
//头像
string db_avatar; //头像
string db_userName;
//用户类型
int db_UserType;
//经验值
int db_exp;
//性别
int db_sex;
//游戏币
long db_money;
//奖券
int db_coupon = 0;
//房卡
int db_fangka;
//金币
int db_glod;
int db_daili = 0;
db_nickname = gameTable.Rows[0]["nickNameEm"] as string;
if (string.IsNullOrEmpty(db_nickname))
{
db_nickname = gameTable.Rows[0][nickNameField] as string;
}
db_userName = gameTable.Rows[0]["userName"] as string;
if (db_nickname == null)
db_nickname = string.Empty;
db_area = gameTable.Rows[0][areaField] as string;
if (db_area == null)
db_area = string.Empty;
db_sex = (int)gameTable.Rows[0][sexField];
db_money = (long)gameTable.Rows[0][moneyField];
db_exp = (int)gameTable.Rows[0][expField];
db_fangka = (int)gameTable.Rows[0]["xu"];
db_UserType = (int)gameTable.Rows[0][UserTypeField];
db_coupon = (int)gameTable.Rows[0][couponField];
db_avatar = gameTable.Rows[0][AvatarFidle] as string;
db_daili = (int)gameTable.Rows[0][DailiField];
var platEnum = (int)gameTable.Rows[0][PlatEnumField];
string pi = pl.pi;
if (string.IsNullOrEmpty(pl.pi))
{
pi = (gameTable.Rows[0][PiField] as string) ?? string.Empty;
}
string platTag = (gameTable.Rows[0][platTagField] as string) ?? string.Empty;
int matchRoll = (int)gameTable.Rows[0][MatchRollField];
int head = (int)gameTable.Rows[0][HeadField];
DateTime regTime = default(DateTime);
try
{
regTime = (DateTime)gameTable.Rows[0]["RegTime"];
}
catch
{
}
if (db_avatar == null)
db_avatar = string.Empty;
db_glod = (int)gameTable.Rows[0]["hjha_Gold"];
List hes = new List();
hes.Add(new HashEntry(useridField, userid));
hes.Add(new HashEntry(UserNameField,db_userName));
hes.Add(new HashEntry(nickNameField, db_nickname));
hes.Add(new HashEntry(moneyField, db_money));
hes.Add(new HashEntry(sexField, db_sex));
hes.Add(new HashEntry(areaField, db_area));
hes.Add(new HashEntry(expField, db_exp));
hes.Add(new HashEntry(couponField, db_coupon));
hes.Add(new HashEntry(fangkaField, db_fangka));
hes.Add(new HashEntry(UserTypeField, db_UserType.ToString()));
hes.Add(new HashEntry(AvatarFidle, db_avatar));
hes.Add(new HashEntry(goldFiled, db_glod));
hes.Add(new HashEntry(verField, ver));
hes.Add(new HashEntry(DailiField, db_daili));
hes.Add(new HashEntry(PiField, pi));
hes.Add(new HashEntry(platTagField, platTag));
hes.Add(new HashEntry("RegTime", regTime.ToString("yyyy-MM-dd HH:mm:ss")));
hes.Add(new HashEntry(MatchRollField, matchRoll));
hes.Add(new HashEntry(HeadField, head));
hes.Add(new HashEntry(PlatEnumField, platEnum));
//Debug.Info("设置玩家原始数据:" + userid + "," + db_money);
redisManager.db.HashSetAsync(key, hes.ToArray());
pl.nickname = db_nickname;
pl.UserName = db_userName;
pl.money = db_money;
pl.sex = db_sex;
pl.area = db_area;
pl.exp = db_exp;
pl.coupon = db_coupon;
pl.fangka = db_fangka;
pl.userType = db_UserType;
pl.avatar = db_avatar;
pl.gold = db_glod;
pl.daili = db_daili;
pl.pi = pi;
pl.PlatEnum = platEnum;
pl.MatchRoll = matchRoll;
pl.platTag = platTag;
pl.RegTime = regTime;
pl.HeadType = head;
if (pdc != null)
PlayerFun.PlayerAddChangeData(pl, pdc);
return true;
}
///
/// 把玩家的变化数据清楚掉-和写sql一起使用, 原始数据+ 变化数据-
///
///
/// 是否存在改玩家
public static bool ClearRedisDataChange(PlayerDataChange pdc)
{
string key = GetKey(pdc.userid);
var tran = redisManager.GetDataBase().CreateTransaction();
tran.AddCondition(Condition.KeyExists(key));
if (pdc.moneyChange != 0)
{
tran.HashDecrementAsync(key, moneyChangeField, pdc.moneyChange);
tran.HashIncrementAsync(key, moneyField, pdc.moneyChange);
}
if (pdc.expChange != 0)
{
tran.HashDecrementAsync(key, expChangeField, pdc.expChange);
tran.HashIncrementAsync(key, expField, pdc.expChange);
}
if (pdc.fangkaChange != 0)
{
tran.HashDecrementAsync(key, FangKaChangeField, pdc.fangkaChange);
tran.HashIncrementAsync(key, fangkaField, pdc.fangkaChange);
}
if (pdc.goldChange != 0)
{
tran.HashDecrementAsync(key, goldChangeField, pdc.goldChange);
tran.HashIncrementAsync(key, goldFiled, pdc.goldChange);
}
if (pdc.couponChange != 0)
{
tran.HashDecrementAsync(key, couponChangeField, pdc.couponChange);
tran.HashIncrementAsync(key, couponField, pdc.couponChange);
}
if (pdc.MatchRollChange != 0)
{
tran.HashDecrementAsync(key, MatchRollChangeField, pdc.MatchRollChange);
tran.HashIncrementAsync(key, MatchRollField, pdc.MatchRollChange);
}
return tran.Execute();
}
///
/// 变化数据写入redis中
///
/// 玩家数据变化值
/// 是否存在这个玩家
public static bool WriteToRedis(PlayerDataChange pdc)
{
string key = GetKey(pdc.userid);
var tran = redisManager.GetDataBase().CreateTransaction();
if (pdc.moneyChange != 0)
tran.HashIncrementAsync(key, moneyChangeField, pdc.moneyChange);
if (pdc.expChange != 0)
tran.HashIncrementAsync(key, expChangeField, pdc.expChange);
if (pdc.goldChange != 0)
tran.HashIncrementAsync(key, goldChangeField, pdc.goldChange);
if (pdc.fangkaChange != 0)
tran.HashIncrementAsync(key, FangKaChangeField, pdc.fangkaChange);
if (pdc.couponChange != 0)
tran.HashIncrementAsync(key, couponChangeField, pdc.couponChange);
if (pdc.MatchRollChange != 0)
tran.HashIncrementAsync(key, MatchRollChangeField, pdc.MatchRollChange);
tran.AddCondition(Condition.KeyExists(key));
return tran.Execute();
}
///
/// 加载redis 中的变化的数据
///
///
private static PlayerDataChange LoadRedisPlayerDataChange(int userid, bool isLock)
{
string key = GetKey(userid);
//加载redis 中变化的数据
var hes = redisManager.db.HashGetAll(key);
if (hes == null)
return null;
int tmpint;
long tmplong;
PlayerDataChange pdc =PlayerDataChange.Create(userid);
foreach (var item in hes)
{
switch (item.Name)
{
case moneyChangeField:
if (long.TryParse(item.Value, out tmplong))
{
pdc.moneyChange = tmplong;
}
else
{
Debug.Error("redis 中玩家的游戏币变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
case expChangeField:
if (int.TryParse(item.Value, out tmpint))
{
pdc.expChange = tmpint;
}
else
{
Debug.Error("redis 中玩家的经验变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
case goldChangeField:
if (int.TryParse(item.Value, out tmpint))
{
pdc.goldChange = tmpint;
}
else
{
Debug.Error("redis 中金币变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
case couponChangeField:
if (int.TryParse(item.Value, out tmpint))
{
pdc.couponChange = tmpint;
}
else
{
Debug.Error("redis 中奖券变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
case FangKaChangeField:
if (int.TryParse(item.Value, out tmpint))
{
pdc.fangkaChange = tmpint;
}
else
{
Debug.Error("redis 中房卡变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
case MatchRollChangeField:
if (int.TryParse(item.Value, out tmpint))
{
pdc.MatchRollChange = tmpint;
}
else
{
Debug.Error("redis 中比赛卷变化值不是数值userid:{0},value:{1}", userid, item.Value);
}
break;
}
}
return pdc;
}
///
/// 删除玩家redis key
///
///
public static void DeletePlayReids(int userid)
{
redisManager.db.KeyDelete(GetKey(userid));
}
///
/// 保存至sql数据库
///
///
public static bool SaveToSql(int userid)
{
PlayerDataChange pdc = LoadRedisPlayerDataChange(userid, false);
try
{
if (pdc != null && pdc.IsChanged)
{
//读取变化的数据
Debug.Info("保存玩家数据:" + pdc.userid + "," + pdc.moneyChange);
//先清楚redis, sql未保存成功 再手动回滚
if (!ClearRedisDataChange(pdc))
{
Debug.Error("数据竟然没有了,,,......玩家数据被穿透!!");
return false;
}
bool isOK = true;
try
{
isOK = PlayerDB.SavePlayerData(pdc);
}
catch (Exception e)
{
Debug.Error("保存玩家数据时出现错误:" + e.ToString());
isOK = false;
}
//写入要志
if (!isOK)
{
try
{
//获取相反值,回滚
PlayerDataChange pdc2 = pdc.GetOppositeValue(true);
ClearRedisDataChange(pdc2);
}
catch (Exception e)
{
Debug.Error($"回滚失败!错误错误!:{e.Message}\r\n" + pdc.ToString());
}
}
return isOK;
}
}finally
{
if (pdc != null)
{
ReferencePool.Recycle(pdc);
}
}
return true;
}
public Task GetUserAccountInfoAsync(int userid)
{
return Task.Run(() => GetUserAccountInfo(userid));
}
public UserAccountInfo GetUserAccountInfo(int userid)
{
var dt =GameDB.Instance.selectDb(dbbase.gamedb,"tbUserBaseInfo",new string[]{"UserName","NickName","nickNameEm"},$"userid={userid}");
if (dt.Rows.Count == 1)
{
var row = dt.Rows[0];
UserAccountInfo info = new UserAccountInfo();
info.UserId = userid;
var userName = Convert.ToString(row["UserName"]);
var nickName = Convert.ToString(row["NickName"]);
var nickNameEm = Convert.ToString(row["nickNameEm"]);
info.UserName = userName;
info.NickName = string.IsNullOrEmpty(nickNameEm) ? nickName : nickNameEm;
return info;
}
else
{
if (dt.Rows.Count < 1)
{
Debug.Error($"GetUserAccountInfo 未找到用户 {userid}");
}
else
{
Debug.Error($"GetUserAccountInfo 多条数据 userid={userid}");
}
return null;
}
}
}
///
/// 用户信息
///
public class UserAccountInfo
{
///
/// UserId
///
public int UserId;
///
/// 用户名
///
public string UserName;
///
/// 昵称
///
public string NickName;
}
}