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
593 lines
21 KiB
C#
593 lines
21 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Configuration;
|
||
using System.IO;
|
||
using System.Net;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using GameData;
|
||
using GameData;
|
||
using GameMessage;
|
||
using MessagePack;
|
||
using MrWu.Debug;
|
||
using MrWu.RabbitMQ;
|
||
using Newtonsoft.Json;
|
||
using Server.Core;
|
||
using Server.Data;
|
||
using Server.Data.Module;
|
||
using Server.MQ;
|
||
using Server.Net;
|
||
using Server.Pack;
|
||
using UnityGame;
|
||
|
||
namespace Server
|
||
{
|
||
public class GameMessageManager : SingleInstance<GameMessageManager>, IDisposable
|
||
{
|
||
private bool isStart = false;
|
||
|
||
/// <summary>
|
||
/// 等待处理的消息
|
||
/// </summary>
|
||
private readonly ConcurrentQueue<PackGroup> waitHandleMsg = new ConcurrentQueue<PackGroup>();
|
||
|
||
private readonly ConcurrentQueue<PackGroup> idlePackGroup = new ConcurrentQueue<PackGroup>();
|
||
|
||
private ModuleType _moduleType;
|
||
|
||
private int _moduleId;
|
||
|
||
private int Port;
|
||
|
||
public void Start(ModuleType moduleType,int port,int gameid)
|
||
{
|
||
if (isStart)
|
||
{
|
||
return;
|
||
}
|
||
|
||
this._moduleType = moduleType;
|
||
this._moduleId = (int)moduleType;
|
||
|
||
if (port > 0)
|
||
{
|
||
GameNetManager.Instance.ConnectedEvt += OnConnected;
|
||
GameNetManager.Instance.DisConnectedEvt += OnDisconnected;
|
||
GameNetManager.Instance.ReceiveEvt += OnReceived;
|
||
GameNetManager.Instance.Start($"/serid{gameid}/", port);
|
||
Port = port;
|
||
}
|
||
|
||
MessageDispatcher.Instance.AddListener(MessageCode.ClientPackRequest, OnClientPackRequest);
|
||
Debug.Info($"启动监听:{port} {gameid}");
|
||
isStart = true;
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
if (isStart)
|
||
{
|
||
if (Port > 0)
|
||
{
|
||
GameNetManager.Instance.Update();
|
||
}
|
||
|
||
while (true)
|
||
{
|
||
if (waitHandleMsg.TryDequeue(out PackGroup packGroup))
|
||
{
|
||
OnReceived(packGroup.Session,packGroup.HeadWrapper);
|
||
packGroup.HeadWrapper.Dispose();
|
||
ReleasePackGroup(packGroup);
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
if (isStart)
|
||
{
|
||
if (Port > 0)
|
||
{
|
||
GameNetManager.Instance.ConnectedEvt -= OnConnected;
|
||
GameNetManager.Instance.DisConnectedEvt -= OnDisconnected;
|
||
GameNetManager.Instance.ReceiveEvt -= OnReceived;
|
||
GameNetManager.Instance.Dispose();
|
||
}
|
||
|
||
isStart = false;
|
||
}
|
||
|
||
}
|
||
|
||
private void OnConnected(Session session)
|
||
{
|
||
PackHead head = PackHead.Create();
|
||
head.packlx = ServerPackAgreement.connecOk;
|
||
session.SendPack(head);
|
||
head.Dispose();
|
||
}
|
||
|
||
private void OnDisconnected(Session session)
|
||
{
|
||
if (session.UserData == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
int userid = session.UserData.Userid;
|
||
if (!GameSessionManager.Instance.RemovePlayerSession(userid, session)) {
|
||
Debug.Error("玩家未移除链接!");
|
||
return;
|
||
}
|
||
|
||
GameDispatcher.Instance.DispatchNextFrame(GameMsgId.DisConnected, userid);
|
||
}
|
||
|
||
private void OnReceived(IUserSession session, byte[] data)
|
||
{
|
||
int packlx = 0;
|
||
try
|
||
{
|
||
string jsonData = Encoding.UTF8.GetString(data);
|
||
HeadWrapper headWrapper = JsonPack.GetData<HeadWrapper>(jsonData);
|
||
headWrapper.head.ip = session.RemoteIPAddress.ToString();
|
||
headWrapper.IsText = true;
|
||
|
||
if (headWrapper == null || headWrapper.head == null)
|
||
{
|
||
Debug.Error($"解包失败,收到的消息:{jsonData}");
|
||
session.DisConnected();
|
||
return;
|
||
}
|
||
|
||
if (session.UserData != null)
|
||
{
|
||
headWrapper.head.userid = session.UserData.Userid;
|
||
}
|
||
|
||
//输出毫秒值
|
||
//Debug.Info($"收包线程:{Thread.CurrentThread.ManagedThreadId},{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
|
||
waitHandleMsg.Enqueue(GetPackGroup(session, headWrapper));
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Error($"收包处理错误 packlx:{packlx} {e.Message}");
|
||
}
|
||
}
|
||
|
||
private Task OnClientPackRequest(GamePacket gamePacket)
|
||
{
|
||
//Debug.Log("收到客户端来的包!");
|
||
if (gamePacket.MessageData is ClientPackRequest request)
|
||
{
|
||
Debug.Log($"head:{request.Head.Length}");
|
||
PackHead head = MessagePackSerializer.Deserialize<PackHead>(request.Head);
|
||
|
||
head.ip = gamePacket.Session.RemoteIPAddress.ToString();
|
||
if (gamePacket.Session.UserData != null)
|
||
{
|
||
head.userid = gamePacket.Session.UserData.Userid;
|
||
Debug.Log($"取服务器中绑定的数据:{head.userid}");
|
||
head.plat = gamePacket.Session.UserData.Plat.ToString();
|
||
head.platValue = gamePacket.Session.UserData.Plat;
|
||
head.clientVer = gamePacket.Session.UserData.ClientVer;
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"包内带的数据:{head.userid}");
|
||
}
|
||
|
||
HeadWrapper headWrapper = HeadWrapper.Create(head, request.Data);
|
||
if (gamePacket.Session is ProxySession temp)
|
||
{
|
||
waitHandleMsg.Enqueue(GetPackGroup(temp.SourceSession, headWrapper));
|
||
}
|
||
}
|
||
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
private void OnReceived(IUserSession session, HeadWrapper headWrapper)
|
||
{
|
||
PackHead head = headWrapper.head;
|
||
if (head.Util == null)
|
||
{
|
||
head.Util = GameBase.instance.myUtil;
|
||
}
|
||
|
||
switch (head.packlx)
|
||
{
|
||
case ServerPackAgreement.SocketPing: //测试用的
|
||
if (session.UserData != null)
|
||
Debug.Log("收到测试包了!");
|
||
|
||
session.SendPack(head,headWrapper.jsonMessage);
|
||
break;
|
||
|
||
|
||
case ServerPackAgreement.GetPlayerGameInfo: //获取玩家所有的游戏信息
|
||
GetPlayerGameInfo(head, session);
|
||
break;
|
||
|
||
case ServerPackAgreement.registeredSocket: //登录在本Socket中注册玩家
|
||
Debug.Log("来包绑定Socket!");
|
||
AddUser(head, (headWrapper.IsBinary ? headWrapper.Data2Text : headWrapper.jsonMessage), session);
|
||
break;
|
||
|
||
case ServerPackAgreement.closeSocket: //连接断开
|
||
session.DisConnected();
|
||
break;
|
||
|
||
case ServerPackAgreement.PushLogin: //强行登录
|
||
break;
|
||
|
||
case ServerPackAgreement.Heartbeat: //处理心跳
|
||
// if (head.otherInt != null)
|
||
// {
|
||
// Debug.Info($"处理心跳:{head.otherInt[0]} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
|
||
// }
|
||
// else
|
||
// {
|
||
// Debug.Info("心跳包??");
|
||
// }
|
||
|
||
DoHeart(head,session);
|
||
break;
|
||
|
||
// case GamePackAgreement.EveryGame://任意游戏模块处理
|
||
// deliveyGame_(head,messagedata);
|
||
// break;
|
||
|
||
case GamePackAgreement.DoMessgae: //处理消息转发
|
||
break;
|
||
|
||
case GamePackAgreement.UpdateSocketCryptKey: //应客户端要求更新加密密钥
|
||
|
||
break;
|
||
|
||
default: //发送给指定游戏模块
|
||
if (session.UserData == null)
|
||
{
|
||
Debug.ImportantLog($"收到未知来历的包裹:{head.packlx}");
|
||
return;
|
||
}
|
||
|
||
Debug.Log("收到包裹:" + head.packlx);
|
||
//665000
|
||
if (head.packlx >= Game.Data.GameData.PackCardInt)
|
||
{
|
||
if ((head.packlx / Game.Data.GameData.PackCardInt) != _moduleId)
|
||
{
|
||
Debug.Warning("收到未解析的包裹!" + head.packlx);
|
||
return;
|
||
}
|
||
head.packlx = head.packlx % Game.Data.GameData.PackCardInt;
|
||
}
|
||
GamePack gamePack = null;
|
||
if (headWrapper.IsText)
|
||
{
|
||
gamePack = GamePack.Create(head, headWrapper.jsonMessage);
|
||
}
|
||
else
|
||
{
|
||
gamePack = GamePack.Create(head, headWrapper.Data);
|
||
}
|
||
GameManager.instance.DoPack(gamePack);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理心跳包
|
||
/// </summary>
|
||
private void DoHeart(PackHead head, IUserSession session) {
|
||
if (session.UserData == null) {
|
||
return;
|
||
}
|
||
|
||
session.SendPack(head);
|
||
}
|
||
|
||
private void AddUser(PackHead head, string jsonMessage, IUserSession session)
|
||
{
|
||
if (head.userid <= 0)
|
||
{
|
||
Debug.Log("userid is zero");
|
||
return;
|
||
}
|
||
|
||
//有uuid 处理uuid 没有 uuid 创建 uuid
|
||
BindSocket bindSocket = null;
|
||
if (!string.IsNullOrEmpty(jsonMessage))
|
||
{
|
||
bindSocket = JsonPack.GetData<BindSocket>(jsonMessage);
|
||
}
|
||
else
|
||
{
|
||
// 先临时生成uuid,后续升级可以把这个删除,没有提供uuid的包,提示升级
|
||
bindSocket = new BindSocket()
|
||
{
|
||
SeesionUUID = SessionUUIDManager.Instance.CreateSessionUUID(head.userid)
|
||
};
|
||
}
|
||
|
||
int userid = SessionUUIDManager.Instance.CheckSessionUUID(bindSocket.SeesionUUID);
|
||
|
||
if (userid != head.userid)
|
||
{
|
||
//登录过期,请重新登录
|
||
SendLoginResult(head, -1, session);
|
||
session.DisConnected();
|
||
return;
|
||
}
|
||
|
||
IUserSession beforeSession = GameSessionManager.Instance.FindSession(userid);
|
||
|
||
if (beforeSession != null) { //这个玩家已经有链接了
|
||
|
||
if (beforeSession == session)
|
||
{
|
||
Debug.Warning($"同一个链接发送过来的注册,已经注册过了! {userid}");
|
||
return;
|
||
}
|
||
|
||
Debug.Warning("--已经有这个链接了!" + head.userid + "," + beforeSession.IsDisConnected);
|
||
if (beforeSession.IsDisConnected)
|
||
{
|
||
Debug.Error($"已经有这个连接了:{head.userid}");
|
||
}
|
||
else
|
||
{
|
||
if(beforeSession.UserData != null)
|
||
{
|
||
Debug.Error($"--- ForceDisConnected UserId:{userid} beforeSession:{beforeSession.RemoteIPAddress} session:{session.RemoteIPAddress} {beforeSession.GetType().FullName} DeveiceInfoId:{beforeSession.UserData.DeviceInfo} {bindSocket.DeviceInfoId}");
|
||
}
|
||
else
|
||
{
|
||
Debug.Error($"beforeSession UserData is null userid:{userid}");
|
||
}
|
||
}
|
||
|
||
//断线,但是有可能还未发完包
|
||
// 先把断线逻辑处理完
|
||
if (beforeSession is Session)
|
||
{
|
||
SendLoginResult(head, -4, beforeSession);
|
||
GameNetManager.Instance.ForceDisconnected(beforeSession.Id);
|
||
}
|
||
else if (beforeSession is UserSession userSession)
|
||
{
|
||
userSession.ForceDiscConnect(ServerFin.FinCode_RemoteLogin,userid);
|
||
Debug.ImportantLog($"上一个强制下线:{userSession.Id} {ServerFin.FinCode_RemoteLogin}");
|
||
//要处理下线逻辑
|
||
}
|
||
|
||
SendLoginResult(head, -9, session);
|
||
|
||
} else
|
||
{
|
||
BindUser(session, userid, bindSocket, head);
|
||
}
|
||
}
|
||
|
||
private void BindUser(IUserSession session,int userid, BindSocket bindSocket,PackHead head)
|
||
{
|
||
object lockObj = null;
|
||
if (session is Session userSession)
|
||
{
|
||
lockObj = userSession.DisConnectLock;
|
||
}
|
||
else if (session is UserSession _userSession)
|
||
{
|
||
lockObj = new object();
|
||
}
|
||
|
||
lock (lockObj)
|
||
{
|
||
if (session.IsDisConnected)
|
||
{
|
||
Debug.Error("玩家链接已经断开,不处理!");
|
||
return;
|
||
}
|
||
|
||
session.BindUser(userid, bindSocket.SeesionUUID, head.clientVer,head.platValue,bindSocket.DeviceInfoId,false,bindSocket.StoreType);
|
||
//这个玩家正常
|
||
if (GameSessionManager.Instance.AddPlayerSession(head.userid, session))
|
||
{
|
||
Debug.Info("绑定完成!");
|
||
SendLoginResult(head, 1, session);
|
||
}
|
||
else
|
||
{
|
||
Debug.Error("玩家没有添加成功!");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发送登录结果包
|
||
/// </summary>
|
||
/// <param name="head"></param>
|
||
/// <param name="style"></param>
|
||
/// <param name="session"></param>
|
||
private void SendLoginResult(PackHead head, int style, IUserSession session, playerData pl = null) {
|
||
head.packlx = GamePackAgreement.registeredSocket;
|
||
|
||
SocketRegResult result = SocketRegResult.GetSocketRegResult(style);
|
||
result.pldata = pl;
|
||
session.SendPack(head, result);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取玩家所在的游戏信息
|
||
/// </summary>
|
||
/// <param name="head">包头</param>
|
||
/// <param name="session">链接</param>
|
||
private async void GetPlayerGameInfo(PackHead head, IUserSession session) {
|
||
if (session.UserData == null) {
|
||
Debug.Error("897c570e-6571-4958-adaa-e8f2e48f2db1:用户未链接完成!" + head.userid);
|
||
return;
|
||
}
|
||
|
||
int clickGame = 0;
|
||
if (head.otherInt != null && head.otherInt.Length > 0) {
|
||
clickGame = head.otherInt[0];
|
||
}
|
||
|
||
PlayerLockInfo pllockinfo = await PlayerFun.GetPlayerLockInfoAsync(head.userid);
|
||
|
||
head = PackHead.Create(ServerPackAgreement.InGameInfo);
|
||
PlayerGameInfo pgi = null;
|
||
|
||
//这个包是给朋友房用的,朋友房先查询是不是在游戏中,如果在就提示玩家,不在才让进朋友房
|
||
if (pllockinfo != null) {
|
||
pgi = new PlayerGameInfo(pllockinfo.gameid, pllockinfo.isFriend ? 1 : 0,1, clickGame);
|
||
} else {
|
||
pgi = new PlayerGameInfo(0, 0, 2, clickGame);
|
||
}
|
||
|
||
session.SendPack(head,pgi);
|
||
head.Dispose();
|
||
}
|
||
|
||
private PackGroup GetPackGroup(IUserSession session,HeadWrapper headWrapper)
|
||
{
|
||
if (!idlePackGroup.TryDequeue(out PackGroup packGroup))
|
||
{
|
||
packGroup = new PackGroup();
|
||
}
|
||
packGroup.Session = session;
|
||
packGroup.HeadWrapper = headWrapper;
|
||
return packGroup;
|
||
}
|
||
|
||
private void ReleasePackGroup(PackGroup packGroup)
|
||
{
|
||
packGroup.Clear();
|
||
idlePackGroup.Enqueue(packGroup);
|
||
}
|
||
|
||
public bool ForceOffLine(int userid,bool isSendPack)
|
||
{
|
||
IUserSession session = GameSessionManager.Instance.FindSession(userid);
|
||
if (session == null)
|
||
{
|
||
Debug.Info("没找到玩家!" + userid);
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
if (isSendPack)
|
||
{
|
||
PackHead head = PackHead.Create(ServerPackAgreement.registeredSocket);
|
||
SocketRegResult plr = SocketRegResult.GetSocketRegResult(-4);
|
||
session.SendPack(head,plr);
|
||
head.Dispose();
|
||
}
|
||
|
||
session.DisConnected();
|
||
return true;
|
||
}
|
||
}
|
||
|
||
private class PackGroup
|
||
{
|
||
public IUserSession Session;
|
||
|
||
public HeadWrapper HeadWrapper;
|
||
|
||
public void Clear()
|
||
{
|
||
Session = null;
|
||
HeadWrapper = null;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
public static class SessionExtend
|
||
{
|
||
public static void SendPack(this IUserSession session, PackHead head, byte[] data)
|
||
{
|
||
if (session == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
HeadWrapper headWrapper = HeadWrapper.Create(head, data);
|
||
session.SendPack(headWrapper);
|
||
headWrapper.Dispose();
|
||
}
|
||
|
||
public static void SendPack(this IUserSession session, PackHead head, object data) {
|
||
|
||
if (session == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
session.SendPack(head, data == null ? null : JsonPack.GetJson(data));
|
||
}
|
||
|
||
public static void SendPack(this IUserSession session, PackHead head, string jsonMessage = null)
|
||
{
|
||
if (session == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//todo 这里可以用引用池
|
||
HeadWrapper headWrapper = HeadWrapper.Create(head, jsonMessage);
|
||
session.SendPack(headWrapper);
|
||
headWrapper.Dispose();
|
||
}
|
||
|
||
public static void SendPack(this IUserSession session, HeadWrapper value)
|
||
{
|
||
if (session == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (session.IsDisConnected)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//Debug.Info($"发送包数据:{value.head.packlx}");
|
||
//这里只能按字符串发送,TMD。之前的设计害死人
|
||
if (session is Session oldSession)
|
||
{
|
||
string jsonValue = JsonPack.GetJson(value);
|
||
oldSession.Send(jsonValue);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"发包给客户端: 2122");
|
||
byte[] data = value.Data;
|
||
if (value.jsonMessage != null)
|
||
{
|
||
data = Encoding.UTF8.GetBytes(value.jsonMessage);
|
||
}
|
||
|
||
if (data != null)
|
||
{
|
||
Debug.Log($"发送的数据:{data.Length}");
|
||
}
|
||
|
||
ClientPackResponse response =
|
||
ClientPackResponse.Create(MessagePackSerializer.Serialize(value.head), data);
|
||
session.Send(response);
|
||
response.Dispose();
|
||
}
|
||
}
|
||
}
|
||
} |