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
This commit is contained in:
308
GlobalSever/GlobalManager/CaCheManager.cs
Normal file
308
GlobalSever/GlobalManager/CaCheManager.cs
Normal file
@ -0,0 +1,308 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.DB.Redis;
|
||||
using System.Collections.Concurrent;
|
||||
using MrWu.Debug;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using StackExchange.Redis;
|
||||
using Server.Pack;
|
||||
using Server.MQ;
|
||||
using GameData;
|
||||
|
||||
namespace Server {
|
||||
/// <summary>
|
||||
/// 缓存管理
|
||||
/// </summary>
|
||||
public class CaCheManager {
|
||||
|
||||
private CaCheManager() {
|
||||
}
|
||||
|
||||
static CaCheManager() {
|
||||
instance = new CaCheManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实例
|
||||
/// </summary>
|
||||
public static CaCheManager instance {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private IDatabase DB {
|
||||
get {
|
||||
return redisManager.GetDataBase(DbStyle.main, RedisDictionary.cachedb);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓 key 对应 缓存的key Tuple('版本','数据')
|
||||
/// </summary>
|
||||
ConcurrentDictionary<string, Tuple<long, string>> caches = new ConcurrentDictionary<string, Tuple<long, string>>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Tuple<long, string> GetCache(string key) {
|
||||
|
||||
Tuple<long, string> result = null;
|
||||
|
||||
if (!caches.TryGetValue(key, out result)) { //缓存没有值
|
||||
result = UpdateKey(key);
|
||||
}
|
||||
|
||||
if (result == null && !caches.TryGetValue(key, out result)) {
|
||||
Debug.Warning("没这个缓存数据:" + key);
|
||||
}
|
||||
|
||||
Debug.Log("获取到缓存!" + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<Tuple<long, string>> UpdateKeyAsync(string key)
|
||||
{
|
||||
return Task.Run(() => UpdateKey(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新缓存_也就是把Redis中的数据读取到内存中来
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public Tuple<long, string> UpdateKey(string key) {
|
||||
|
||||
Debug.Info("更新缓存" + key);
|
||||
var type = redisManager.Getdb(RedisDictionary.cachedb).KeyType(key);
|
||||
|
||||
Tuple<long, string> result = null;
|
||||
Tuple<long, string> value = null;
|
||||
|
||||
switch (type) {
|
||||
case StackExchange.Redis.RedisType.Hash:
|
||||
value = GetHash(key); //转换成 json ver,data={字典} 字典传输出去
|
||||
break;
|
||||
case StackExchange.Redis.RedisType.String:
|
||||
value = GetString(key); //转换成 json ver,data={字符串}
|
||||
break;
|
||||
case StackExchange.Redis.RedisType.List:
|
||||
value = GetList(key); //转换成 json ver,data={数组}
|
||||
break;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(key)) {
|
||||
result = caches.AddOrUpdate(key, value, (k, v) => value);
|
||||
}
|
||||
|
||||
//Debug.Info($"得到缓存:{value}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取hash
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
Tuple<long, string> GetHash(string key) {
|
||||
var tran = DB.CreateTransaction();
|
||||
var keyvaluestask = tran.HashGetAllAsync(key); //拿数据
|
||||
var valuestask = tran.StringGetAsync(key + ":ver"); //拿版本
|
||||
if (tran.Execute()) {
|
||||
if (keyvaluestask.Result == null || keyvaluestask.Result.Length == 0)
|
||||
return null;
|
||||
|
||||
var keyvalues = keyvaluestask.Result;
|
||||
long value = -1;
|
||||
string verResult = valuestask.Result;
|
||||
if (verResult != null && !long.TryParse(verResult, out value)) {
|
||||
Debug.Warning("未获取到版本号!" + key);
|
||||
value = -1;
|
||||
}
|
||||
|
||||
JObject obj = new JObject();
|
||||
int len = keyvalues.Length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
obj[keyvalues[i].Name] = JsonPack.GetData<JObject>(keyvalues[i].Value);
|
||||
}
|
||||
//Debug.Info("获取到缓存:" + key + ":" + verResult);
|
||||
JObject baseobj = new JObject();
|
||||
baseobj["ver"] = verResult;
|
||||
baseobj["data"] = obj;
|
||||
return new Tuple<long, string>(value, JsonPack.GetJson(baseobj));
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字符串
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
Tuple<long, string> GetString(string key) {
|
||||
var tran = DB.CreateTransaction();
|
||||
var valuetask = tran.StringGetAsync(key);
|
||||
var vertask = tran.StringGetAsync(key + ":ver");
|
||||
|
||||
if (tran.Execute()) {
|
||||
long ver = -1;
|
||||
string verResult = vertask.Result;
|
||||
if (verResult != null && !long.TryParse(verResult, out ver)) {
|
||||
Debug.Warning("未获取到版本号!" + key);
|
||||
ver = -1;
|
||||
}
|
||||
JObject baseobj = new JObject();
|
||||
baseobj["ver"] = ver;
|
||||
baseobj["data"] = (string)valuetask.Result;
|
||||
return new Tuple<long, string>(ver, JsonPack.GetJson(baseobj));
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取列表
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
Tuple<long, string> GetList(string key) {
|
||||
var tran = DB.CreateTransaction();
|
||||
var valuestask = tran.ListRangeAsync(key);
|
||||
var vertask = tran.StringGetAsync(key + ":ver");
|
||||
|
||||
if (tran.Execute()) {
|
||||
var values = valuestask.Result;
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
long ver = -1;
|
||||
string verResult = vertask.Result;
|
||||
if (verResult != null && !long.TryParse(verResult, out ver)) {
|
||||
Debug.Warning("未获取到版本号!" + key);
|
||||
ver = -1;
|
||||
}
|
||||
|
||||
JArray jar = new JArray();
|
||||
|
||||
int len = values.Length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
jar.Add(JsonPack.GetData<JObject>(values[i]));
|
||||
}
|
||||
|
||||
JObject baseobj = new JObject();
|
||||
baseobj["ver"] = ver;
|
||||
baseobj["data"] = jar;
|
||||
|
||||
return new Tuple<long, string>(ver, JsonPack.GetJson(baseobj));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查版本是否达到了最大
|
||||
/// </summary>
|
||||
/// <param name="verKey">版本key</param>
|
||||
/// <param name="task">增加版本的任务</param>
|
||||
private void CheckVerMax(string verKey, Task<long> task) {
|
||||
if (task.Result > 9999999999) {
|
||||
DB.StringSet(verKey, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public bool DelCache(string key) {
|
||||
var tran = DB.CreateTransaction();
|
||||
tran.KeyDeleteAsync(key);
|
||||
tran.KeyDeleteAsync(key + ":ver");
|
||||
return tran.Execute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设Hash缓存数据
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="field"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetHash(string key, string field, string value) {
|
||||
var tran = DB.CreateTransaction();
|
||||
tran.HashSetAsync(key, field, value);
|
||||
string verKey = key + ":ver";
|
||||
var taskVer = tran.StringIncrementAsync(verKey);
|
||||
|
||||
Debug.Info($"保存缓存数据:{field} {value}");
|
||||
if (tran.Execute()) {
|
||||
Debug.Log("保存Hash缓存成功!" + value);
|
||||
CheckVerMax(verKey, taskVer);
|
||||
} else {
|
||||
Debug.Error("保存配置失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存的Hash字段
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="field"></param>
|
||||
public void DelHashField(string key, string field) {
|
||||
var tran = DB.CreateTransaction();
|
||||
tran.HashDeleteAsync(key, field);
|
||||
string verKey = key + ":ver";
|
||||
var taskVer = tran.StringIncrementAsync(verKey);
|
||||
|
||||
if (tran.Execute()) {
|
||||
Debug.Log("删除Hash子段成功!");
|
||||
CheckVerMax(verKey, taskVer);
|
||||
} else {
|
||||
Debug.Error("删除配置失败!");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置字符串类型的缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetString(string key, string value) {
|
||||
var tran = DB.CreateTransaction();
|
||||
tran.StringSetAsync(key, value);
|
||||
string verKey = key + ":ver";
|
||||
var taskVer = tran.StringIncrementAsync(verKey);
|
||||
|
||||
if (tran.Execute()) {
|
||||
Debug.Log("设置string缓存成功!" + value);
|
||||
CheckVerMax(verKey, taskVer);
|
||||
} else {
|
||||
Debug.Error("保存配置失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 列表形式的缓存 下次再拓展
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// 发送缓存变化包
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public static void SendCacheChange(string key) {
|
||||
PackHead head = PackHead.Create(ServerPackAgreement.CacheChange);
|
||||
head.otherString = new string[] { key };
|
||||
|
||||
Debug.Log("发送更新缓存包:");
|
||||
GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, null), true);
|
||||
head.Dispose();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
846
GlobalSever/GlobalManager/GlobalManager.cs
Normal file
846
GlobalSever/GlobalManager/GlobalManager.cs
Normal file
@ -0,0 +1,846 @@
|
||||
/*
|
||||
* 由SharpDevelop创建。
|
||||
* 用户: Administrator
|
||||
* 日期: 2018-09-13
|
||||
* 时间: 17:14
|
||||
*
|
||||
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GameData;
|
||||
using MrWu.Debug;
|
||||
using MrWu.RabbitMQ;
|
||||
using Server.Data.Module;
|
||||
using Server.DB.Redis;
|
||||
using Server.DB.Sql;
|
||||
using Server.MQ;
|
||||
using Server.Pack;
|
||||
using Server.Config;
|
||||
using Server.Core;
|
||||
using Server.Net;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 全局管理
|
||||
/// </summary>
|
||||
public abstract partial class GlobalManager : ITimerProcessor, IServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否需要重新加载配置
|
||||
/// </summary>
|
||||
public bool IsReloadTable;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器单元工厂
|
||||
/// </summary>
|
||||
public static ServerUtilFactory Factory;
|
||||
|
||||
private static GlobalManager mInstance;
|
||||
|
||||
/// <summary>
|
||||
/// 每个服务器只能管理一个服务,单例模式
|
||||
/// </summary>
|
||||
public static GlobalManager instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mInstance == null)
|
||||
mInstance = Factory.GetGlobalManager();
|
||||
return mInstance;
|
||||
}
|
||||
}
|
||||
|
||||
#region 数据
|
||||
|
||||
/// <summary>
|
||||
/// 是否自杀
|
||||
/// </summary>
|
||||
public bool isKill { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以开战,关闭服务器前先禁止,然后再关闭服务器
|
||||
/// </summary>
|
||||
public bool IsCanWar = true;
|
||||
|
||||
/// <summary>
|
||||
/// 客户端要得到的配置
|
||||
/// </summary>
|
||||
public ConfigHead ClientConfig;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器信息
|
||||
/// </summary>
|
||||
protected ServerInfo m_serverinfo;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器信息
|
||||
/// </summary>
|
||||
public virtual ServerInfo serverinfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_serverinfo == null)
|
||||
m_serverinfo = new ServerInfo();
|
||||
return m_serverinfo;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置头
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ConfigHead GetConfigHead()
|
||||
{
|
||||
ConfigHead cfh = new ConfigHead();
|
||||
cfh.style = 1;
|
||||
cfh.id = ServerConfigManager.Instance.NodeId;
|
||||
cfh.num = ServerConfigManager.Instance.NodeNum;
|
||||
cfh.maxSVer = ServerConfigManager.Instance.MaxVer;
|
||||
cfh.minSVer = ServerConfigManager.Instance.MinVer;
|
||||
cfh.maxCver = ServerConfigManager.Instance.MaxCVer;
|
||||
cfh.minCver = ServerConfigManager.Instance.MinCVer;
|
||||
return cfh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置系统时间间隔
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
[DllImport("winmm")]
|
||||
protected static extern void timeBeginPeriod(int t);
|
||||
|
||||
/// <summary>
|
||||
/// 恢复系统时间间隔
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
[DllImport("winmm")]
|
||||
protected static extern void timeEndPeriod(int t);
|
||||
|
||||
/// <summary>
|
||||
/// 定时器管理
|
||||
/// </summary>
|
||||
private TimerManager timermgr;
|
||||
|
||||
/// <summary>
|
||||
/// 更新服务器信息的时间
|
||||
/// </summary>
|
||||
public int updateServerInfo_time;
|
||||
|
||||
/// <summary>
|
||||
/// 更新服务器信息
|
||||
/// </summary>
|
||||
protected virtual void UpdateServerInfo(bool isStart = false)
|
||||
{
|
||||
timeBeginPeriod(1);
|
||||
|
||||
serverinfo.moduleId = myUtil.id;
|
||||
serverinfo.nodenum = myUtil.nodeNum;
|
||||
if (isStart)
|
||||
serverinfo.startTime = DateTime.Now;
|
||||
|
||||
serverinfo.serverName = ServerName;
|
||||
serverinfo.dopackCnt = 0;
|
||||
serverinfo.minfps = minfps;
|
||||
serverinfo.fps = Fps;
|
||||
serverinfo.maxRuntime = maxruntiming;
|
||||
serverinfo.ConnectCnt = UserSessionsInfo.GetAllSessionCount();
|
||||
serverinfo.BindConnectCnt = UserSessionsInfo.GetBindSessionCount();
|
||||
|
||||
updateServerInfo_time = ServerConfigManager.Instance.UpdateServerInfoTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
protected virtual void Update()
|
||||
{
|
||||
TimeInfo.Instance.Update();
|
||||
// long key = Debug.StartTiming();
|
||||
GameNetDispatcher.Instance.Update();
|
||||
GlobalDispatcher.Instance.Update();
|
||||
GameDispatcher.Instance.Update();
|
||||
|
||||
// double runtime = Debug.GetRunTime(key);
|
||||
// if (runtime > 200)
|
||||
// {
|
||||
// Debug.Error($"Update: 处理慢:{runtime}");
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual bool Init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void DayChange()
|
||||
{
|
||||
GameDispatcher.Instance.Dispatch(GameMsgId.DayChange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// fps计数
|
||||
/// </summary>
|
||||
private int fpscount = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 帧率
|
||||
/// </summary>
|
||||
public int Fps { get; protected set; }
|
||||
|
||||
private int m_minfps = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 最小fps
|
||||
/// </summary>
|
||||
public int minfps
|
||||
{
|
||||
get { return m_minfps; }
|
||||
protected set { m_minfps = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大运行时间
|
||||
/// </summary>
|
||||
public double maxruntiming { get; protected set; }
|
||||
|
||||
private System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
|
||||
|
||||
/// <summary>
|
||||
/// 发送配置包裹
|
||||
/// </summary>
|
||||
protected virtual void SendConfigPack()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理模块死亡信号
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <param name="nodenum"></param>
|
||||
protected void DoModuleDieSign(object param)
|
||||
{
|
||||
if (param is ServerNode serverNode)
|
||||
{
|
||||
Debug.Info("模块死亡包处理!");
|
||||
|
||||
PackHead head = PackHead.Create();
|
||||
head.packlx = ServerPackAgreement.ModuleDie;
|
||||
Message msg = GlobalMQ.CreateMessage(head, serverNode);
|
||||
GlobalMQ.instance.AddMessage(msg);
|
||||
head.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送开启节点包
|
||||
/// </summary>
|
||||
protected virtual void SendOpenNode()
|
||||
{
|
||||
//注册模块
|
||||
PackHead head = PackHead.Create();
|
||||
head.packlx = ServerPackAgreement.openNode;
|
||||
var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;
|
||||
GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, data), true);
|
||||
head.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送关闭节点包
|
||||
/// </summary>
|
||||
protected void SendCloseNode()
|
||||
{
|
||||
PackHead head = PackHead.Create();
|
||||
head.packlx = ServerPackAgreement.closeNode;
|
||||
var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;
|
||||
|
||||
GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, data), true);
|
||||
head.Dispose();
|
||||
}
|
||||
|
||||
//自身主机信息应该是不变的。 暂存这个信息
|
||||
MonitoringAppInfo MonitoringAppInfo =>
|
||||
MonitoringAppInfo.GetCurrentApplicateInfo(this.myUtil.onlyId, this.myUtil.id, this.myUtil.nodeNum);
|
||||
|
||||
/// <summary>
|
||||
/// 退出游戏
|
||||
/// </summary>
|
||||
public virtual void Quit()
|
||||
{
|
||||
state = ServerState.Stoping;
|
||||
}
|
||||
|
||||
#region ITimerProcessor
|
||||
|
||||
/// <summary>
|
||||
/// 100毫秒定时器
|
||||
/// </summary>
|
||||
public virtual void OnTime(int Interval)
|
||||
{
|
||||
//Debug.Log("秒级定时器:" + "," + System.DateTime.Now.Ticks);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 记录天
|
||||
/// </summary>
|
||||
int Day = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 秒级定时器
|
||||
/// </summary>
|
||||
public virtual void SecondTime()
|
||||
{
|
||||
updateServerInfo_time--;
|
||||
|
||||
if (updateServerInfo_time == 0)
|
||||
{
|
||||
UpdateServerInfo();
|
||||
}
|
||||
|
||||
DoFps();
|
||||
|
||||
if (Day != DateTime.Now.Day)
|
||||
{
|
||||
Day = DateTime.Now.Day;
|
||||
DayInit();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 每一天初始化一次
|
||||
/// </summary>
|
||||
public virtual void DayInit()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理Fps的赋值
|
||||
/// </summary>
|
||||
protected virtual void DoFps()
|
||||
{
|
||||
if (minfps < 0 || minfps > fpscount)
|
||||
{
|
||||
minfps = fpscount;
|
||||
//Debug.Warning("fps最低记录:" + minfps);
|
||||
}
|
||||
|
||||
Fps = fpscount;
|
||||
fpscount = 0;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 缓存变化
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
protected virtual void CacheChange(WaitBeMsg msg)
|
||||
{
|
||||
var head = msg.head;
|
||||
if (head.otherString == null || head.otherString.Length == 0)
|
||||
return;
|
||||
Debug.Info("处理缓存更新!" + head.otherString[0]);
|
||||
CaCheManager.instance.UpdateKeyAsync(head.otherString[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理其他
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual bool HandleOtherServerPack(WaitBeMsg msg) => false;
|
||||
|
||||
/// <summary>
|
||||
/// 处理模块死亡信号——意外死亡
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
protected virtual void ModuleDie(WaitBeMsg msg)
|
||||
{
|
||||
var data = JsonPack.GetData<ServerNode>(msg.jsondata);
|
||||
if (data == null)
|
||||
Debug.Error("数据错误!");
|
||||
else
|
||||
Debug.Warning("模块死亡信号:" + data.id + "," + data.nodeNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected virtual void Ping(PackHead head, string jsondata)
|
||||
{
|
||||
ModuleUtile util = JsonPack.GetData<ModuleUtile>(jsondata);
|
||||
if (util == null)
|
||||
Debug.Error("收到网络监测包数据为空!");
|
||||
head.packlx = ServerPackAgreement.Pong;
|
||||
GlobalMQ.instance.DeliveryOne(new ServerNode(util.id, util.nodeNum), GlobalMQ.CreateMessage(head, myUtil),
|
||||
true);
|
||||
|
||||
Debug.Info("发送探测包:" + myUtil.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="jsondata"></param>
|
||||
protected virtual void Pong(PackHead head, string jsondata)
|
||||
{
|
||||
ModuleUtile util = JsonPack.GetData<ModuleUtile>(jsondata);
|
||||
if (util == null)
|
||||
Debug.Error("收到网络探测回包数据为空!");
|
||||
else
|
||||
Debug.Info("Pong : " + util.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 心跳处理包
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
protected virtual void Heart(WaitBeMsg msg)
|
||||
{
|
||||
PackHead head = msg.head;
|
||||
ServerNode node = head.sendutil;
|
||||
if (node == null)
|
||||
{
|
||||
Debug.Error("心跳包错误,没有发送者的描述!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.Equals(myUtil)) //自己的包不处理
|
||||
return;
|
||||
|
||||
//ServerHeart.instanece.DoHeartAsync(node.id, node.nodeNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点开启信号
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
[System.Diagnostics.DebuggerNonUserCode]
|
||||
protected virtual void RecvOpenNode(WaitBeMsg msg)
|
||||
{
|
||||
PackHead head = msg.head;
|
||||
ModuleUtile node = head.sendutil;
|
||||
if (node == null)
|
||||
{
|
||||
Debug.Error("节点开启信号包错误,没有发送者的描述!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.Equals(myUtil))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Debug.Info($"接收到模块开启:{node.ToString()}");
|
||||
|
||||
RountingManager.instance.AddModule(node.id, node.name);
|
||||
|
||||
if (node.id == (int)ModuleType.ConfigModule)
|
||||
{
|
||||
SendConfigPack();
|
||||
}
|
||||
|
||||
if (head.otherString == null || head.otherString.Length == 0 || head.otherString[0] != "ok")
|
||||
{
|
||||
head.packlx = ServerPackAgreement.openNode;
|
||||
head.otherString = new string[] { "ok" };
|
||||
var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;
|
||||
var sendmsg = GlobalMQ.CreateMessage(head, data, null, -1, -1, null, null);
|
||||
GlobalMQ.instance.DeliveryOne(node, sendmsg, true);
|
||||
}
|
||||
|
||||
ServerHeart.instanece.AddModule(node.id, node.name, node.nodeNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点关闭信号_正常关闭
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
protected virtual void RecvCloseNode(WaitBeMsg msg)
|
||||
{
|
||||
ModuleUtile node = msg.head.sendutil;
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
Debug.Error("收到节点关闭信号,没有发送者的描述!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.Equals(myUtil))
|
||||
{
|
||||
//是本模块
|
||||
if (node.onlyId != myUtil.onlyId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == ServerState.Runing)
|
||||
{
|
||||
//检测到已经死了
|
||||
//直接退出
|
||||
Debug.Error("收到死完包!直接退出!");
|
||||
state = ServerState.Error;
|
||||
return;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
//模块死亡信号
|
||||
ServerHeart.instanece.RemoveDie(node.id, node.nodeNum, true);
|
||||
Debug.Warning("收到模块关闭信号:" + node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理命令
|
||||
/// </summary>
|
||||
protected virtual void DoCommand(WaitBeMsg msg)
|
||||
{
|
||||
string[] cmds = msg.head.otherString;
|
||||
if (cmds == null || cmds.Length <= 0)
|
||||
return;
|
||||
|
||||
Debug.Info("收到命令" + cmds[0]);
|
||||
|
||||
switch (cmds[0])
|
||||
{
|
||||
case "exit":
|
||||
Quit();
|
||||
break;
|
||||
case "test":
|
||||
break;
|
||||
case "onlineModules": //在线的所有模块
|
||||
Debug.Log("所有的在线模块");
|
||||
break;
|
||||
|
||||
case "redislocktest":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DistributedLock
|
||||
/// </summary>
|
||||
protected DistributedLock dtl { get; } = new DistributedLock(1000);
|
||||
|
||||
#region IServer
|
||||
|
||||
/// <summary>
|
||||
/// 服务器状态
|
||||
/// </summary>
|
||||
public ServerState state { get; set; } = ServerState.Close;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器名称
|
||||
/// </summary>
|
||||
public string ServerName
|
||||
{
|
||||
get
|
||||
{
|
||||
return ServerConfigManager.Instance.ServerName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 我的模块单元
|
||||
/// </summary>
|
||||
public ModuleUtile myUtil { get; protected set; }
|
||||
|
||||
private ModuleType mMyType;
|
||||
|
||||
/// <summary>
|
||||
/// 模块类型
|
||||
/// </summary>
|
||||
public ModuleType myType
|
||||
{
|
||||
get { return mMyType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息处理器
|
||||
/// </summary>
|
||||
public MessageProcessor msgProcessor;
|
||||
|
||||
/// <summary>
|
||||
/// 其他配置初始化
|
||||
/// </summary>
|
||||
public virtual void OtherConfigInit()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
stringBuilder.Append('0');
|
||||
}
|
||||
|
||||
if (ServerConfigManager.Instance.GameConfig != null)
|
||||
{
|
||||
ServerConfigManager.Instance.GameConfig.GameGz = stringBuilder.ToString();
|
||||
|
||||
if (ServerConfigManager.Instance.TingCnt > 0)
|
||||
{
|
||||
foreach (var ting in ServerConfigManager.Instance.Tings)
|
||||
{
|
||||
ting.TingGz = stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置表是否有问题
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool CheckConfig()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
public bool Start()
|
||||
{
|
||||
//启动中
|
||||
state = ServerState.Starting;
|
||||
|
||||
mMyType = (ModuleType)ServerConfigManager.Instance.NodeId;
|
||||
|
||||
myUtil = new ModuleUtile(ServerConfigManager.Instance.NodeId,
|
||||
ServerConfigManager.Instance.NodeNum,
|
||||
Enum.GetName(myType.GetType(), myType),
|
||||
ServerConfigManager.Instance.MaxVer);
|
||||
|
||||
TimeInfo.Instance.DayChange += DayChange;
|
||||
|
||||
//序列化预热
|
||||
PreLoadMessagePack();
|
||||
|
||||
GlobalDispatcher.Instance.Dispatch(GlobalMsgId.GameNameReadSuccess, ServerConfigManager.Instance.ServerName);
|
||||
Debug.Info($"Start ServerName:{ServerConfigManager.Instance.ServerName}");
|
||||
|
||||
//数据库初始化
|
||||
GameDB.Instance.Init(SqlConfigCategory.Instance.GetDBSqlConfig());
|
||||
|
||||
//redis启动
|
||||
redisManager.Start();
|
||||
|
||||
ClientConfig = GetConfigHead();
|
||||
|
||||
//存储自己的模块信息
|
||||
if (!redisManager.db.HashExists(RedisDictionary.moduleNames, ServerConfigManager.Instance.NodeId.ToString()))
|
||||
redisManager.db.HashSet(RedisDictionary.moduleNames, ServerConfigManager.Instance.NodeId, myUtil.name);
|
||||
|
||||
//心跳开始,并检查模块是否在线
|
||||
if (!ServerHeart.instanece.Start(myType, ServerConfigManager.Instance.NodeNum))
|
||||
{
|
||||
Debug.ImportantLog("启动失败,模块在线!");
|
||||
return false;
|
||||
}
|
||||
|
||||
MessagePool.tag = "" + myUtil.id + "-" + myUtil.nodeNum + "-" + myUtil.ver + "-" + myUtil.name;
|
||||
|
||||
//模块死亡事件监听
|
||||
GlobalDispatcher.Instance.AddListener(GlobalMsgId.ModuleNodeDie, DoModuleDieSign);
|
||||
|
||||
//创建消息处理
|
||||
Factory.CreateGlobalMQFactory().CreateGlobalMQ();
|
||||
|
||||
//启动rabbit
|
||||
if (!GlobalMQ.instance.StartModule(RabbitConfigCategory.Instance.GetRabbitMQConfig(), myUtil))
|
||||
{
|
||||
Debug.Error("启动失败:A71134F4-EA97-44C0-A305-E35966622FEB");
|
||||
return false;
|
||||
}
|
||||
|
||||
msgProcessor = Factory.CreateMessageProcessor();
|
||||
|
||||
new UserSessionsManager().Register();
|
||||
//重要数据启动
|
||||
if (!Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.ImportantLog("init over!!!");
|
||||
//发送开启信号
|
||||
SendOpenNode();
|
||||
|
||||
//定时器管理
|
||||
timermgr = new TimerManager(ServerConfigManager.Instance.OnTime);
|
||||
timermgr.Start();
|
||||
|
||||
//更改状态为运行中
|
||||
state = ServerState.Runing;
|
||||
|
||||
//更新服务器信息
|
||||
UpdateServerInfo(true);
|
||||
|
||||
//开始发送心跳包
|
||||
ServerHeart.instanece.BeginHeart(Factory.CreateHeartPack(myUtil));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private StringBuilder logs = new StringBuilder();
|
||||
|
||||
private int GcCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 预热 MessagePack
|
||||
/// </summary>
|
||||
protected virtual void PreLoadMessagePack()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void ReLoadTable()
|
||||
{
|
||||
TableManager.Instance.ReLoadTableData();
|
||||
|
||||
try
|
||||
{
|
||||
ReLoadTableInit();
|
||||
Debug.ImportantLog("配置重新加载成功!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("重载配置出错!" + e.Message);
|
||||
TableManager.Instance.RollBack();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ReLoadTableInit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主线程
|
||||
/// </summary>
|
||||
public void Loop()
|
||||
{
|
||||
if (state == ServerState.Runing)
|
||||
{
|
||||
try
|
||||
{
|
||||
logs.Clear();
|
||||
watch.Restart();
|
||||
//watch.Restart();
|
||||
|
||||
if (IsReloadTable)
|
||||
{
|
||||
IsReloadTable = false;
|
||||
ReLoadTable();
|
||||
}
|
||||
|
||||
if (timermgr.GetMillScoend())
|
||||
{
|
||||
#if DEBUG
|
||||
var key = Debug.StartTiming();
|
||||
logs.AppendLine($"GlobalManager Loop DoTime begin");
|
||||
#endif
|
||||
OnTime(timermgr.Interval);
|
||||
#if DEBUG
|
||||
logs.AppendLine($"GlobalManager Loop DoTime end, time: {Debug.GetRunTime(key)}");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (timermgr.GetSecoend())
|
||||
{
|
||||
#if DEBUG
|
||||
var key = Debug.StartTiming();
|
||||
logs.AppendLine($"GlobalManager Loop DoTimeSecond begin");
|
||||
#endif
|
||||
SecondTime();
|
||||
#if DEBUG
|
||||
logs.AppendLine($"GlobalManager Loop DoTimeSecond end, time: {Debug.GetRunTime(key)}");
|
||||
#endif
|
||||
}
|
||||
|
||||
//消息处理
|
||||
msgProcessor.Run(logs);
|
||||
|
||||
#if DEBUG
|
||||
var updateKey = Debug.StartTiming();
|
||||
#endif
|
||||
fpscount++;
|
||||
Update();
|
||||
#if DEBUG
|
||||
logs.AppendLine($"Update Loop time:{Debug.GetRunTime(updateKey)}");
|
||||
#endif
|
||||
watch.Stop();
|
||||
double runtime = watch.ElapsedMilliseconds; //.ElapsedMilliseconds;
|
||||
|
||||
if (runtime >= 100)
|
||||
{
|
||||
logs.AppendLine(
|
||||
$"GlobalManager Loop end, now: {DateTime.Now}, runtime: {runtime} / {watch.Elapsed.TotalMilliseconds}");
|
||||
|
||||
Debug.Error($"Loop runtime warning: " + logs.ToString());
|
||||
}
|
||||
|
||||
if (runtime > maxruntiming)
|
||||
maxruntiming = runtime;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("主线程错误:" + e.ToString());
|
||||
}
|
||||
}
|
||||
else if (state == ServerState.Stoping)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞检查,直到正常退出
|
||||
/// </summary>
|
||||
public virtual void Close()
|
||||
{
|
||||
UUIDManager.Instance.Close();
|
||||
UserSessionsManager.Instance.Dispose();
|
||||
timermgr.Stop();
|
||||
|
||||
SendCloseNode();
|
||||
ServerHeart.instanece.Close();
|
||||
//ServerManager.instance.Close();
|
||||
if (GlobalMQ.instance != null)
|
||||
GlobalMQ.instance.Close();
|
||||
|
||||
//保存道具日志
|
||||
PropManager.Instance.Dispose();
|
||||
state = ServerState.Stop;
|
||||
|
||||
Debug.Log("模块正常退出!");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 收到获取在线人数的请求
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
protected virtual void ReportPlayerOnLineData(WaitBeMsg msg)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
57
GlobalSever/GlobalManager/IServer.cs
Normal file
57
GlobalSever/GlobalManager/IServer.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using Server.Data.Module;
|
||||
using GameData;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务管理
|
||||
/// </summary>
|
||||
public interface IServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器状态
|
||||
/// </summary>
|
||||
ServerState state {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器名称
|
||||
/// </summary>
|
||||
string ServerName {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模块单元
|
||||
/// </summary>
|
||||
ModuleUtile myUtil {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模块类型
|
||||
/// </summary>
|
||||
ModuleType myType {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器启动
|
||||
/// </summary>
|
||||
bool Start();
|
||||
|
||||
/// <summary>
|
||||
/// 主进程
|
||||
/// </summary>
|
||||
void Loop();
|
||||
|
||||
/// <summary>
|
||||
/// 服务器关闭
|
||||
/// </summary>
|
||||
void Close();
|
||||
|
||||
}
|
||||
}
|
||||
27
GlobalSever/GlobalManager/ITimerProcessor.cs
Normal file
27
GlobalSever/GlobalManager/ITimerProcessor.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 定时器处理者
|
||||
/// </summary>
|
||||
public interface ITimerProcessor
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 定时器
|
||||
/// </summary>
|
||||
/// <param name="Interval">定时器时间间隔 单位毫秒</param>
|
||||
void OnTime(int Interval);
|
||||
|
||||
/// <summary>
|
||||
/// 秒级定时器
|
||||
/// </summary>
|
||||
void SecondTime();
|
||||
|
||||
}
|
||||
}
|
||||
96
GlobalSever/GlobalManager/JsonExtensions.cs
Normal file
96
GlobalSever/GlobalManager/JsonExtensions.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// JsonExtensions
|
||||
/// </summary>
|
||||
public static class JsonExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// TryGetValue
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="jobj"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="valueIfnotexist"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetValueOrDefault<T>(this JObject jobj, string propertyName, T valueIfnotexist = default(T)) {
|
||||
if (jobj.TryGetValue(propertyName, out var value)) {
|
||||
return value.ToObject<T>();
|
||||
}
|
||||
return valueIfnotexist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TryGetValue
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="jobj"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="tokenType"></param>
|
||||
/// <param name="valueIfnotexist"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetValueOrDefault<T>(this JObject jobj, string propertyName, JTokenType tokenType, T valueIfnotexist = default(T)) {
|
||||
if (jobj.TryGetValue(propertyName, out var value) && value.Type == tokenType) {
|
||||
return value.ToObject<T>();
|
||||
}
|
||||
return valueIfnotexist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TryGetValue
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="jobj"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="tokenType"></param>
|
||||
/// <param name="outValue"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetValue<T>(this JObject jobj, string propertyName, JTokenType tokenType, out T outValue) {
|
||||
outValue = default(T);
|
||||
if (jobj.TryGetValue(propertyName, out var value) && value.Type == tokenType) {
|
||||
outValue = value.ToObject<T>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <returns></returns>
|
||||
public static JToken ToJson(this object instance) => JToken.FromObject(instance);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToJsonString(this object instance) => JToken.FromObject(instance).ToString(Formatting.None);
|
||||
|
||||
/// <summary>
|
||||
/// parse json string then Deserialze to object
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static T ParseJsonToObject<T>(this string str) => JToken.Parse(str).ToObject<T>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <returns></returns>
|
||||
public static JObject ToJObject(this object instance) => JObject.FromObject(instance);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instances"></param>
|
||||
/// <returns></returns>
|
||||
public static JArray ToJArray(this IEnumerable instances) => JArray.FromObject(instances);
|
||||
}
|
||||
93
GlobalSever/GlobalManager/MainActor.cs
Normal file
93
GlobalSever/GlobalManager/MainActor.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ActorCore;
|
||||
using NetWorkMessage;
|
||||
using Server.Net;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class MainActor : Actor
|
||||
{
|
||||
public override SchedulerType SchedulerType => SchedulerType.Main;
|
||||
|
||||
public override MailBoxType MailBoxType => MailBoxType.UnOrderedMessage;
|
||||
|
||||
public static ActorId MainActorId
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
protected virtual bool IsOrderMessage => true;
|
||||
|
||||
public MainActor(byte moduleId, byte nodeNum) : base(moduleId, nodeNum, ActorTypeId.Main)
|
||||
{
|
||||
MainActorId = new ActorId(moduleId, nodeNum, ActorTypeId.Main);
|
||||
}
|
||||
|
||||
public override void RegisterHandle()
|
||||
{
|
||||
this.RegisterMessageHandle(typeof(ClientMessage),OuterMessageHandle);
|
||||
this.RegisterMessageHandle(typeof(UserPropChangeMessage),OnUserPropChangeMessage);
|
||||
this.RegisterMessageHandle(typeof(UserCurrencyChangeMessage),OnUserCurrencyChangeMessage);
|
||||
this.RegisterRPCHandle(typeof(RpcTestRequest),OnRpcTestRequest);
|
||||
MessageDispatcher.Instance.Start(IsOrderMessage,CoroutineLockManager);
|
||||
}
|
||||
|
||||
private Task OuterMessageHandle(ActorId fromActorId,IMessage message)
|
||||
{
|
||||
if (message is ClientMessage clientMessage)
|
||||
{
|
||||
GameMessageDispatcher.Instance.Dispatch(clientMessage.OpCode, clientMessage);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task OnUserPropChangeMessage(ActorId fromActorId,IMessage message)
|
||||
{
|
||||
if (message is UserPropChangeMessage userPropChangeMessage)
|
||||
{
|
||||
GameDispatcher.Instance.Dispatch(GameMsgId.UserPropChange,userPropChangeMessage);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task OnUserCurrencyChangeMessage(ActorId formActorId, IMessage message)
|
||||
{
|
||||
if (message is UserCurrencyChangeMessage userCurrencyChangeMessage)
|
||||
{
|
||||
GameDispatcher.Instance.Dispatch(GameMsgId.UserCurrencyChange,userCurrencyChangeMessage);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task OnRpcTestRequest(ActorId fromActorId,IRequest request,IResponse response)
|
||||
{
|
||||
if (request is RpcTestRequest rpcTestRequest && response is RpcTestResponse rpcTestResponse)
|
||||
{
|
||||
rpcTestResponse.Id = rpcTestRequest.Id;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (UserSessionManager.Instance != null)
|
||||
{
|
||||
UserSessionManager.Instance.Update();
|
||||
}
|
||||
|
||||
//处理客户端消息
|
||||
MessageDispatcher.Instance.Handle();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
226
GlobalSever/GlobalManager/MessageProcessor.cs
Normal file
226
GlobalSever/GlobalManager/MessageProcessor.cs
Normal file
@ -0,0 +1,226 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Server.MQ;
|
||||
using MrWu.Debug;
|
||||
using Server.Pack;
|
||||
using Server.Data.Module;
|
||||
using GameData;
|
||||
using Server.Config;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public partial class GlobalManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息处理器
|
||||
/// </summary>
|
||||
public class MessageProcessor
|
||||
{
|
||||
private GlobalManager instance
|
||||
{
|
||||
get { return GlobalManager.instance; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理包的数量
|
||||
/// </summary>
|
||||
public long dopackCnt { get; protected set; }
|
||||
|
||||
private long DopackRunKey = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 消息处理
|
||||
/// </summary>
|
||||
public void Run(StringBuilder logs)
|
||||
{
|
||||
int cnt = GlobalMQ.instance.GteMessageCnt();
|
||||
int dealCnt = 0;
|
||||
while (dealCnt < cnt)
|
||||
{
|
||||
if (dealCnt > 500)
|
||||
{
|
||||
Debug.Error("处理的包太多");
|
||||
break;
|
||||
}
|
||||
|
||||
dealCnt++;
|
||||
var msg = GlobalMQ.instance.GetMessage();
|
||||
if (msg == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (TestValue.IsPrintLog)
|
||||
{
|
||||
DopackRunKey = Debug.StartTiming();
|
||||
}
|
||||
DoMessage(msg, logs);
|
||||
if (!msg.isAdd && msg.AutoAck) //不循环处理 并且不是梳理完自动确认
|
||||
WaitBeMsgPool.PutWaiteBeMsg(ref msg);
|
||||
|
||||
if (DopackRunKey > 0)
|
||||
{
|
||||
double runtime = Debug.GetRunTime(DopackRunKey);
|
||||
DopackRunKey = 0;
|
||||
if (runtime > 1000)
|
||||
{
|
||||
Debug.ImportantLog($"DoMessage 慢:{runtime}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 处理包
|
||||
/// </summary>
|
||||
protected void DoMessage(WaitBeMsg wbm, StringBuilder logStringBuilder)
|
||||
{
|
||||
dopackCnt++;
|
||||
|
||||
#if DEBUG
|
||||
var key = Debug.StartTiming();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
wbm.isAdd = false;
|
||||
if (wbm.head.packlx < 0)
|
||||
{
|
||||
#if DEBUG
|
||||
logStringBuilder.AppendLine($"DoPackBase begin, packlx: {wbm.head.packlx}");
|
||||
#endif
|
||||
DoPackBase(wbm, logStringBuilder);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
logStringBuilder.AppendLine($"DoPack begin, packlx: {wbm.head.packlx}");
|
||||
#endif
|
||||
DoPack(wbm, logStringBuilder);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
logStringBuilder.AppendLine($"DoMessage Exception: {e}");
|
||||
#endif
|
||||
Debug.Error("处理吧包发生错误!" + e.ToString());
|
||||
wbm.Ack();
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
logStringBuilder.AppendLine($"finally, time: {Debug.GetRunTime(key)}");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (wbm.isAdd)
|
||||
GlobalMQ.instance.AddMessage(wbm);
|
||||
else
|
||||
{
|
||||
if (wbm.AutoAck && !wbm.noAck && !wbm.isAck && wbm.deliveryTag > 0)
|
||||
wbm.Ack();
|
||||
}
|
||||
//Debug.Info("直到处理用的时间:" + (DateTime.Now - wbm.logTime).TotalMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器基本消息_分发处理
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="logStringBuilder"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual bool DoPackBase(WaitBeMsg msg, StringBuilder logStringBuilder)
|
||||
{
|
||||
switch (msg.head.packlx)
|
||||
{
|
||||
case ServerPackAgreement.command:
|
||||
instance.DoCommand(msg);
|
||||
break;
|
||||
case ServerPackAgreement.nodeHeart: //节点心跳
|
||||
instance.Heart(msg);
|
||||
break;
|
||||
case ServerPackAgreement.openNode: //节点开启
|
||||
instance.RecvOpenNode(msg);
|
||||
break;
|
||||
case ServerPackAgreement.closeNode: //节点正常关闭
|
||||
instance.RecvCloseNode(msg);
|
||||
break;
|
||||
|
||||
case ServerPackAgreement.KillMe: //关闭自身 -只能发一个包
|
||||
instance.isKill = true;
|
||||
break;
|
||||
case ServerPackAgreement.NoStartWar: //禁止开战
|
||||
Debug.Info("接收到禁止开战包!");
|
||||
instance.IsCanWar = false;
|
||||
break;
|
||||
case ServerPackAgreement.CacheChange:
|
||||
Debug.Info("接收到缓存变化包!");
|
||||
instance.CacheChange(msg);
|
||||
break;
|
||||
|
||||
case ServerPackAgreement.Ping:
|
||||
instance.Ping(msg.head, msg.jsondata);
|
||||
break;
|
||||
|
||||
case ServerPackAgreement.Pong:
|
||||
instance.Pong(msg.head, msg.jsondata);
|
||||
break;
|
||||
case ServerPackAgreement.ModuleDie: //模块检测死亡包
|
||||
instance.ModuleDie(msg);
|
||||
break;
|
||||
|
||||
case ServerPackAgreement.PackTest: //包测试
|
||||
break;
|
||||
|
||||
case ServerPackAgreement.ReportPlayerOnLineDataReq:
|
||||
instance.ReportPlayerOnLineData(msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
return instance.HandleOtherServerPack(msg); // false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理模块包裹
|
||||
/// </summary>
|
||||
/// <param name="msg">路由</param>
|
||||
/// <param name="logStringBuilder"></param>
|
||||
protected virtual void DoPack(WaitBeMsg msg, StringBuilder logStringBuilder)
|
||||
{
|
||||
if (!CheckClientVer(msg.head))
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查客户端版本
|
||||
/// </summary>
|
||||
/// <param name="head"></param>
|
||||
protected virtual bool CheckClientVer(PackHead head)
|
||||
{
|
||||
if (head.packlx != GamePackAgreement.TransFerHttp &&
|
||||
head.packlx != GamePackAgreement.TransFerPack &&
|
||||
head.clientVer < ServerConfigManager.Instance.MinCVer)
|
||||
{
|
||||
head.transfer = GamePackAgreement.MandatoryUpdate;
|
||||
var md = head.Util;
|
||||
if (md == null)
|
||||
return true;
|
||||
|
||||
if (md.id == (int)ModuleType.HttpModule)
|
||||
head.packlx = ServerPackAgreement.TransFerHttp;
|
||||
else
|
||||
head.packlx = ServerPackAgreement.TransFerPack;
|
||||
GlobalMQ.instance.DeliveryOne(md, GlobalMQ.CreateMessage(head), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
148
GlobalSever/GlobalManager/MonitoringAppInfo.cs
Normal file
148
GlobalSever/GlobalManager/MonitoringAppInfo.cs
Normal file
@ -0,0 +1,148 @@
|
||||
/********************************
|
||||
*
|
||||
* 作者:徐贞卫
|
||||
* 创建时间: 2019-10-16 13:38:05
|
||||
*
|
||||
********************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Server {
|
||||
/// <summary>
|
||||
/// 监控服务应用信息
|
||||
/// </summary>
|
||||
public class MonitoringAppInfo : IEquatable<MonitoringAppInfo> {
|
||||
|
||||
static DateTime unixbase { get; } = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||
|
||||
/// <summary>
|
||||
/// 网卡硬件地址
|
||||
/// </summary>
|
||||
public string[] MacAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 系统已启动时间(单位:秒)
|
||||
/// </summary>
|
||||
public int SysStartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 进程PID
|
||||
/// </summary>
|
||||
public int Pid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务应用完整路径
|
||||
/// </summary>
|
||||
public string FullFileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模块ID标识符
|
||||
/// </summary>
|
||||
public string UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模块ID
|
||||
/// </summary>
|
||||
public int ModuleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 节点编号
|
||||
/// </summary>
|
||||
public int NodeNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// GetListViewItem
|
||||
/// </summary>
|
||||
/// <returns>GetListViewItem</returns>
|
||||
public System.Windows.Forms.ListViewItem GetListViewItem() {
|
||||
if(viewItem == null) {
|
||||
viewItem = new System.Windows.Forms.ListViewItem(
|
||||
new string[] { ModuleId.ToString(), NodeNumber.ToString(), UniqueId, FullFileName }) { Tag = this };
|
||||
}
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
private System.Windows.Forms.ListViewItem viewItem;
|
||||
|
||||
/// <summary>
|
||||
/// 当前应用信息
|
||||
/// </summary>
|
||||
/// <param name="uniqueId">模块ID标识符</param>
|
||||
/// <param name="moduleId">模块ID</param>
|
||||
/// <param name="nodeNumber">节点编号</param>
|
||||
/// <returns>当前进程的应用信息</returns>
|
||||
public static MonitoringAppInfo GetCurrentApplicateInfo(string uniqueId, int moduleId, int nodeNumber) {
|
||||
|
||||
//时间戳
|
||||
var now = (int)DateTime.Now.Subtract(unixbase).TotalSeconds;
|
||||
|
||||
//获取当前进程
|
||||
var process = Process.GetCurrentProcess();
|
||||
var mainModule = process.MainModule;
|
||||
|
||||
var macAddress = GetNetcardMacaddress();
|
||||
var sysStartTime = now - (Environment.TickCount / 1000);
|
||||
var pId = process.Id;
|
||||
var fullFileName = mainModule.FileName;
|
||||
|
||||
return new MonitoringAppInfo {
|
||||
MacAddress = macAddress,
|
||||
SysStartTime = sysStartTime,
|
||||
Pid = pId,
|
||||
FullFileName = fullFileName,
|
||||
UniqueId = uniqueId,
|
||||
ModuleId = moduleId,
|
||||
NodeNumber = nodeNumber
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本机所有工作的以太网卡物理地址
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string[] GetNetcardMacaddress() {
|
||||
if (MacAddresss == null) {
|
||||
var networkAdapters = NetworkInterface.GetAllNetworkInterfaces().Where(p => p.NetworkInterfaceType == NetworkInterfaceType.Ethernet && p.OperationalStatus == OperationalStatus.Up);
|
||||
MacAddresss = networkAdapters.Select(p => p.GetPhysicalAddress()).Select(p => p.ToString()).ToArray();
|
||||
}
|
||||
return MacAddresss;
|
||||
}
|
||||
|
||||
static string[] MacAddresss = null;
|
||||
|
||||
/// <summary>
|
||||
/// 指示当前对象是否等于同一类型的另一个对象
|
||||
/// </summary>
|
||||
/// <param name="other">一个与此对象进行比较的对象。</param>
|
||||
/// <returns>如果当前对象等于 other 参数,则为 true;否则为 false。</returns>
|
||||
public bool Equals(MonitoringAppInfo other) {
|
||||
if(other == null) {
|
||||
return false;
|
||||
}
|
||||
if(Pid != other.Pid) {
|
||||
return false;
|
||||
}
|
||||
if(ModuleId != other.ModuleId) {
|
||||
return false;
|
||||
}
|
||||
if(NodeNumber != other.NodeNumber) {
|
||||
return false;
|
||||
}
|
||||
if(!string.Equals(FullFileName, other.FullFileName, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToString
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString() {
|
||||
return $"模块ID:{ModuleId}, 节点ID:{NodeNumber},路径:{FullFileName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
163
GlobalSever/GlobalManager/SendManager.cs
Normal file
163
GlobalSever/GlobalManager/SendManager.cs
Normal file
@ -0,0 +1,163 @@
|
||||
using GameData;
|
||||
using Server.MQ;
|
||||
using MrWu.Debug;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 发包管理
|
||||
/// </summary>
|
||||
public static class SendManager {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 0.不启用
|
||||
/// 1.服务器维护中,请稍后再试!
|
||||
/// 2.请求超时!请稍后再试!
|
||||
/// 3.服务器爆满!请稍后再试!
|
||||
/// 4.房间号错误,无此房间!
|
||||
/// 5.进入失败!密码错误!
|
||||
/// 6.房间已开战,进入失败!
|
||||
/// 7.房间已满员,进入失败!
|
||||
/// 8.检测到相同ip账号,进入失败!
|
||||
/// 9.未获取到您的ip,进入失败!
|
||||
/// 10.进入失败,必须微信登录或者微信绑定才能进入此房间!
|
||||
/// 11.进入失败,必须是微信绑定的账号才能进入此房间!
|
||||
/// 12.房卡不足创建失败!
|
||||
/// 13.数据错误,请重新登录!
|
||||
/// 14.登录过期,请重新登录!
|
||||
/// 15.用户名或密码为空
|
||||
/// 16.用户名或密码错误
|
||||
/// 17.对方不在线
|
||||
/// 18.您在朋友房中,不能重复创建!
|
||||
/// 19.您已经在朋友房中了!
|
||||
/// 20.朋友房规则错误!
|
||||
/// 21.房卡不足创建失败!
|
||||
/// 22.竞技比赛名称必须是3-8个字符串组成!
|
||||
/// 23.竞技比赛名称非法!
|
||||
/// 24.创建失败!请稍后再试!
|
||||
/// 25.创建的竞技比赛已达上限!
|
||||
/// 26.竞技比赛公告过长!
|
||||
/// 27.竞技比赛公告包含特殊字符!
|
||||
/// 28.竞技比赛名称已被使用!
|
||||
/// 29.数据错误!
|
||||
/// 30.您不在此竞技比赛!
|
||||
/// 31.您的权限不足!
|
||||
/// 32.修改失败,公告过长或有特殊字符!
|
||||
/// 33.房卡不足,创建失败!
|
||||
/// 34.充值失败!
|
||||
/// 35.由于管理员设置,您无法加入该游戏!
|
||||
/// 36.房卡不足加入失败!
|
||||
/// 37.未知错误,服务器报错!!!
|
||||
/// 38.竞技比赛房间,无法手动加入!",
|
||||
/// 39.操作失败,您在游戏中无法进行仓库操作!,
|
||||
/// 40.仓库密码错误
|
||||
/// 41.您在游戏中无法进行存取金币操作
|
||||
/// 42.金币操作数额过大。
|
||||
/// 43.您身上的金币不足,取出失败
|
||||
/// 44.您身上的游戏币超过限额,无法取出!
|
||||
/// 45.您身上的游戏币不足,存入失败
|
||||
/// 46.您的金币不足,赠送失败!
|
||||
/// 47.操作失败,请稍后重新发起!
|
||||
/// 48.赠送的金币必须大于1!
|
||||
/// 49.金币不足,购买失败!
|
||||
/// 50.操作失败,请稍后再试!
|
||||
/// 51.卖出失败!
|
||||
/// 52.不能卖出身上的物品!
|
||||
/// 53.保存失败!
|
||||
/// 54.玩法已被修改或者删除!
|
||||
/// 55.防作弊检查,进入房间失败!
|
||||
/// 56.创建失败,未检测到ip地址!
|
||||
/// 57.暂时微信用户才可创建房间,绑定后再试!
|
||||
/// 58.防作弊房间需开启定位才可创建!
|
||||
/// 59.未获取到设备信息,请稍后再试!
|
||||
/// 60.超时未准备,您已被踢出房间!
|
||||
/// 61.您在别处登录游戏!
|
||||
/// 62.等级不满6级不能使用该功能!
|
||||
/// 63.密码修改失败!
|
||||
/// 64.旧密码错误!
|
||||
/// 65.验证码不正确!
|
||||
/// 66.参数不正确,必须包含联系方式、登录名、登录密码及预留的联系信息!
|
||||
/// 67.新密码格式不对!
|
||||
/// 68.房卡不足,充值失败!
|
||||
/// 69.没有这个玩家,赠送失败!
|
||||
/// 70."没有这个用户,请检查手机号是否输入正确!"
|
||||
/// 71."没有这个用户,请检查用户名是否正确!",
|
||||
/// 72."该用户未绑定手机,请联系客服修改密码!"
|
||||
/// 73."加入失败!"
|
||||
/// 74."不存在这个房间!"
|
||||
/// 75."解散成功!"
|
||||
/// 76."已存在相同名称的战队!"
|
||||
/// 77."金币不足,创建战队失败!"
|
||||
/// 78.""不存在该战队!"
|
||||
/// 79."超时未准备,您已被踢出房间!"
|
||||
/// </summary>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="style"></param>
|
||||
/// <param name="tiptext"></param>
|
||||
public static void SendErrotInfo_Http(PackHead head, int style, int tiptext) {
|
||||
head.transfer = GamePackAgreement.pack_error;
|
||||
head.packlx = GamePackAgreement.TransFerHttp;
|
||||
|
||||
TipInfo errPack = new TipInfo(style, tiptext);
|
||||
ServerNode node = head.Util;
|
||||
GlobalMQ.instance.DeliveryOne(node, GlobalMQ.CreateMessage(head, errPack), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送游戏币超上限提示
|
||||
/// </summary>
|
||||
/// <param name="userid"></param>
|
||||
/// <param name="node"></param>
|
||||
public static void SendMoneyUpper(int userid, ServerNode node) {
|
||||
PackHead head = new PackHead();
|
||||
head.userid = userid;
|
||||
head.packlx = GamePackAgreement.TransFerPack;
|
||||
head.transfer = GamePackAgreement.MoneyUpper;
|
||||
|
||||
GlobalMQ.instance.DeliveryOne(node, GlobalMQ.CreateMessage(head), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送自定义错误提示信息
|
||||
/// </summary>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="style"></param>
|
||||
/// <param name="tiptext"></param>
|
||||
public static void SendErrotInfo_Http(PackHead head, int style, string tiptext) {
|
||||
head.transfer = GamePackAgreement.autoTipInfo;
|
||||
head.packlx = GamePackAgreement.TransFerHttp;
|
||||
|
||||
head.otherString = new string[] { tiptext };
|
||||
|
||||
ServerNode node = head.Util;
|
||||
|
||||
GlobalMQ.instance.DeliveryOne(node, GlobalMQ.CreateMessage(head, null), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个在游戏中的包给客服端
|
||||
/// </summary>
|
||||
/// <param name="userid">userid</param>
|
||||
/// <param name="game_serid">游戏服务器id</param>
|
||||
/// <param name="clickgame_serid">点击的游戏服务器id</param>
|
||||
/// <param name="friendRoom">朋友房房号</param>
|
||||
/// <param name="style">类型 1.提示进入 2.让客户端立即进入</param>
|
||||
/// <param name="head">SocketNode Socket节点</param>
|
||||
public static void SendInGameInfo_Http(int userid, int game_serid, int clickgame_serid, int friendRoom, int style, PackHead head) {
|
||||
if (head == null) {
|
||||
Debug.Warning("SendInGameInfo_Http params error head is null");
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerGameInfo pgi = new PlayerGameInfo(game_serid, friendRoom,style, clickgame_serid);
|
||||
head.packlx = GamePackAgreement.TransFerHttp;
|
||||
head.transfer = GamePackAgreement.InGameInfo;
|
||||
head.userid = userid;
|
||||
|
||||
GlobalMQ.instance.DeliveryOne(head.Util, GlobalMQ.CreateMessage(head, pgi), true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
45
GlobalSever/GlobalManager/ServerState.cs
Normal file
45
GlobalSever/GlobalManager/ServerState.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 服务器状态
|
||||
/// </summary>
|
||||
public enum ServerState
|
||||
{
|
||||
/// <summary>
|
||||
/// 关闭状态
|
||||
/// </summary>
|
||||
Close = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 启动中
|
||||
/// </summary>
|
||||
Starting = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 运行中
|
||||
/// </summary>
|
||||
Runing = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 停止中
|
||||
/// </summary>
|
||||
Stoping = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
Stop = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 服务器意外终止
|
||||
/// </summary>
|
||||
Error = 5
|
||||
}
|
||||
}
|
||||
65
GlobalSever/GlobalManager/ServerUtilFactory.cs
Normal file
65
GlobalSever/GlobalManager/ServerUtilFactory.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using Server.MQ;
|
||||
using Server.Module;
|
||||
using Server.Data;
|
||||
using Server.Pack;
|
||||
using Server.Data.Module;
|
||||
using GameData;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务单元工厂
|
||||
/// </summary>
|
||||
public abstract class ServerUtilFactory
|
||||
{
|
||||
private IGlobalFactory GlobalMQFactory;
|
||||
|
||||
/// <summary>
|
||||
/// 创建消息管理
|
||||
/// </summary>
|
||||
public virtual IGlobalFactory CreateGlobalMQFactory() {
|
||||
if (GlobalMQFactory == null)
|
||||
GlobalMQFactory = new GlobalMQ.Factory();
|
||||
return GlobalMQFactory;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract GlobalManager GetGlobalManager();
|
||||
|
||||
/// <summary>
|
||||
/// 创建一些信息使用
|
||||
/// </summary>
|
||||
/// <param name="ObjectName"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Object Produce(string ObjectName);
|
||||
|
||||
/// <summary>
|
||||
/// 创建心跳包
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string CreateHeartPack(ModuleUtile util) {
|
||||
PackHead head = PackHead.Create();
|
||||
head.sendutil = util;
|
||||
head.packlx = ServerPackAgreement.nodeHeart;
|
||||
string result = JsonPack.GetJsonByPack(head, null);
|
||||
head.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建消息处理器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual GlobalManager.MessageProcessor CreateMessageProcessor() {
|
||||
return new GlobalManager.MessageProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
129
GlobalSever/GlobalManager/TimerManager.cs
Normal file
129
GlobalSever/GlobalManager/TimerManager.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MrWu.Debug;
|
||||
using System.Threading;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 定时器标记管理
|
||||
/// </summary>
|
||||
public class TimerManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否触发定时器事件
|
||||
/// </summary>
|
||||
private volatile bool isTimerMillEvt;
|
||||
/// <summary>
|
||||
/// 秒级定时器
|
||||
/// </summary>
|
||||
private volatile bool isSecondTimeEvt;
|
||||
|
||||
private volatile int mInterval;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在运行中
|
||||
/// </summary>
|
||||
public bool isRun {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发定时器的时间间隔
|
||||
/// </summary>
|
||||
public int Interval {
|
||||
get {
|
||||
return mInterval;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置定时器的时间间隔
|
||||
/// </summary>
|
||||
/// <param name="Interval"></param>
|
||||
public void SetInterval(int Interval) {
|
||||
if (Interval < 1) {
|
||||
Debug.Error("不能设置这么小的事件间隔:" + Interval);
|
||||
return;
|
||||
}
|
||||
|
||||
mInterval = Interval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造
|
||||
/// </summary>
|
||||
/// <param name="Interval">定时器的时间间隔</param>
|
||||
public TimerManager(int Interval) {
|
||||
if (Interval < 1)
|
||||
throw new ArgumentOutOfRangeException("Interval 必须为大于 1 的值!");
|
||||
|
||||
this.mInterval = Interval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 秒级定时器
|
||||
/// </summary>
|
||||
private Timer SecondTimer;
|
||||
|
||||
/// <summary>
|
||||
/// 毫秒级定时器
|
||||
/// </summary>
|
||||
private Timer MillTimer;
|
||||
|
||||
/// <summary>
|
||||
/// 开始定时器的触发
|
||||
/// </summary>
|
||||
public void Start() {
|
||||
if (SecondTimer == null) {
|
||||
SecondTimer = new Timer(SecoendTime, null, 0, 1000);
|
||||
MillTimer = new Timer(MillTime, null, 0, Interval);
|
||||
} else {
|
||||
SecondTimer.Change(0, 1000);
|
||||
MillTimer.Change(0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止定时器的触发
|
||||
/// </summary>
|
||||
public void Stop() {
|
||||
SecondTimer.Change(-1, 1000);
|
||||
MillTimer.Change(-1, Interval);
|
||||
}
|
||||
|
||||
private void SecoendTime(object state) {
|
||||
isSecondTimeEvt = true;
|
||||
}
|
||||
|
||||
private void MillTime(object state) {
|
||||
isTimerMillEvt = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否需要定时器触发
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool GetSecoend() {
|
||||
if (isSecondTimeEvt) {
|
||||
isSecondTimeEvt = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否需要触发毫秒定时器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool GetMillScoend() {
|
||||
if (isTimerMillEvt) {
|
||||
isTimerMillEvt = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
282
GlobalSever/GlobalManager/WayManager.cs
Normal file
282
GlobalSever/GlobalManager/WayManager.cs
Normal file
@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.DB.Redis;
|
||||
using GameData;
|
||||
using MrWu.Debug;
|
||||
using StackExchange.Redis;
|
||||
using Server.Data.ClubDef;
|
||||
using GameDAL.FriendRoom;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MrWu.Basic;
|
||||
|
||||
namespace Server {
|
||||
/// <summary>
|
||||
/// 玩法管理
|
||||
/// </summary>
|
||||
public class WayManager {
|
||||
|
||||
/* 玩法只需要存储桌子的唯一码,具体的数据到Room 类里面拿
|
||||
*
|
||||
* 1.加入玩法房间
|
||||
* 2.创建玩法房间
|
||||
* 3.退出玩法房间
|
||||
*
|
||||
* 4.玩法被删除。-> 主动解散房间
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// 数据库Idx
|
||||
/// </summary>
|
||||
public const int DbIdx = 6;
|
||||
|
||||
/// <summary>
|
||||
/// 实例
|
||||
/// </summary>
|
||||
public static WayManager instance {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private WayManager() { }
|
||||
|
||||
static WayManager() {
|
||||
instance = new WayManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库代理
|
||||
/// </summary>
|
||||
public IDatabaseProxy databaseProxy {
|
||||
get {
|
||||
return redisManager.Getdb(DbIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// redis数据事务操作
|
||||
/// </summary>
|
||||
public IDatabase db {
|
||||
get {
|
||||
return redisManager.GetDataBase(DbStyle.main, DbIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基本Key
|
||||
/// </summary>
|
||||
public const string BaseKey = "ClubWay:";
|
||||
|
||||
/// <summary>
|
||||
/// 获取桌子信息的Key值
|
||||
/// </summary>
|
||||
/// <param name="clubid">竞技比赛id</param>
|
||||
/// <param name="wayid">玩法id</param>
|
||||
public string GetDeskInfoKey(int clubid, string wayid) {
|
||||
return $"{BaseKey}{clubid}:{wayid}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///保存玩法的桌子
|
||||
/// </summary>
|
||||
/// <param name="clubid">竞技比赛id</param>
|
||||
/// <param name="wayid">玩法id</param>
|
||||
/// <param name="weiyima">唯一码</param>
|
||||
public void SaveWayDesk(int clubid, string wayid, string weiyima) {
|
||||
|
||||
|
||||
string key = GetDeskInfoKey(clubid, wayid);
|
||||
|
||||
//暂时 Hash 的 Value 不存放数据, 没啥可以存的。留给以后扩展
|
||||
databaseProxy.HashSet(key, weiyima, 0);
|
||||
|
||||
// WayDeskChangeSend(clubid, wayid, weiyima, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除玩法的桌子信息
|
||||
/// </summary>
|
||||
/// <param name="clubid"></param>
|
||||
/// <param name="wayid"></param>
|
||||
/// <param name="weiyima"></param>
|
||||
public void DelDeskInfo(int clubid, string wayid, string weiyima) {
|
||||
|
||||
string key = GetDeskInfoKey(clubid, wayid);
|
||||
//WayDeskChangeSend(clubid, wayid, weiyima, 1);
|
||||
databaseProxy.HashDelete(key, weiyima);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除玩法
|
||||
/// </summary>
|
||||
/// <param name="clubid">竞技比赛id</param>
|
||||
/// <param name="wayid">玩法id</param>
|
||||
public void DelWay(int clubid, string wayid) {
|
||||
string key = GetDeskInfoKey(clubid, wayid);
|
||||
//写这两句是要干嘛 玩法是竞技比赛发起的,发给竞技比赛多余
|
||||
//var weiyimaList = GetDesksWeiYiMa(clubid, wayid).Select(p => p.Name).ToList();
|
||||
//weiyimaList.ForEach(weiyima => WayDeskChangeSend(clubid, wayid, weiyima, 1));
|
||||
databaseProxy.KeyDelete(key);
|
||||
}
|
||||
|
||||
public Task<DeskInfo> LoadDeskInfoAsync(string weiyima)
|
||||
{
|
||||
return Task.Run(() => LoadDeskInfo(weiyima));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载桌子信息
|
||||
/// </summary>
|
||||
/// <param name="weiyima">唯一码</param>
|
||||
/// <returns></returns>
|
||||
public DeskInfo LoadDeskInfo(string weiyima)
|
||||
{
|
||||
|
||||
//去Room 类里面找到加载DeskInfo 方法补充起来
|
||||
DeskInfo deskinfo = null;
|
||||
if(!Room.LoadRoom(weiyima, out deskinfo)) {
|
||||
Debug.Info("未加载成功!");
|
||||
return null;
|
||||
}
|
||||
if(deskinfo == null) {
|
||||
Debug.Info("加载成功, 却没有桌子信息???");
|
||||
}
|
||||
return deskinfo;
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// 加载某个玩法的所有桌子信息
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// public List<DeskInfo> LoadDeskInfo(int clubid, string wayid) {
|
||||
// string key = GetDeskInfoKey(clubid, wayid);
|
||||
//
|
||||
// return LoadDeskInfoInternal(key);
|
||||
// }
|
||||
|
||||
public Task<List<DeskInfo>> LoadDeskInfoAsync(int clubId)
|
||||
{
|
||||
return Task.Run(() => LoadDeskInfo(clubId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取竞技比赛的所有桌子
|
||||
/// </summary>
|
||||
/// <param name="clubid"></param>
|
||||
/// <returns></returns>
|
||||
public List<DeskInfo> LoadDeskInfo(int clubid) {
|
||||
string pattern = GetDeskInfoKey(clubid, "*");
|
||||
//获取此club所有玩法的key
|
||||
var clubKeys = redisManager.Keys(pattern, DbIdx, 1000,DbStyle.main);
|
||||
//将当前club的所有玩法及每玩法的所有桌;
|
||||
int len = clubKeys.Count;
|
||||
List<DeskInfo> infos = new List<DeskInfo>();
|
||||
for (int i = 0; i < len; i++) {
|
||||
infos.AddRange(LoadDeskInfoInternal(clubKeys[i]));
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
|
||||
List<DeskInfo> LoadDeskInfoInternal(RedisKey key) {
|
||||
List<DeskInfo> desks = new List<DeskInfo>();
|
||||
//获取此key下所有唯一码
|
||||
var weiyimaArray = databaseProxy.HashGetAll(key);
|
||||
|
||||
int len = weiyimaArray.Length;
|
||||
DeskInfo info;
|
||||
for (int i = 0; i < len; i++) {
|
||||
info = LoadDeskInfo(weiyimaArray[i].Name);
|
||||
if (info != null)
|
||||
desks.Add(info);
|
||||
}
|
||||
return desks;
|
||||
// return weiyimaArray.Select(weiyima => LoadDeskInfo(weiyima)).Where(deskInfo => deskInfo != null).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取这个玩法的所有的桌子的唯一码
|
||||
/// </summary>
|
||||
/// <param name="clubid"></param>
|
||||
/// <param name="wayid"></param>
|
||||
/// <returns>唯一码 玩家人数</returns>
|
||||
public HashEntry[] GetDesksWeiYiMa(int clubid, string wayid) {
|
||||
return databaseProxy.HashGetAll(GetDeskInfoKey(clubid, wayid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 竞技比赛玩家变化
|
||||
/// </summary>
|
||||
/// <param name="clubid">竞技比赛id</param>
|
||||
/// <param name="wayid">玩法id</param>
|
||||
/// <param name="weiyima">桌子的唯一码</param>
|
||||
/// <param name="isInc">是否是增量 true 增 false 减</param>
|
||||
public ClubWayPlayer ClubWayPlayerChange(int clubid, string wayid, string weiyima, bool isInc) {
|
||||
|
||||
//组建ClubWayPlayer
|
||||
string key = GetDeskInfoKey(clubid, wayid);
|
||||
|
||||
ClubWayPlayer cwp = new ClubWayPlayer();
|
||||
cwp.clubid = clubid;
|
||||
cwp.wayid = wayid;
|
||||
cwp.weiyima = weiyima;
|
||||
if (isInc)
|
||||
cwp.playerCnt = (int)databaseProxy.HashIncrement(key, weiyima);
|
||||
else
|
||||
cwp.playerCnt = (int)databaseProxy.HashDecrement(key, weiyima);
|
||||
//cwp.playerCnt = (int)databaseProxy.HashIncrement(GetDeskInfoKey(clubid, wayid), weiyima, isInc ? 1 : -1);
|
||||
return cwp;
|
||||
|
||||
/*
|
||||
ClubWayPlayer cwp = new ClubWayPlayer();
|
||||
cwp.clubid = clubid;
|
||||
cwp.wayid = wayid;
|
||||
|
||||
string key = GetKey(clubid, wayid);
|
||||
var datas = redisManager.db.SortedSetRangeByRankWithScores(key, 0, -1, Order.Descending);
|
||||
if (datas == null) {
|
||||
cwp.deskCnt = 0;
|
||||
cwp.playerCnt = 0;
|
||||
|
||||
} else {
|
||||
int len = datas.Length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (datas[i].Score < minCnt) {
|
||||
cwp.playerCnt = (int)datas[i].Score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cwp.deskCnt = len;
|
||||
}
|
||||
return cwp;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 玩法的桌子变化 数据发送
|
||||
/// </summary>
|
||||
/// <param name="clubid">竞技比赛id</param>
|
||||
/// <param name="wayid">玩法id</param>
|
||||
/// <param name="weiyima">桌子的唯一码</param>
|
||||
/// <param name="style">类型 0新增 1删除 2更新</param>
|
||||
public void WayDeskChangeSend(int clubid, string wayid, string weiyima, int style) {
|
||||
//组建 WayDeskChange 包裹发送给竞技比赛
|
||||
|
||||
var wdc = new Data.WayDeskChange {
|
||||
clubid = clubid,
|
||||
wayid = wayid,
|
||||
deskweiyima = weiyima,
|
||||
style = style
|
||||
};
|
||||
|
||||
PackHead head = PackHead.Create(Pack.ServerPackAgreement.WayDeskChange);
|
||||
MQ.GlobalMQ.instance.DeliveryEveryOne((int)Data.Module.ModuleType.ClubModule, MQ.GlobalMQ.CreateMessage(head, wdc), true);
|
||||
head.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user