server-master/srcs/WingsAPI.Game/Networking/SessionsContainer.cs
2026-02-10 18:21:30 +01:00

303 lines
No EOL
7 KiB
C#

// WingsEmu
//
// Developed by NosWings Team
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using WingsEmu.Game.Networking.Broadcasting;
using WingsEmu.Packets;
namespace WingsEmu.Game.Networking;
public abstract class SessionsContainer : IBroadcaster
{
private static readonly IPacketSerializer Serializer = new PacketSerializer();
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion);
private readonly ConcurrentQueue<string> _queue = new();
private readonly List<IClientSession> _sessionsAll = new();
private bool _disposed;
public IReadOnlyList<IClientSession> Sessions
{
get
{
_lock.EnterReadLock();
try
{
return _sessionsAll.ToArray();
}
finally
{
_lock.ExitReadLock();
}
}
}
public void Broadcast(string packet)
{
_queue.Enqueue(packet);
}
public void Broadcast<T>(T packet, params IBroadcastRule[] rules) where T : IServerPacket
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
bool all = true;
foreach (IBroadcastRule x in rules)
{
if (!x.Match(session))
{
all = false;
break;
}
}
if (!rules.Any() || all)
{
session.SendPacket(packet);
}
}
}
finally
{
_lock.ExitReadLock();
}
}
public void Broadcast(string packet, params IBroadcastRule[] rules)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
bool all = true;
foreach (IBroadcastRule x in rules)
{
if (!x.Match(session))
{
all = false;
break;
}
}
if (!rules.Any() || all)
{
session.SendPacket(packet);
}
}
}
finally
{
_lock.ExitReadLock();
}
}
public void Broadcast(IEnumerable<string> packets)
{
foreach (string packet in packets)
{
_queue.Enqueue(packet);
}
}
public void Broadcast(IEnumerable<string> packets, params IBroadcastRule[] rules)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
bool all = true;
foreach (IBroadcastRule x in rules)
{
if (!x.Match(session))
{
all = false;
break;
}
}
if (!rules.Any() || all)
{
session.SendPackets(packets);
}
}
}
finally
{
_lock.ExitReadLock();
}
}
public void Broadcast(Func<IClientSession, string> generatePacketCallback)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
session.SendPacket(generatePacketCallback(session));
}
}
finally
{
_lock.ExitReadLock();
}
}
public void Broadcast(Func<IClientSession, string> generatePacketCallback, params IBroadcastRule[] rules)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
bool all = true;
foreach (IBroadcastRule x in rules)
{
if (x.Match(session))
{
continue;
}
all = false;
break;
}
if (!rules.Any() || all)
{
session.SendPacket(generatePacketCallback(session));
}
}
}
finally
{
_lock.ExitReadLock();
}
}
public async Task BroadcastAsync(Func<IClientSession, Task<string>> lambdaAsync)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
session.SendPacket(await lambdaAsync(session));
}
}
finally
{
_lock.ExitReadLock();
}
}
public async Task BroadcastAsync(Func<IClientSession, Task<string>> generatePacketCallback, params IBroadcastRule[] rules)
{
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
bool all = true;
foreach (IBroadcastRule x in rules)
{
if (!x.Match(session))
{
all = false;
break;
}
}
if (!rules.Any() || all)
{
session.SendPacket(await generatePacketCallback(session));
}
}
}
finally
{
_lock.ExitReadLock();
}
}
public void Broadcast<T>(T packet) where T : IPacket
{
Broadcast(Serializer.Serialize(packet));
}
protected void FlushPackets()
{
var packets = new List<string>();
while (_queue.TryDequeue(out string packet))
{
packets.Add(packet);
}
_lock.EnterReadLock();
try
{
foreach (IClientSession session in _sessionsAll)
{
session.SendPackets(packets);
}
}
finally
{
_lock.ExitReadLock();
}
}
public virtual void Dispose()
{
if (_disposed)
{
return;
}
GC.SuppressFinalize(this);
_disposed = true;
}
public virtual void RegisterSession(IClientSession session)
{
if (!session.HasSelectedCharacter)
{
return;
}
_lock.EnterWriteLock();
try
{
_sessionsAll.Add(session);
}
finally
{
_lock.ExitWriteLock();
}
}
public virtual void UnregisterSession(IClientSession session)
{
_lock.EnterWriteLock();
try
{
_sessionsAll.Remove(session);
}
finally
{
_lock.ExitWriteLock();
}
}
}