mirror of
https://github.com/rafi1212122/PemukulPaku
synced 2025-12-12 19:44:37 +01:00
164 lines
4.9 KiB
C#
164 lines
4.9 KiB
C#
using System.Net.Sockets;
|
|
using Common;
|
|
using Common.Resources.Proto;
|
|
using Common.Utils;
|
|
using PemukulPaku.GameServer.Commands;
|
|
using PemukulPaku.GameServer.Game;
|
|
|
|
namespace PemukulPaku.GameServer
|
|
{
|
|
public class Session
|
|
{
|
|
public readonly string Id;
|
|
public readonly TcpClient Client;
|
|
public readonly Logger c;
|
|
public long LastClientKeepAlive = Global.GetUnixInSeconds();
|
|
public long LastServerKeepAlive = Global.GetUnixInSeconds();
|
|
public Player Player = default!;
|
|
|
|
public Session(string id, TcpClient client)
|
|
{
|
|
Id = id;
|
|
Client = client;
|
|
c = new Logger(Id);
|
|
Task.Run(ClientLoop);
|
|
new Thread(KeepAliveLoop).Start();
|
|
}
|
|
|
|
private void ClientLoop()
|
|
{
|
|
NetworkStream stream = Client.GetStream();
|
|
|
|
byte[] msg = new byte[1 << 16];
|
|
|
|
while (Client.Connected)
|
|
{
|
|
Array.Clear(msg, 0, msg.Length);
|
|
int len = stream.Read(msg, 0, msg.Length);
|
|
|
|
if (len > 0)
|
|
{
|
|
List<byte[]> packets = new ();
|
|
|
|
ReadOnlySpan<byte> prefix = new byte[] { 0x01, 0x23, 0x45, 0x67 };
|
|
ReadOnlySpan<byte> suffix = new byte[] { 0x89, 0xAB, 0xCD, 0xEF };
|
|
|
|
Span<byte> message = msg.AsSpan();
|
|
|
|
for (int offset = 0; offset < message.Length;)
|
|
{
|
|
var segment = message[offset..];
|
|
int start = segment.IndexOf(prefix);
|
|
|
|
if (start == -1)
|
|
break;
|
|
|
|
int end = segment.IndexOf(suffix);
|
|
|
|
if (end == -1)
|
|
break;
|
|
|
|
end += suffix.Length;
|
|
|
|
packets.Add(segment[start..end].ToArray());
|
|
offset += end;
|
|
}
|
|
|
|
foreach (byte[] packet in packets)
|
|
{
|
|
if (Packet.IsValid(packet))
|
|
{
|
|
ProcessPacket(new Packet(packet), true);
|
|
}
|
|
else
|
|
{
|
|
c.Error("Invalid packet received:", BitConverter.ToString(packet).Replace("-", ""));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void KeepAliveLoop()
|
|
{
|
|
while(Client.Connected)
|
|
{
|
|
try
|
|
{
|
|
Send(Packet.FromProto(new KeepAliveNotify() { }, CmdId.KeepAliveNotify));
|
|
}
|
|
catch
|
|
{
|
|
break;
|
|
}
|
|
Thread.Sleep(3000);
|
|
}
|
|
|
|
Player.SaveAll();
|
|
c.Debug("Player data saved to database");
|
|
c.Warn($"{Id} disconnected");
|
|
|
|
if (ReadLine.GetInstance().session == this) { ReadLine.GetInstance().session = null; }
|
|
Server.GetInstance().Sessions.Remove(Id);
|
|
Server.GetInstance().LogClients();
|
|
}
|
|
|
|
public void ProcessPacket(Packet _packet, bool log = false)
|
|
{
|
|
string PacketName = Enum.GetName(typeof(CmdId), _packet.CmdId)!;
|
|
if(PacketName == "KeepAliveNotify") { LastClientKeepAlive = Global.GetUnixInSeconds(); c.Log(PacketName); return; }
|
|
try
|
|
{
|
|
CmdId cmdId = (CmdId)Enum.ToObject(typeof(CmdId), _packet.CmdId);
|
|
IPacketHandler? handler = PacketFactory.GetPacketHandler(cmdId);
|
|
|
|
if (handler == null)
|
|
{
|
|
c.Warn($"{PacketName} not handled!");
|
|
return;
|
|
}
|
|
|
|
if(log)
|
|
c.Log(PacketName);
|
|
|
|
handler.Handle(this, _packet);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
if ((int)Global.config.VerboseLevel > 0)
|
|
{
|
|
c.Error(ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Send(params Packet[] packets)
|
|
{
|
|
foreach (Packet packet in packets)
|
|
{
|
|
string PacketName = Enum.GetName(typeof(CmdId), packet.CmdId)!;
|
|
|
|
try
|
|
{
|
|
Client.GetStream().Write(packet.Raw, 0, packet.Raw.Length);
|
|
c.Log(PacketName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
c.Error($"Failed to send {PacketName}:" + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Id;
|
|
}
|
|
|
|
public static Session? FromUid(uint uid)
|
|
{
|
|
return Server.GetInstance().Sessions.FirstOrDefault(s => s.Value.Player.User.Uid == uid).Value;
|
|
}
|
|
}
|
|
}
|