Files
DanhengServer-OpenSource/DanhengKcpSharp/DanhengConnection.cs

165 lines
5.1 KiB
C#

using System.Net;
using System.Reflection;
using EggLink.DanhengServer.Enums;
using EggLink.DanhengServer.Kcp.KcpSharp;
using EggLink.DanhengServer.Util;
using Google.Protobuf;
using Google.Protobuf.Reflection;
namespace EggLink.DanhengServer.Kcp;
public class DanhengConnection
{
public const int MAX_MSG_SIZE = 16384;
public const int HANDSHAKE_SIZE = 20;
public static readonly List<int> BannedPackets = [];
private static readonly Logger Logger = new("GameServer");
public static readonly Dictionary<string, string> LogMap = [];
public static readonly List<int> IgnoreLog =
[
CmdIds.PlayerHeartBeatCsReq, CmdIds.PlayerHeartBeatScRsp, CmdIds.SceneEntityMoveCsReq,
CmdIds.SceneEntityMoveScRsp, CmdIds.GetShopListCsReq, CmdIds.GetShopListScRsp
];
protected readonly CancellationTokenSource CancelToken;
protected readonly KcpConversation Conversation;
public readonly IPEndPoint RemoteEndPoint;
public string DebugFile = "";
public bool IsOnline = true;
public StreamWriter? Writer;
public DanhengConnection(KcpConversation conversation, IPEndPoint remote)
{
Conversation = conversation;
RemoteEndPoint = remote;
CancelToken = new CancellationTokenSource();
Start();
}
public long? ConversationId => Conversation.ConversationId;
public SessionStateEnum State { get; set; } = SessionStateEnum.INACTIVE;
//public PlayerInstance? Player { get; set; }
public virtual void Start()
{
Logger.Info($"New connection from {RemoteEndPoint}.");
State = SessionStateEnum.WAITING_FOR_TOKEN;
}
public virtual void Stop()
{
//Player?.OnLogoutAsync();
//Listener.UnregisterConnection(this);
Conversation.Dispose();
try
{
CancelToken.Cancel();
CancelToken.Dispose();
}
catch
{
}
IsOnline = false;
}
public void LogPacket(string sendOrRecv, ushort opcode, byte[] payload)
{
try
{
//Logger.DebugWriteLine($"{sendOrRecv}: {Enum.GetName(typeof(OpCode), opcode)}({opcode})\r\n{Convert.ToHexString(payload)}");
if (IgnoreLog.Contains(opcode)) return;
var typ = AppDomain.CurrentDomain.GetAssemblies()
.SingleOrDefault(assembly => assembly.GetName().Name == "DanhengProto")!.GetTypes()
.First(t => t.Name == $"{LogMap[opcode.ToString()]}"); //get the type using the packet name
var descriptor =
typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static)?.GetValue(
null, null) as MessageDescriptor; // get the static property Descriptor
var packet = descriptor?.Parser.ParseFrom(payload);
var formatter = JsonFormatter.Default;
var asJson = formatter.Format(packet);
var output = $"{sendOrRecv}: {LogMap[opcode.ToString()]}({opcode})\r\n{asJson}";
#if DEBUG
Logger.Debug(output);
#endif
if (DebugFile != "" && ConfigManager.Config.ServerOption.SavePersonalDebugFile)
{
var sw = GetWriter();
sw.WriteLine($"[{DateTime.Now:HH:mm:ss}] [GameServer] [DEBUG] " + output);
sw.Flush();
}
}
catch
{
var output = $"{sendOrRecv}: {LogMap[opcode.ToString()]}({opcode})";
#if DEBUG
Logger.Debug(output);
#endif
if (DebugFile != "" && ConfigManager.Config.ServerOption.SavePersonalDebugFile)
{
var sw = GetWriter();
sw.WriteLine($"[{DateTime.Now:HH:mm:ss}] [GameServer] [DEBUG] " + output);
sw.Flush();
}
}
}
private StreamWriter GetWriter()
{
// Create the file if it doesn't exist
var file = new FileInfo(DebugFile);
if (!file.Exists)
{
Directory.CreateDirectory(file.DirectoryName!);
File.Create(DebugFile).Dispose();
}
Writer ??= new StreamWriter(DebugFile, true);
return Writer;
}
public async Task SendPacket(byte[] packet)
{
try
{
_ = await Conversation.SendAsync(packet, CancelToken.Token);
}
catch
{
// ignore
}
}
public async Task SendPacket(BasePacket packet)
{
// Test
if (packet.CmdId <= 0)
{
Logger.Debug("Tried to send packet with missing cmd id!");
return;
}
// DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can)
if (BannedPackets.Contains(packet.CmdId)) return;
LogPacket("Send", packet.CmdId, packet.Data);
// Header
var packetBytes = packet.BuildPacket();
try
{
_ = await Conversation.SendAsync(packetBytes, CancelToken.Token);
}
catch
{
// ignore
}
}
public async Task SendPacket(int cmdId)
{
await SendPacket(new BasePacket((ushort)cmdId));
}
}