jsgr-mmo/src/Core/Client.cs
Robert Paciorek 0f161d899c fixes for SuperSecret
- added logout handler
- support for api 0.x (MID as string)
- support for using SUV insted of SPV
- use zoneName from login request when no roomName in join room request
2024-04-22 02:48:37 +00:00

116 lines
3.4 KiB
C#

using sodoffmmo.Data;
using System;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
namespace sodoffmmo.Core;
public class Client {
static int id;
static object lck = new();
public int ClientID { get; private set; }
public PlayerData PlayerData { get; set; } = new();
public Room? Room { get; private set; }
public bool OldApi { get; set; } = false;
public bool TempMuted { get; set; } = false;
private readonly Socket socket;
SocketBuffer socketBuffer = new();
private volatile bool scheduledDisconnect = false;
private readonly object clientLock = new();
public Client(Socket clientSocket) {
socket = clientSocket;
lock (lck) {
ClientID = ++id;
}
}
public async Task Receive() {
byte[] buffer = new byte[2048];
int len = await socket.ReceiveAsync(buffer, SocketFlags.None);
if (len == 0)
throw new SocketException();
socketBuffer.Write(buffer, len);
}
public bool TryGetNextPacket(out NetworkPacket packet) {
return socketBuffer.ReadPacket(out packet);
}
public void Send(NetworkPacket packet) {
try {
socket.Send(packet.SendData);
} catch (SocketException) {
ScheduleDisconnect();
}
}
public void SetRoom(Room? room) {
lock(clientLock) {
// set variable player data as not valid, but do not reset all player data
PlayerData.IsValid = false;
if (Room != null) {
Console.WriteLine($"Leave room: {Room.Name} (id={Room.Id}, size={Room.ClientsCount}) IID: {ClientID}");
Room.RemoveClient(this);
NetworkObject data = new();
data.Add("r", Room.Id);
data.Add("u", ClientID);
Room.Send(NetworkObject.WrapObject(0, 1004, data).Serialize());
}
// set new room (null when SetRoom is used as LeaveRoom)
Room = room;
if (Room != null) {
Console.WriteLine($"Join room: {Room.Name} RoomID (id={Room.Id}, size={Room.ClientsCount}) IID: {ClientID}");
Room.AddClient(this);
Send(Room.SubscribeRoom());
UpdatePlayerUserVariables();
}
}
}
private void UpdatePlayerUserVariables() {
foreach (Client c in Room.Clients) {
NetworkObject cmd = new();
NetworkObject obj = new();
cmd.Add("c", "SUV");
if (OldApi) {
obj.Add("MID", c.ClientID.ToString());
} else {
obj.Add("MID", c.ClientID);
}
cmd.Add("p", obj);
Send(NetworkObject.WrapObject(1, 13, cmd).Serialize());
}
}
public void Disconnect() {
try {
socket.Shutdown(SocketShutdown.Both);
} finally {
socket.Close();
}
}
public void ScheduleDisconnect() {
if (Room != null) {
// quiet remove from room (to avoid issues in Room.Send)
// - do not change Room value here
// - full remove will be will take place Server.HandleClient (before real disconnected)
Room.RemoveClient(this);
}
scheduledDisconnect = true;
}
public bool Connected {
get {
return socket.Connected && !scheduledDisconnect;
}
}
}