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
1199 lines
44 KiB
C#
1199 lines
44 KiB
C#
/*
|
|
* 作者:吴隆健
|
|
* 日期: 2019-04-22
|
|
* 时间: 13:20
|
|
*
|
|
*/
|
|
|
|
using System;
|
|
using Server.DB.Redis;
|
|
using StackExchange.Redis;
|
|
using MrWu.Debug;
|
|
using GameData;
|
|
using Server.Data;
|
|
using System.Data;
|
|
using Server.DB.Sql;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Data.SqlClient;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using GameMessage;
|
|
using Newtonsoft.Json;
|
|
using Server;
|
|
|
|
namespace GameDAL.FriendRoom
|
|
{
|
|
/// <summary>
|
|
/// 房间管理
|
|
/// </summary>
|
|
public static class Room
|
|
{
|
|
/// <summary>
|
|
/// 战斗数据保存的文件夹 --服务器目录
|
|
/// </summary>
|
|
public const string RoomFightPath = "RoomFightPath";
|
|
|
|
/// <summary>
|
|
/// 密码
|
|
/// </summary>
|
|
public const string pwdField = "pwd";
|
|
|
|
/// <summary>
|
|
/// 最大玩家数量
|
|
/// </summary>
|
|
public const string maxCntField = "maxCnt";
|
|
|
|
/// <summary>
|
|
/// 最小玩家数量
|
|
/// </summary>
|
|
public const string minCntField = "minCnt";
|
|
|
|
/// <summary>
|
|
/// 朋友房多少局
|
|
/// </summary>
|
|
public const string warCntField = "warCnt";
|
|
|
|
/// <summary>
|
|
/// 当前开战的是第几场
|
|
/// </summary>
|
|
public const string nowCntField = "nowCnt";
|
|
|
|
/// <summary>
|
|
/// 结束的局数
|
|
/// </summary>
|
|
public const string overCntField = "overCnt";
|
|
|
|
/// <summary>
|
|
/// 房间所属游戏
|
|
/// </summary>
|
|
public const string gameidField = "gameid";
|
|
|
|
/// <summary>
|
|
/// 服务器版本
|
|
/// </summary>
|
|
public const string serverVerField = "serVer";
|
|
|
|
/// <summary>
|
|
/// 0普通开 1代开房间 5竞技比赛创建房间
|
|
/// </summary>
|
|
public const string CreateStyleField = "createStyle";
|
|
|
|
/// <summary>
|
|
/// 创建房间id 如果是普通创建房间 则此id为玩家userid 竞技比赛创建则为竞技比赛id
|
|
/// </summary>
|
|
public const string CreateIdField = "CreateId";
|
|
|
|
/// <summary>
|
|
/// 创建房间的房卡数量
|
|
/// </summary>
|
|
public const string fangkaField = "Fangka";
|
|
|
|
/// <summary>
|
|
/// 座位标记
|
|
/// </summary>
|
|
public const string seatTagField = "seatTag";
|
|
|
|
/// <summary>
|
|
/// 房间规则
|
|
/// </summary>
|
|
public const string roomRuleField = "RoomRule";
|
|
|
|
/// <summary>
|
|
/// 创建时间
|
|
/// </summary>
|
|
public const string CreateTimeField = "CreateTime";
|
|
|
|
/// <summary>
|
|
/// userid
|
|
/// </summary>
|
|
public const string useridField = "Userid";
|
|
|
|
/// <summary>
|
|
/// 昵称
|
|
/// </summary>
|
|
public const string nickNameField = "nickName";
|
|
|
|
/// <summary>
|
|
/// 性别
|
|
/// </summary>
|
|
public const string sexField = "sex";
|
|
|
|
/// <summary>
|
|
/// 头像
|
|
/// </summary>
|
|
public const string photoField = "photo";
|
|
|
|
/// <summary>
|
|
/// 房主
|
|
/// </summary>
|
|
public const string fangzhuField = "fangzhu";
|
|
|
|
/// <summary>
|
|
/// 战斗id
|
|
/// </summary>
|
|
public const string fightField = "fightid";
|
|
|
|
/// <summary>
|
|
/// 玩家的分值
|
|
/// </summary>
|
|
public const string scorejsonField = "playerScore";
|
|
|
|
/// <summary>
|
|
/// 战斗座位
|
|
/// </summary>
|
|
public const string fightseatField = "seat";
|
|
|
|
/// <summary>
|
|
/// 是否拦截ip
|
|
/// </summary>
|
|
public const string interceptIpField = "interceptIp";
|
|
|
|
/// <summary>
|
|
/// 是否拦截不是微信的账号
|
|
/// </summary>
|
|
public const string interceptWeChatField = "interceptWeChat";
|
|
|
|
/// <summary>
|
|
/// 是否关闭
|
|
/// </summary>
|
|
public const string isCloseField = "closeField";
|
|
|
|
/// <summary>
|
|
/// 关闭时间
|
|
/// </summary>
|
|
public const string closeTimeField = "closeTime";
|
|
|
|
/// <summary>
|
|
/// 房间号
|
|
/// </summary>
|
|
public const string roomNumField = "roomNum";
|
|
|
|
/// <summary>
|
|
/// 战斗超时时间
|
|
/// </summary>
|
|
public const string wartimeOutField = "warTimeOut";
|
|
|
|
/// <summary>
|
|
/// 加入超时时间
|
|
/// </summary>
|
|
public const string jointimeOutField = "jointimeOut";
|
|
|
|
/// <summary>
|
|
/// 玩法的id
|
|
/// </summary>
|
|
public const string wayidField = "wayid";
|
|
|
|
/// <summary>
|
|
/// 拓展字段
|
|
/// </summary>
|
|
public const string exField = "ex";
|
|
|
|
/// <summary>
|
|
/// 拓展字段
|
|
/// </summary>
|
|
public const string ruleexField = "ruleEx";
|
|
|
|
/// <summary>
|
|
/// 房间的最大数量
|
|
/// </summary>
|
|
public const int MaxCnt = 1000000;
|
|
|
|
/// <summary>
|
|
/// 是否保存战斗数据到数据库
|
|
/// </summary>
|
|
//public static bool IsSaveFightToDB = false;
|
|
|
|
/// <summary>
|
|
/// 房间分布式锁
|
|
/// </summary>
|
|
public static DistributedLock roomlock = new DistributedLock(100);
|
|
|
|
/// <summary>
|
|
/// 获的一个房间号
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static int GetRoomNum()
|
|
{
|
|
DateTime lastCreateTime = DateTime.Now;
|
|
string lastCreateNum = "000000";
|
|
|
|
try
|
|
{
|
|
var hes = redisManager.db.HashGetAll(RedisDictionary.lastRoomNum);
|
|
|
|
if (hes != null && hes.Length > 0)
|
|
{
|
|
foreach (var he in hes)
|
|
{
|
|
switch (he.Name)
|
|
{
|
|
case RedisDictionary.lastCreatRoomTime: //上次创建的时间
|
|
lastCreateTime = DateTime.Parse(he.Value);
|
|
break;
|
|
case RedisDictionary.lastRoomNum:
|
|
lastCreateNum = he.Value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error("7B69BB45-9B1A-49DF-BC81-3370D8CEDE59:" + e.ToString());
|
|
}
|
|
|
|
int lastCreateNum_ = int.Parse(lastCreateNum);
|
|
|
|
//时间差值,秒钟
|
|
int betweenTime = (int)(DateTime.Now - lastCreateTime).TotalSeconds;
|
|
|
|
//房间增量
|
|
int deltanum = betweenTime / 10 % 1000;
|
|
|
|
int roomNum_ = (lastCreateNum_ + deltanum) % MaxCnt;
|
|
|
|
while (roomNum_ == lastCreateNum_ || roomNum_ == 0)
|
|
{
|
|
roomNum_++;
|
|
roomNum_ = roomNum_ % MaxCnt;
|
|
}
|
|
|
|
try
|
|
{
|
|
HashEntry[] hhe = new HashEntry[2];
|
|
hhe[0] = new HashEntry(RedisDictionary.lastCreatRoomTime, DateTime.Now.ToString());
|
|
hhe[1] = new HashEntry(RedisDictionary.lastRoomNum, roomNum_);
|
|
redisManager.db.HashSetAsync(RedisDictionary.lastRoomNum, hhe, CommandFlags.FireAndForget);
|
|
}
|
|
finally
|
|
{
|
|
}
|
|
|
|
return roomNum_;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取朋友房数据的key
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static string GetWeiYiMaKey(string weiyima)
|
|
{
|
|
return RedisDictionary.friendRoomField + weiyima;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取朋友房中玩家数据key
|
|
/// </summary>
|
|
/// <param name="weiyima"></param>
|
|
/// <param name="index"></param>
|
|
/// <returns></returns>
|
|
public static string GetPlayerKey(string weiyima, int index)
|
|
{
|
|
return RedisDictionary.friendRoomField + weiyima + ":" + index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 存储玩家所在的房间号以及唯一码
|
|
/// </summary>
|
|
/// <param name="userid"></param>
|
|
/// <returns></returns>
|
|
public static string GetPlayerNumKey(int userid)
|
|
{
|
|
return "Game:FriendRoom:Player:" + userid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取每局详情key
|
|
/// </summary>
|
|
/// <param name="weiyima"></param>
|
|
/// <param name="index"></param>
|
|
/// <returns></returns>
|
|
public static string GetBureauKey(string weiyima, int index)
|
|
{
|
|
return RedisDictionary.friendRoomField + weiyima + "." + index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置当前开战次数
|
|
/// </summary>
|
|
/// <param name="deskinfo"></param>
|
|
public static void SetNowCnt(DeskInfo deskinfo)
|
|
{
|
|
string key = GetWeiYiMaKey(deskinfo.weiyima);
|
|
redisManager.db.HashSet(key, nowCntField, deskinfo.nowCnt);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置结束次数
|
|
/// </summary>
|
|
/// <param name="deskinfo"></param>
|
|
public static void SetOverCnt(DeskInfo deskinfo)
|
|
{
|
|
string key = GetWeiYiMaKey(deskinfo.weiyima);
|
|
redisManager.db.HashSet(key, overCntField, deskinfo.overCnt);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载房间号
|
|
/// </summary>
|
|
/// <param name="roomnum">房间号</param>
|
|
/// <param name="weiyima">唯一码</param>
|
|
/// <returns></returns>
|
|
public static bool LoadPlayerNum(int userid, ref string roomnum, ref string weiyima)
|
|
{
|
|
string plNumKey = GetPlayerNumKey(userid);
|
|
var hes = redisManager.db.HashGetAll(plNumKey);
|
|
|
|
if (hes == null || hes.Length == 0)
|
|
return false;
|
|
|
|
int len = hes.Length;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
switch (hes[i].Name)
|
|
{
|
|
case "num":
|
|
roomnum = hes[i].Value;
|
|
break;
|
|
case "weiyima":
|
|
weiyima = hes[i].Value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清楚玩家所在的房间号
|
|
/// </summary>
|
|
public static void ClearPlayerNum(int userid)
|
|
{
|
|
string plNumkey = GetPlayerNumKey(userid);
|
|
redisManager.db.KeyDelete(plNumkey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取房间的唯一码
|
|
/// </summary>
|
|
/// <param name="roomnum"></param>
|
|
/// <returns></returns>
|
|
public static bool GetWeiyima(int roomnum, ref string weiyima, ref ServerNode node)
|
|
{
|
|
string key = Roomkey(roomnum.ToString());
|
|
|
|
var hes = redisManager.db.HashGetAll(key);
|
|
if (hes == null || hes.Length == 0)
|
|
return false;
|
|
|
|
int len = hes.Length;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
switch (hes[i].Name)
|
|
{
|
|
case "weiyima":
|
|
weiyima = hes[i].Value;
|
|
break;
|
|
case "server":
|
|
node = JsonPack.GetData<ServerNode>(hes[i].Value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存玩家数据到redis中
|
|
/// </summary>
|
|
/// <param name="dskinfo"></param>
|
|
/// <param name="index"></param>
|
|
public static bool SavePlayerToRedis(DeskInfo dskinfo, int index)
|
|
{
|
|
DeskInfo.PlayerData pl = dskinfo.pls[index];
|
|
if (pl == null)
|
|
{
|
|
Debug.Error("程序错误....playerdata is null index:{0}", index);
|
|
return false;
|
|
}
|
|
|
|
string plNumKey = GetPlayerNumKey(pl.userid);
|
|
string key = GetPlayerKey(dskinfo.weiyima, index);
|
|
|
|
IDatabase db = redisManager.GetDataBase();
|
|
|
|
var tran = db.CreateTransaction();
|
|
|
|
tran.AddCondition(Condition.KeyNotExists(plNumKey));
|
|
tran.AddCondition(Condition.KeyNotExists(key));
|
|
|
|
var numhes = new HashEntry[2];
|
|
numhes[0] = new HashEntry("num", dskinfo.roomNum); //房间号
|
|
numhes[1] = new HashEntry("weiyima", dskinfo.weiyima); //唯一码
|
|
tran.HashSetAsync(plNumKey, numhes); //保存玩家的房间号以及唯一码
|
|
|
|
HashEntry[] hes = new HashEntry[6];
|
|
hes[0] = new HashEntry(useridField, pl.userid);
|
|
hes[1] = new HashEntry(fangzhuField, pl.fangzhu);
|
|
if (pl.nickName == null)
|
|
pl.nickName = string.Empty;
|
|
hes[2] = new HashEntry(nickNameField, pl.nickName);
|
|
if (pl.photo == null)
|
|
pl.photo = string.Empty;
|
|
hes[3] = new HashEntry(photoField, pl.photo);
|
|
hes[4] = new HashEntry(sexField, pl.sex);
|
|
hes[5] = new HashEntry("clubid", pl.ClubId);
|
|
tran.HashSetAsync(key, hes); //保存玩家数据
|
|
|
|
|
|
key = GetWeiYiMaKey(dskinfo.weiyima);
|
|
Debug.Info("key1:" + key + "," + plNumKey);
|
|
tran.AddCondition(Condition.KeyExists(key));
|
|
tran.HashSetAsync(key, seatTagField, JsonPack.GetJson(dskinfo.seat)); //保存房间数据中的座位信息
|
|
|
|
Debug.Log("key2:" + key);
|
|
|
|
return tran.Execute();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从redis中清楚玩家数据
|
|
/// </summary>
|
|
/// <param name="dskinfo"></param>
|
|
/// <param name="index"></param>
|
|
public static bool ClearPlayerToRedis(DeskInfo dskinfo, int index, int userid)
|
|
{
|
|
string key = GetPlayerKey(dskinfo.weiyima, index);
|
|
|
|
var db = redisManager.GetDataBase();
|
|
|
|
var tran = db.CreateTransaction();
|
|
|
|
tran.KeyDeleteAsync(key); //清空玩家数据
|
|
|
|
key = GetPlayerNumKey(userid);
|
|
tran.KeyDeleteAsync(key);
|
|
|
|
key = GetWeiYiMaKey(dskinfo.weiyima);
|
|
tran.AddCondition(Condition.KeyExists(key));
|
|
tran.HashSetAsync(key, seatTagField, JsonPack.GetJson(dskinfo.seat));
|
|
|
|
return tran.Execute();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存单局详情_修改及保存
|
|
/// </summary>
|
|
/// <param name="deskinfo">桌子信息</param>
|
|
/// <param name="index"></param>
|
|
public static void SaveBureau(DeskInfo deskinfo, int index)
|
|
{
|
|
string key = GetBureauKey(deskinfo.weiyima, index);
|
|
|
|
redisManager.db.StringSet(key, JsonPack.GetJson(deskinfo.burs[index]));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存牌局数据包
|
|
/// </summary>
|
|
/// <param name="weiyima"></param>
|
|
/// <param name="data"></param>
|
|
public static void SaveFightData(string weiyima, byte[] data)
|
|
{
|
|
FightDataManager.Instance.SaveFightData(weiyima,data);
|
|
}
|
|
|
|
public static void DelFightData(string weiyima)
|
|
{
|
|
FightDataManager.Instance.DelFightData(weiyima);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载牌局数据包
|
|
/// </summary>
|
|
/// <param name="weiyima"></param>
|
|
/// <returns></returns>
|
|
public static byte[] LoadFightData(string weiyima,out bool isOld)
|
|
{
|
|
byte[] data = FightDataManager.Instance.LoadFightData(weiyima,out isOld);
|
|
return data;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载战斗记录-回放用 --- todo 改成二进制存储
|
|
/// </summary>
|
|
/// <param name="weiyima">朋友房唯一码</param>
|
|
/// <param name="playCnt">玩的场次</param>
|
|
/// <param name="data">战斗数据</param>
|
|
public static void LoadFightRecord(string weiyima, int playCnt, out FightData data)
|
|
{
|
|
string key = RedisDictionary.friendRoomfightRecord + playCnt + ":" + weiyima;
|
|
|
|
//先找文本
|
|
string fileName = $"fightRecord/{key}";
|
|
fileName = fileName.Replace(":", "");
|
|
if (File.Exists(fileName))
|
|
{
|
|
try
|
|
{
|
|
|
|
string jsonData = File.ReadAllText(fileName);
|
|
data = JsonConvert.DeserializeObject<FightData>(jsonData);
|
|
File.Delete(fileName);
|
|
Debug.Info("读取回放数据!!");
|
|
return;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error($"加载战绩报错!{weiyima},{playCnt}" + e.Message);
|
|
}
|
|
}
|
|
|
|
var values = redisManager.db.ListRange(key);
|
|
if (values == null || values.Length == 0)
|
|
{
|
|
data = new FightData();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
data = new FightData();
|
|
try
|
|
{
|
|
int len = values.Length;
|
|
for (int i = 1; i < len; i++)
|
|
{
|
|
var dataone = JsonPack.GetData<fightdataone>(values[i]);
|
|
data.fightPack.Add(dataone);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error($"加载战斗数据-出现错误!!! {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 设置总结算
|
|
/// </summary>
|
|
public static void SetSumBurs(DeskInfo deskinfo)
|
|
{
|
|
if (deskinfo == null) return;
|
|
//if (!deskinfo.isAllOver) return;
|
|
if (deskinfo.seat == null || deskinfo.seat.Length <= 0 || deskinfo.burs == null ||
|
|
deskinfo.burs.Count <= 0) return;
|
|
try
|
|
{
|
|
deskinfo.SumBurs.Clear();
|
|
int[] seat = new int[deskinfo.seat.Length];
|
|
decimal[] score = new decimal[seat.Length];
|
|
for (int i = 0; i < deskinfo.seat.Length; i++)
|
|
{
|
|
seat[i] = deskinfo.seat[i];
|
|
var num = deskinfo.GetTotalScore(seat[i]);
|
|
score[i] = num * (decimal)deskinfo.rule.peilv;
|
|
}
|
|
|
|
score = CalcCapping(score, deskinfo.rule.Capping);
|
|
for (int i = 0; i < seat.Length; i++)
|
|
{
|
|
DeskInfo.SummaryBureau temp = new DeskInfo.SummaryBureau { seat = seat[i], Score = score[i] };
|
|
deskinfo.SumBurs.Add(temp);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error($"SetSumBurs error:{e.Message},code:{e.StackTrace},Data info");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算超过封顶的玩家,让赢的玩家均摊
|
|
/// </summary>
|
|
/// <param name="playScore"></param>
|
|
/// <param name="capping"></param>
|
|
/// <returns></returns>
|
|
public static decimal[] CalcCapping(decimal[] playScore, int capping)
|
|
{
|
|
if (capping <= 0) return playScore;
|
|
int len = playScore.Length;
|
|
decimal zongDuo = 0; //输的多出来的总数
|
|
decimal zongShu = 0; //超过封顶的玩家 输的总数
|
|
List<int> winIdx = new List<int>(); //赢钱人的下标
|
|
List<decimal> winJian = new List<decimal>(); //存储赢钱人平均摊的数值
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
var temp = Math.Abs(playScore[i]);
|
|
if (playScore[i] < 0 && temp > capping)
|
|
{
|
|
zongDuo += temp - capping;
|
|
playScore[i] = 0 - capping;
|
|
}
|
|
|
|
if (playScore[i] > 0)
|
|
{
|
|
zongShu += playScore[i];
|
|
winIdx.Add(i);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < winIdx.Count - 1; i++)
|
|
{
|
|
var temp = zongDuo * playScore[winIdx[i]] / zongShu;
|
|
winJian.Add(Math.Round(temp, 2));
|
|
}
|
|
|
|
var temp1 = zongDuo - winJian.Sum();
|
|
winJian.Add(temp1);
|
|
for (int i = 0; i < winIdx.Count; i++)
|
|
{
|
|
playScore[winIdx[i]] = playScore[winIdx[i]] - winJian[i];
|
|
}
|
|
|
|
return playScore;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据唯一码获取房间号
|
|
/// </summary>
|
|
/// <param name="weiyima">唯一码</param>
|
|
/// <returns>房间号</returns>
|
|
public static string GetRoomNum(string weiyima)
|
|
{
|
|
string key = GetWeiYiMaKey(weiyima);
|
|
|
|
return redisManager.db.HashGet(key, roomNumField);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载房间数据_当前房间
|
|
/// </summary>
|
|
/// <param name="weiyima">唯一码</param>
|
|
/// <param name="data">房间数据</param>
|
|
/// <returns>是否加载成功</returns>
|
|
public static bool LoadRoom(string weiyima, out DeskInfo data)
|
|
{
|
|
string key = GetWeiYiMaKey(weiyima);
|
|
|
|
data = new DeskInfo();
|
|
|
|
DeskInfo dt = data;
|
|
dt.rule = new DeskRule();
|
|
DeskRule rule = dt.rule;
|
|
|
|
Func<bool> func = () =>
|
|
{
|
|
dt.weiyima = weiyima;
|
|
try
|
|
{
|
|
//获取朋友房数据 //朋友房基本数据
|
|
HashEntry[] hes = redisManager.db.HashGetAll(key);
|
|
if (hes == null || hes.Length <= 0)
|
|
return false;
|
|
foreach (var he in hes)
|
|
{
|
|
switch (he.Name)
|
|
{
|
|
case roomNumField:
|
|
dt.roomNum = he.Value;
|
|
break;
|
|
case pwdField:
|
|
rule.pwd = he.Value;
|
|
break;
|
|
case maxCntField:
|
|
rule.maxCnt = int.Parse(he.Value);
|
|
break;
|
|
case minCntField:
|
|
rule.minCnt = int.Parse(he.Value);
|
|
break;
|
|
case warCntField:
|
|
rule.warCnt = int.Parse(he.Value);
|
|
break;
|
|
case exField:
|
|
var ex = JsonPack.GetData<string[]>(he.Value);
|
|
rule.ex = ex;
|
|
break;
|
|
case ruleexField:
|
|
var exstr = he.value;
|
|
rule.RuleEx = string.IsNullOrEmpty(exstr)
|
|
? new DeskRuleEx()
|
|
: JsonPack.GetData<DeskRuleEx>(exstr);
|
|
break;
|
|
case "peilv":
|
|
rule.peilv = float.Parse(he.Value);
|
|
break;
|
|
case "Capping":
|
|
rule.Capping = int.Parse(he.value);
|
|
break;
|
|
case "Remarks":
|
|
rule.Remarks = he.value;
|
|
break;
|
|
case overCntField:
|
|
dt.overCnt = int.Parse(he.Value);
|
|
break;
|
|
case gameidField:
|
|
rule.game_serid = int.Parse(he.Value);
|
|
break;
|
|
case serverVerField:
|
|
dt.serverVer = int.Parse(he.Value);
|
|
break;
|
|
case CreateStyleField:
|
|
dt.creatStyle = int.Parse(he.Value);
|
|
break;
|
|
case CreateIdField:
|
|
dt.creatUserid = int.Parse(he.Value);
|
|
break;
|
|
case fangkaField:
|
|
dt.fangka = int.Parse(he.Value);
|
|
break;
|
|
|
|
case seatTagField:
|
|
dt.seat = JsonPack.GetData<int[]>(he.Value);
|
|
Debug.Info("座位号:" + he.Value);
|
|
break;
|
|
case roomRuleField:
|
|
dt.rule.roomrule = he.Value;
|
|
break;
|
|
case CreateTimeField:
|
|
dt.CreateTime = DateTime.Parse(he.Value);
|
|
break;
|
|
case nowCntField:
|
|
dt.nowCnt = int.Parse(he.Value);
|
|
break;
|
|
case interceptIpField:
|
|
rule.interceptIp = int.Parse(he.Value);
|
|
break;
|
|
case interceptWeChatField:
|
|
rule.interceptWeChat = int.Parse(he.Value);
|
|
break;
|
|
case isCloseField:
|
|
dt.isClose = int.Parse(he.Value);
|
|
break;
|
|
case closeTimeField:
|
|
dt.closeTime = DateTime.Parse(he.Value);
|
|
break;
|
|
case jointimeOutField:
|
|
dt.jointimeOutDis = DateTime.Parse(he.Value);
|
|
break;
|
|
case wartimeOutField:
|
|
dt.wartimeOutDis = DateTime.Parse(he.Value);
|
|
break;
|
|
case wayidField:
|
|
dt.wayid = he.Value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//RedisDictionary.friendRoomPlayerField+
|
|
|
|
dt.pls = new DeskInfo.PlayerData[rule.maxCnt];
|
|
dt.OnceFight = new int[rule.maxCnt];
|
|
for (int i = 0; i < rule.maxCnt; i++)
|
|
{
|
|
//加载玩家数据
|
|
string
|
|
plkey = GetPlayerKey(weiyima, i); // RedisDictionary.friendRoomPlayerField + weiyima+"."+i;
|
|
|
|
HashEntry[] plhes = redisManager.db.HashGetAll(plkey);
|
|
|
|
if (plhes == null || plhes.Length <= 0)
|
|
{
|
|
dt.pls[i] = null;
|
|
}
|
|
else
|
|
{
|
|
dt.pls[i] = new DeskInfo.PlayerData();
|
|
foreach (HashEntry he in plhes)
|
|
{
|
|
switch (he.Name)
|
|
{
|
|
case useridField:
|
|
dt.pls[i].userid = int.Parse(he.Value);
|
|
break;
|
|
case nickNameField:
|
|
dt.pls[i].nickName = he.Value;
|
|
break;
|
|
case sexField:
|
|
dt.pls[i].sex = int.Parse(he.Value);
|
|
break;
|
|
case photoField:
|
|
dt.pls[i].photo = he.Value;
|
|
break;
|
|
case fangzhuField:
|
|
dt.pls[i].fangzhu = int.Parse(he.Value);
|
|
break;
|
|
case "clubid":
|
|
dt.pls[i].ClubId = int.Parse(he.Value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//加载战斗记录
|
|
int cnt = dt.nowCnt != 0 ? dt.nowCnt : dt.overCnt;
|
|
for (int i = 0; i < cnt; i++)
|
|
{
|
|
string fightkey = GetBureauKey(weiyima, i); // RedisDictionary.friendRoomField+weiyima+i;
|
|
|
|
DeskInfo.Bureau bru = new DeskInfo.Bureau();
|
|
bru.id = i;
|
|
|
|
string jsonfihtrecord = redisManager.db.StringGet(fightkey);
|
|
if (jsonfihtrecord != null)
|
|
bru = JsonPack.GetData<DeskInfo.Bureau>(jsonfihtrecord);
|
|
|
|
dt.burs.Add(bru);
|
|
}
|
|
|
|
Debug.Info("桌子加载成功!");
|
|
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error("加载房间号错误:" + e.ToString());
|
|
return false;
|
|
}
|
|
};
|
|
|
|
bool r = roomlock.LockRun(key, func, 5);
|
|
data.plsDis = new int[data.rule.maxCnt];
|
|
Room.SetSumBurs(data);
|
|
return r;
|
|
}
|
|
|
|
//创建房间移除房间修改房间只能又一个程序处理 其他程序只能读数据,不能改数据
|
|
|
|
/// <summary>
|
|
/// 创建房间 只负责redis数据
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
public static bool CreateRoom(DeskInfo data, ServerNode node)
|
|
{
|
|
//房间号-> 唯一码 - 管理的模块
|
|
//朋友房的房间信息
|
|
|
|
//保证数据一致性
|
|
|
|
//先写房间号 - 唯一码 - 管理模块
|
|
|
|
string roomnum = data.roomNum;
|
|
string weiyima = data.weiyima;
|
|
|
|
//不存在才可以改,存在,不能改
|
|
var db = redisManager.GetDataBase();
|
|
|
|
string key = Roomkey(roomnum);
|
|
string datakey = RedisDictionary.friendRoomField + data.weiyima;
|
|
|
|
var tran = db.CreateTransaction();
|
|
tran.AddCondition(Condition.KeyNotExists(key)); //不存在才能执行事务
|
|
tran.AddCondition(Condition.KeyNotExists(datakey));
|
|
|
|
HashEntry[] hes = new HashEntry[2];
|
|
hes[0] = new HashEntry("weiyima", weiyima);
|
|
hes[1] = new HashEntry("server", JsonPack.GetJson(node));
|
|
tran.HashSetAsync(key, hes);
|
|
|
|
var datahes = GetDeskInfoHashEntry(data);
|
|
|
|
|
|
tran.HashSetAsync(datakey, datahes.ToArray()); //保存朋友房数据
|
|
|
|
Debug.Info("创建朋友房:" + key + "," + datakey);
|
|
|
|
return tran.Execute();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取桌子信息
|
|
/// </summary>
|
|
private static List<HashEntry> GetDeskInfoHashEntry(DeskInfo data)
|
|
{
|
|
List<HashEntry> datahes = new List<HashEntry>();
|
|
datahes.Add(new HashEntry(roomNumField, data.roomNum));
|
|
DeskRule rule = data.rule;
|
|
if (rule.pwd == null)
|
|
rule.pwd = string.Empty;
|
|
datahes.Add(new HashEntry(pwdField, rule.pwd));
|
|
datahes.Add(new HashEntry(maxCntField, rule.maxCnt));
|
|
datahes.Add(new HashEntry(minCntField, rule.minCnt));
|
|
datahes.Add(new HashEntry(warCntField, rule.warCnt));
|
|
datahes.Add(new HashEntry(nowCntField, data.nowCnt));
|
|
datahes.Add(new HashEntry(overCntField, data.overCnt));
|
|
datahes.Add(new HashEntry(gameidField, rule.game_serid));
|
|
datahes.Add(new HashEntry(serverVerField, data.serverVer));
|
|
datahes.Add(new HashEntry(CreateStyleField, data.creatStyle));
|
|
datahes.Add(new HashEntry(CreateIdField, data.creatUserid));
|
|
datahes.Add(new HashEntry(fangkaField, data.fangka));
|
|
datahes.Add(new HashEntry(seatTagField, JsonPack.GetJson(data.seat)));
|
|
datahes.Add(new HashEntry(roomRuleField, data.rule.roomrule));
|
|
datahes.Add(new HashEntry(CreateTimeField, data.CreateTime.ToString()));
|
|
datahes.Add(new HashEntry(interceptIpField, rule.interceptIp));
|
|
datahes.Add(new HashEntry(interceptWeChatField, rule.interceptWeChat));
|
|
datahes.Add(new HashEntry(isCloseField, data.isClose));
|
|
datahes.Add(new HashEntry(closeTimeField, data.closeTime.ToString()));
|
|
datahes.Add(new HashEntry(exField, JsonPack.GetJson(data.rule.ex)));
|
|
datahes.Add(new HashEntry(ruleexField, data.rule.RuleExStr));
|
|
datahes.Add(new HashEntry("peilv", rule.peilv));
|
|
datahes.Add(new HashEntry("Capping", rule.Capping));
|
|
datahes.Add(new HashEntry("Remarks", rule.Remarks == null ? "" : rule.Remarks.ToString()));
|
|
datahes.Add(new HashEntry(wartimeOutField, data.wartimeOutDis.ToString()));
|
|
datahes.Add(new HashEntry(jointimeOutField, data.jointimeOutDis.ToString()));
|
|
if (data.wayid != null)
|
|
datahes.Add(new HashEntry(wayidField, data.wayid.ToString()));
|
|
return datahes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重新写入房间
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
public static bool RenewRoom(DeskInfo data)
|
|
{
|
|
string roomnum = data.roomNum;
|
|
string weiyima = data.weiyima;
|
|
|
|
//不存在才可以改,存在,不能改
|
|
var db = redisManager.GetDataBase();
|
|
string key = Roomkey(roomnum);
|
|
string datakey = RedisDictionary.friendRoomField + data.weiyima;
|
|
|
|
var datahes = GetDeskInfoHashEntry(data);
|
|
db.HashSetAsync(datakey, datahes.ToArray()); //保存朋友房数据
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除房间 ->先删房间主体->删除房间玩家数据->玩家详情
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
public static bool DeleteRoom(DeskInfo data)
|
|
{
|
|
if (!data.noWar)
|
|
{
|
|
//开战过保存到数据库
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
SaveRoomData(data);
|
|
SaveRoomPlayerData(data);
|
|
});
|
|
}
|
|
|
|
var db = redisManager.GetDataBase();
|
|
|
|
var tran = db.CreateTransaction();
|
|
|
|
//删除玩家的被锁的 房间号-对应的唯一码
|
|
//删除房间号-被锁的唯一码
|
|
//删除房间详细数据
|
|
//删除玩家数据
|
|
//删除每局详情,删除玩家详情
|
|
|
|
string key = Roomkey(data.roomNum);
|
|
tran.KeyDeleteAsync(key); //房间号-对应的唯一码
|
|
|
|
int len = data.pls.Length;
|
|
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (data.pls[i] == null) continue;
|
|
string plkey = GetPlayerNumKey(data.pls[i].userid);
|
|
tran.KeyDeleteAsync(plkey); //清楚玩家所在的房间号以及对应的唯一码
|
|
int index = -1;
|
|
int count = data.seat.Length; //玩家玩家详细数据
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
if (data.seat[j] == i)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 0)
|
|
{
|
|
Debug.Error("未找到玩家位置!");
|
|
continue;
|
|
}
|
|
|
|
string pldatakey = GetPlayerKey(data.weiyima, index);
|
|
tran.KeyDeleteAsync(pldatakey);
|
|
}
|
|
|
|
//删除房间详细数据
|
|
|
|
string datakey = RedisDictionary.friendRoomField + data.weiyima;
|
|
tran.KeyDeleteAsync(datakey);
|
|
|
|
DelFightData(data.weiyima);
|
|
// string fightdatakey = GetFightDataKey(data.weiyima);
|
|
// tran.KeyDeleteAsync(fightdatakey);
|
|
|
|
//Debug.Error("解散游戏数据!" + data.overCnt + "," + fightdatakey);
|
|
|
|
for (int i = 0; i < data.overCnt + 1; i++)
|
|
{
|
|
string bureaukey = GetBureauKey(data.weiyima, i);
|
|
tran.KeyDeleteAsync(bureaukey);
|
|
}
|
|
|
|
return tran.Execute();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存房间基本数据
|
|
/// </summary>
|
|
static void SaveRoomData(DeskInfo data)
|
|
{
|
|
DeskRule rule = data.rule;
|
|
var sql = GameDB.Instance.BeginSetProcedureParameter(dbbase.game2018, "SaveRoomData202408");
|
|
GameDB.Instance.AddProdureParameters(sql, "@weiyima", SqlDbType.Char, data.weiyima);
|
|
GameDB.Instance.AddProdureParameters(sql, "@roomnum", SqlDbType.Char, data.roomNum);
|
|
GameDB.Instance.AddProdureParameters(sql, "@maxcnt", SqlDbType.Int, rule.maxCnt);
|
|
GameDB.Instance.AddProdureParameters(sql, "@mincnt", SqlDbType.Int, rule.minCnt);
|
|
GameDB.Instance.AddProdureParameters(sql, "@warcnt", SqlDbType.Int, rule.warCnt);
|
|
GameDB.Instance.AddProdureParameters(sql, "@nowcnt", SqlDbType.Int, data.nowCnt);
|
|
GameDB.Instance.AddProdureParameters(sql, "@overcnt", SqlDbType.Int, data.overCnt);
|
|
GameDB.Instance.AddProdureParameters(sql, "@gameid", SqlDbType.Int, rule.game_serid);
|
|
GameDB.Instance.AddProdureParameters(sql, "@serverVer", SqlDbType.Int, data.serverVer);
|
|
GameDB.Instance.AddProdureParameters(sql, "@createStyle", SqlDbType.Int, data.creatStyle);
|
|
GameDB.Instance.AddProdureParameters(sql, "@createid", SqlDbType.Int, data.creatUserid);
|
|
GameDB.Instance.AddProdureParameters(sql, "@fangka", SqlDbType.Int, data.fangka);
|
|
GameDB.Instance.AddProdureParameters(sql, "@interceptIp", SqlDbType.Int, rule.interceptIp);
|
|
GameDB.Instance.AddProdureParameters(sql, "@interceptWeChat", SqlDbType.Int, rule.interceptWeChat);
|
|
|
|
byte[] bts = System.Text.Encoding.UTF8.GetBytes(data.rule.roomrule);
|
|
GameDB.Instance.AddProdureParameters(sql, "@roomrule", SqlDbType.Image, bts); //json的base64数据
|
|
|
|
GameDB.Instance.AddProdureParameters(sql, "@createTime", SqlDbType.DateTime, data.CreateTime);
|
|
GameDB.Instance.AddProdureParameters(sql, "@closeTime", SqlDbType.DateTime, data.closeTime);
|
|
GameDB.Instance.AddProdureParameters(sql, "@ex", SqlDbType.Text, JsonPack.GetJson(data.rule.ex));
|
|
|
|
GameDB.Instance.AddProdureParameters(sql, "@ruleEx", SqlDbType.Text, data.rule.RuleExStr);
|
|
|
|
GameDB.Instance.AddProdureParameters(sql, "@peilv", SqlDbType.Float, rule.peilv);
|
|
GameDB.Instance.AddProdureParameters(sql, "@Capping", SqlDbType.Int, rule.Capping);
|
|
GameDB.Instance.AddProdureParameters(sql, "@Remarks", SqlDbType.VarChar,
|
|
rule.Remarks == null ? "" : rule.Remarks);
|
|
GameDB.Instance.EndAddProdureParameters(sql);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存玩家数据
|
|
/// </summary>
|
|
static void SaveRoomPlayerData(DeskInfo data)
|
|
{
|
|
int len = data.pls.Length;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (data.pls[i] == null) continue; //这个位置没人
|
|
|
|
var sql = GameDB.Instance.BeginSetProcedureParameter(dbbase.game2018, "SaveRoom_PlayerData2024");
|
|
GameDB.Instance.AddProdureParameters(sql, "@weiyima", SqlDbType.Char, data.weiyima);
|
|
GameDB.Instance.AddProdureParameters(sql, "@playeridx", SqlDbType.Int, i);
|
|
GameDB.Instance.AddProdureParameters(sql, "@userid", SqlDbType.Int, data.pls[i].userid);
|
|
GameDB.Instance.AddProdureParameters(sql, "@nickName", SqlDbType.NChar, data.pls[i].nickName);
|
|
GameDB.Instance.AddProdureParameters(sql, "@sex", SqlDbType.Int, data.pls[i].sex);
|
|
GameDB.Instance.AddProdureParameters(sql, "@clubid", SqlDbType.Int, data.pls[i].ClubId);
|
|
|
|
byte[] bts = Encoding.UTF8.GetBytes(data.pls[i].photo);
|
|
GameDB.Instance.AddProdureParameters(sql, "@photo", SqlDbType.Image, bts);
|
|
GameDB.Instance.AddProdureParameters(sql, "@fangzhu", SqlDbType.Int, data.pls[i].fangzhu);
|
|
|
|
long allScore = 0;
|
|
foreach (var item in data.burs)
|
|
{
|
|
allScore += item.playScore[i];
|
|
}
|
|
|
|
GameDB.Instance.AddProdureParameters(sql, "@allScore", SqlDbType.Int, allScore);
|
|
GameDB.Instance.AddProdureParameters(sql, "@gameid", SqlDbType.Int, data.rule.game_serid);
|
|
GameDB.Instance.EndAddProdureParameters(sql);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存战斗数据
|
|
/// </summary>
|
|
/// <param name="deskinfo"></param>
|
|
/// <param name="data"></param>
|
|
/// <param name="style">结束类型</param>
|
|
public static void SaveFightRecord(DeskInfo deskinfo, FightData data, int style = -1)
|
|
{
|
|
//ClearFightRecord(deskinfo.weiyima, deskinfo.burs.Count);
|
|
if (data == null)
|
|
return;
|
|
Debug.Info("保存战斗记录到数据库!");
|
|
//string jsondata = JsonPack.GetJson(data);
|
|
int idx = deskinfo.burs.Count;
|
|
int index = idx - 1;
|
|
if (index < 0)
|
|
{
|
|
Debug.Warning("未开战过,无需保存!");
|
|
return;
|
|
}
|
|
|
|
int lx = deskinfo.creatStyle;
|
|
var playScore = deskinfo.burs[index].playScore;
|
|
//string score = JsonPack.GetJson(playScore);
|
|
var seatd = deskinfo.burs[index].seat;
|
|
//string seat = JsonPack.GetJson(seatd);
|
|
string weiyima = deskinfo.weiyima;
|
|
|
|
if (lx == 5 || lx == 0)
|
|
{
|
|
RoomFightData temp = new RoomFightData { playScore = playScore, seat = seatd, data = data, style = style };
|
|
FightRecordManager.Instance.SaveFightInfo(weiyima, temp, idx);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 房间号key 里面保存着,管理房间的模块以及房间号对应的唯一码
|
|
/// </summary>
|
|
/// <param name="roomnum">房间号</param>
|
|
/// <returns>返回值</returns>
|
|
public static string Roomkey(string roomnum)
|
|
{
|
|
return "Game:FriendRoom:RoomNum:" + roomnum;
|
|
}
|
|
|
|
public static string GetClubFightKey(int userId)
|
|
{
|
|
return $"ClubFightLock:{userId}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 锁住俱乐部玩家
|
|
/// </summary>
|
|
/// <param name="userid"></param>
|
|
/// <param name="serId"></param>
|
|
public static void LockClubFightPlayer(List<int> userid, int serId)
|
|
{
|
|
try
|
|
{
|
|
var ts = TimeSpan.FromHours(1);
|
|
IBatch batch = redisManager.db.CreateBatch();
|
|
for (int i = 0; i < userid.Count; i++)
|
|
{
|
|
batch.StringSetAsync(GetClubFightKey(userid[i]), serId, ts);
|
|
}
|
|
batch.Execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error($"LockClubFightPlayer Error:{e.Message}");
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
} |