fix client stay in room and add Room.Send

- fix client stay in room:
  - replace Client.JoinRoom and Client.LeaveRoom by Client.SetRoom
  - do not call Client.LeaveRoom / Client.SetRoom(null) for SheduleDisconnect cases
    (only quietly remove client from room and the rest do in disconnect realisation)
- add Room.Send for send message to all clients in room
  - replace Room.Client sending loops by calls Room.Send
This commit is contained in:
Robert Paciorek 2024-03-24 21:29:57 +00:00
parent fa0870784a
commit 82e83722da
16 changed files with 81 additions and 127 deletions

View File

@ -35,11 +35,7 @@ class ChatMessageHandler : ICommandHandler {
cmd.Add("p", data); cmd.Add("p", data);
NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet, client);
if (roomClient != client) {
roomClient.Send(packet);
}
}
cmd = new(); cmd = new();
data = new(); data = new();

View File

@ -7,6 +7,6 @@ namespace sodoffmmo.CommandHandlers;
[CommandHandler(26)] [CommandHandler(26)]
class ExitHandler : ICommandHandler { class ExitHandler : ICommandHandler {
public void Handle(Client client, NetworkObject receivedObject) { public void Handle(Client client, NetworkObject receivedObject) {
client.LeaveRoom(); client.SetRoom(null);
} }
} }

View File

@ -39,10 +39,7 @@ class GauntletPlayAgainHandler : ICommandHandler
client.PlayerData.Uid client.PlayerData.Uid
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
room.SendPA(client); room.SendPA(client);
} }
} }
@ -61,9 +58,7 @@ class GauntletLobbyUserReadyHandler : ICommandHandler
client.PlayerData.Uid client.PlayerData.Uid
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
if (room.GetReadyCount() > 1) { if (room.GetReadyCount() > 1) {
packet = Utils.ArrNetworkPacket(new string[] { packet = Utils.ArrNetworkPacket(new string[] {
@ -72,9 +67,7 @@ class GauntletLobbyUserReadyHandler : ICommandHandler
client.PlayerData.Uid client.PlayerData.Uid
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
} }
} }
} }
@ -93,9 +86,7 @@ class GauntletLobbyUserNotReadyHandler : ICommandHandler
client.PlayerData.Uid client.PlayerData.Uid
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
} }
} }
@ -114,10 +105,7 @@ class GauntletLevelLoadHandler : ICommandHandler
p.Get<string>("1"), p.Get<string>("1"),
p.Get<string>("2") // TODO use size of p.fields - 1 p.Get<string>("2") // TODO use size of p.fields - 1
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
} }
} }
@ -139,9 +127,7 @@ class GauntletLevelLoadedHandler : ICommandHandler
room.Id.ToString(), room.Id.ToString(),
(--counter).ToString() (--counter).ToString()
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
timer = new System.Timers.Timer(1500); timer = new System.Timers.Timer(1500);
timer.AutoReset = true; timer.AutoReset = true;
@ -169,9 +155,7 @@ class GauntletLevelLoadedHandler : ICommandHandler
timer!.Close(); timer!.Close();
timer = null; timer = null;
} }
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
} }
} }
@ -191,10 +175,7 @@ class GauntletRelayGameDataHandler : ICommandHandler
p.Get<string>("0"), p.Get<string>("0"),
p.Get<string>("1") p.Get<string>("1")
}, "msg", room.Id); }, "msg", room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
} }
} }

View File

@ -8,7 +8,6 @@ namespace sodoffmmo.CommandHandlers;
class GenericMessageHandler : ICommandHandler { class GenericMessageHandler : ICommandHandler {
public void Handle(Client client, NetworkObject receivedObject) { public void Handle(Client client, NetworkObject receivedObject) {
NetworkPacket packet = NetworkObject.WrapObject(0, 7, receivedObject).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(0, 7, receivedObject).Serialize();
foreach (var roomClient in client.Room.Clients) client.Room.Send(packet);
roomClient.Send(packet);
} }
} }

View File

@ -11,7 +11,6 @@ class JoinRoomHandler : ICommandHandler
{ {
string roomName = receivedObject.Get<NetworkObject>("p").Get<string>("rn"); string roomName = receivedObject.Get<NetworkObject>("p").Get<string>("rn");
Room room = Room.GetOrAdd(roomName); Room room = Room.GetOrAdd(roomName);
Console.WriteLine($"Join Room: {roomName} RoomID: {room.Id} IID: {client.ClientID}"); client.SetRoom(room);
client.JoinRoom(room);
} }
} }

View File

@ -24,8 +24,6 @@ class RacingPMHandler : ICommandHandler
cmd.Add("p", p); cmd.Add("p", p);
NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet);
roomClient.Send(packet);
}
} }
} }

View File

@ -58,9 +58,7 @@ class RacingARACKHandler : ICommandHandler
if (room.GetPlayersCount(RacingPlayerState.RaceReady2) == room.ClientsCount) { if (room.GetPlayersCount(RacingPlayerState.RaceReady2) == room.ClientsCount) {
NetworkPacket packet = room.GetSTAPacket(); NetworkPacket packet = room.GetSTAPacket();
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
Console.WriteLine($"STA"); Console.WriteLine($"STA");
} }
} }

View File

@ -59,11 +59,7 @@ class SetPositionVariablesHandler : ICommandHandler {
cmd.Add("c", "SPV"); cmd.Add("c", "SPV");
cmd.Add("p", obj); cmd.Add("p", obj);
NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
} }
} }

View File

@ -11,6 +11,12 @@ class SetUserVariablesHandler : ICommandHandler {
Client client; Client client;
string? uid; string? uid;
public void Handle(Client client, NetworkObject receivedObject) { public void Handle(Client client, NetworkObject receivedObject) {
if (client.Room == null) {
Console.WriteLine($"SUV Missing Room IID: {client.ClientID}");
client.Send(NetworkObject.WrapObject(0, 1006, new NetworkObject()).Serialize());
client.SheduleDisconnect();
return;
}
this.client = client; this.client = client;
suvData = receivedObject.Get<NetworkObject>("p"); suvData = receivedObject.Get<NetworkObject>("p");
uid = suvData.Get<string>("UID"); uid = suvData.Get<string>("UID");
@ -90,8 +96,7 @@ class SetUserVariablesHandler : ICommandHandler {
data.Add("vl", vl); data.Add("vl", vl);
NetworkPacket packet = NetworkObject.WrapObject(0, 12, data).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(0, 12, data).Serialize();
foreach (var roomClient in client.Room.Clients) client.Room.Send(packet);
roomClient.Send(packet);
NetworkObject cmd = new(); NetworkObject cmd = new();
cmd.Add("c", "SUV"); cmd.Add("c", "SUV");
@ -105,10 +110,7 @@ class SetUserVariablesHandler : ICommandHandler {
container.Add("arr", arr); container.Add("arr", arr);
cmd.Add("p", container); cmd.Add("p", container);
packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
} }
private void UpdatePlayersInRoom() { private void UpdatePlayersInRoom() {
@ -129,10 +131,7 @@ class SetUserVariablesHandler : ICommandHandler {
NetworkPacket packet = NetworkObject.WrapObject(0, 1000, data).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(0, 1000, data).Serialize();
packet.Compress(); packet.Compress();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
} }
private void SendSUVToPlayerInRoom() { private void SendSUVToPlayerInRoom() {
@ -144,9 +143,6 @@ class SetUserVariablesHandler : ICommandHandler {
cmd.Add("p", obj); cmd.Add("p", obj);
NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
foreach (var roomClient in client.Room.Clients) { client.Room.Send(packet, client);
if (roomClient != client)
roomClient.Send(packet);
}
} }
} }

View File

@ -37,9 +37,7 @@ class WorldEventHealthHandler : ICommandHandler {
health.ToString("0.0#####", CultureInfo.GetCultureInfo("en-US")) + "," + DateTime.UtcNow.ToString("ddd MMM dd HH:mm:ss UTC yyyy", CultureInfo.GetCultureInfo("en-US")), health.ToString("0.0#####", CultureInfo.GetCultureInfo("en-US")) + "," + DateTime.UtcNow.ToString("ddd MMM dd HH:mm:ss UTC yyyy", CultureInfo.GetCultureInfo("en-US")),
WorldEvent.Get().GetRoom().Id WorldEvent.Get().GetRoom().Id
); );
foreach (var roomClient in WorldEvent.Get().GetRoom().Clients) { WorldEvent.Get().GetRoom().Send(packet);
roomClient.Send(packet);
}
} }
} }
} }
@ -59,9 +57,7 @@ class WorldEventFlareHandler : ICommandHandler {
p.Get<string>("oh") + "," + p.Get<string>("ts"), p.Get<string>("oh") + "," + p.Get<string>("ts"),
WorldEvent.Get().GetRoom().Id WorldEvent.Get().GetRoom().Id
); );
foreach (var roomClient in WorldEvent.Get().GetRoom().Clients) { WorldEvent.Get().GetRoom().Send(packet);
roomClient.Send(packet);
}
} }
} }
@ -82,9 +78,7 @@ class WorldEventMissileHandler : ICommandHandler {
p.Get<string>("tID"), p.Get<string>("tID"),
p.Get<string>("objID") p.Get<string>("objID")
}); });
foreach (var roomClient in WorldEvent.Get().GetRoom().Clients) { WorldEvent.Get().GetRoom().Send(packet);
roomClient.Send(packet);
}
} }
} }

View File

@ -1,6 +1,7 @@
using sodoffmmo.Data; using sodoffmmo.Data;
using System; using System;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.CompilerServices;
namespace sodoffmmo.Core; namespace sodoffmmo.Core;
public class Client { public class Client {
@ -9,12 +10,12 @@ public class Client {
public int ClientID { get; private set; } public int ClientID { get; private set; }
public PlayerData PlayerData { get; set; } = new(); public PlayerData PlayerData { get; set; } = new();
public Room Room { get; private set; } public Room? Room { get; private set; }
private readonly Socket socket; private readonly Socket socket;
SocketBuffer socketBuffer = new(); SocketBuffer socketBuffer = new();
private volatile bool scheduledDisconnect = false; private volatile bool scheduledDisconnect = false;
private object ClientLock = new(); private readonly object clientLock = new();
public Client(Socket clientSocket) { public Client(Socket clientSocket) {
socket = clientSocket; socket = clientSocket;
@ -39,36 +40,36 @@ public class Client {
try { try {
socket.Send(packet.SendData); socket.Send(packet.SendData);
} catch (SocketException) { } catch (SocketException) {
LeaveRoom();
SheduleDisconnect(); SheduleDisconnect();
} }
} }
public void LeaveRoom() { public void SetRoom(Room? room) {
if (Room != null) { lock(clientLock) {
Console.WriteLine($"Leave room {Room.Name} IID: {ClientID}"); // set variable player data as not valid, but do not reset all player data
Room.RemoveClient(this);
NetworkObject data = new();
data.Add("r", Room.Id);
data.Add("u", ClientID);
NetworkPacket packet = NetworkObject.WrapObject(0, 1004, data).Serialize();
foreach (var roomClient in Room.Clients) {
roomClient.Send(packet);
}
Room = null;
}
}
public void JoinRoom(Room room) {
lock(ClientLock) {
LeaveRoom();
PlayerData.IsValid = false; 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; Room = room;
Room.AddClient(this);
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();
}
} }
Send(Room.SubscribeRoom());
UpdatePlayerUserVariables();
} }
private void UpdatePlayerUserVariables() { private void UpdatePlayerUserVariables() {
@ -91,6 +92,12 @@ public class Client {
} }
public void SheduleDisconnect() { public void SheduleDisconnect() {
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; scheduledDisconnect = true;
} }

View File

@ -65,9 +65,7 @@ public class GauntletRoom : Room {
} }
NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "msg", base.Id); NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "msg", base.Id);
foreach(var player in players) { Send(packet);
player.Key.Send(packet);
}
} }
public void SendPA(Client client) { public void SendPA(Client client) {
@ -112,10 +110,7 @@ public class GauntletRoom : Room {
} }
NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "msg", base.Id); NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "msg", base.Id);
foreach(var player in players) { Send(packet);
player.Key.Send(packet);
}
return true; return true;
} }
} }
@ -127,8 +122,8 @@ public class GauntletRoom : Room {
if (room is null) if (room is null)
room = GauntletRoom.Get(); room = GauntletRoom.Get();
room.AddPlayer(client); // must be call before JoinRoom (before InvalidatePlayerData) - we need uid client.SetRoom(room);
client.JoinRoom(room); room.AddPlayer(client); // client will be not removed from GauntletRoom.players ... after remove all client from room whole GauntletRoom.players will be removed
room.SendUJR(); room.SendUJR();
} }
} }

View File

@ -94,9 +94,7 @@ public class RacingRoom : Room {
} }
NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "", Id); NetworkPacket packet = Utils.ArrNetworkPacket(info.ToArray(), "", Id);
foreach (var roomClient in Clients) { Send(packet);
roomClient.Send(packet);
}
} }
} }
@ -124,8 +122,7 @@ public class RacingRoom : Room {
private void SendJoin(Object? source, ElapsedEventArgs e) { private void SendJoin(Object? source, ElapsedEventArgs e) {
foreach(var player in players) { foreach(var player in players) {
Console.WriteLine($"Join Racing Room: {Name} RoomID: {Id} IID: {player.Key.ClientID}"); player.Key.SetRoom(this);
player.Key.JoinRoom(this);
} }
SetTimer(1, CountDown, true); SetTimer(1, CountDown, true);
} }
@ -142,9 +139,7 @@ public class RacingRoom : Room {
"LT", "LT",
(--counter).ToString() (--counter).ToString()
}, "", Id); }, "", Id);
foreach (var roomClient in Clients) { Send(packet);
roomClient.Send(packet);
}
} }
} }
} }
@ -167,9 +162,7 @@ public class RacingRoom : Room {
"", "",
"ST" "ST"
}, "", Id); }, "", Id);
foreach (var roomClient in Clients) { Send(packet);
roomClient.Send(packet);
}
} }
// TODO StratTimer → kick out to main lobby players without RacingPlayerState.RaceReady1 after timeout, next kick out players without RacingPlayerState.RaceReady2 after timeout2 // TODO StratTimer → kick out to main lobby players without RacingPlayerState.RaceReady1 after timeout, next kick out players without RacingPlayerState.RaceReady2 after timeout2

View File

@ -66,6 +66,14 @@ public class Room {
} }
} }
public void Send(NetworkPacket packet, Client? skip = null) {
foreach (var roomClient in clients) {
if (roomClient != skip) {
roomClient.Send(packet);
}
}
}
public static bool Exists(string name) => rooms.ContainsKey(name); public static bool Exists(string name) => rooms.ContainsKey(name);
public static Room Get(string name) => rooms[name]; public static Room Get(string name) => rooms[name];
@ -99,7 +107,7 @@ public class Room {
roomInfo.Add((short)0); // max spectator count roomInfo.Add((short)0); // max spectator count
NetworkArray userList = new(); NetworkArray userList = new();
foreach (Client player in Clients) { foreach (Client player in clients) {
if (player.PlayerData.Uid != "") if (player.PlayerData.Uid != "")
userList.Add(player.PlayerData.GetNetworkData(player.ClientID, out _)); userList.Add(player.PlayerData.GetNetworkData(player.ClientID, out _));
} }

View File

@ -160,9 +160,7 @@ class WorldEvent {
lastResults, lastResults,
room.Id room.Id
); );
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
NetworkArray vl = new(); NetworkArray vl = new();
vl.Add(NetworkArray.VlElement("WE__AI", NetworkArray.NULL)); vl.Add(NetworkArray.VlElement("WE__AI", NetworkArray.NULL));
@ -171,9 +169,7 @@ class WorldEvent {
vl.Add(NetworkArray.VlElement("WEF_" + t.Key, NetworkArray.NULL)); vl.Add(NetworkArray.VlElement("WEF_" + t.Key, NetworkArray.NULL));
} }
packet = Utils.VlNetworkPacket(vl, room.Id); packet = Utils.VlNetworkPacket(vl, room.Id);
foreach (var roomClient in room.Clients) { room.Send(packet);
roomClient.Send(packet);
}
Console.WriteLine($"Event {uid} sent _End"); Console.WriteLine($"Event {uid} sent _End");
@ -206,9 +202,7 @@ class WorldEvent {
Console.WriteLine($"Event {uid} send event notification (WE_ = {(WE ? startTimeString : WE)} WEN_ = {(WEN ? nextStartTimeString : WEN)}, room = {room.Id}) to all clients"); Console.WriteLine($"Event {uid} send event notification (WE_ = {(WE ? startTimeString : WE)} WEN_ = {(WEN ? nextStartTimeString : WEN)}, room = {room.Id}) to all clients");
NetworkPacket packet = Utils.VlNetworkPacket(EventInfoArray(WE, WEN), room.Id); NetworkPacket packet = Utils.VlNetworkPacket(EventInfoArray(WE, WEN), room.Id);
foreach (var r in Room.AllRooms()) { foreach (var r in Room.AllRooms()) {
foreach (var roomClient in r.Clients) { r.Send(packet);
roomClient.Send(packet);
}
} }
} }

View File

@ -53,7 +53,7 @@ public class Server {
} }
} finally { } finally {
try { try {
client.LeaveRoom(); client.SetRoom(null);
} catch (Exception) { } } catch (Exception) { }
client.Disconnect(); client.Disconnect();
Console.WriteLine("Socket disconnected IID: " + client.ClientID); Console.WriteLine("Socket disconnected IID: " + client.ClientID);