// 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 _queue = new(); private readonly List _sessionsAll = new(); private bool _disposed; public IReadOnlyList Sessions { get { _lock.EnterReadLock(); try { return _sessionsAll.ToArray(); } finally { _lock.ExitReadLock(); } } } public void Broadcast(string packet) { _queue.Enqueue(packet); } public void Broadcast(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 packets) { foreach (string packet in packets) { _queue.Enqueue(packet); } } public void Broadcast(IEnumerable 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 generatePacketCallback) { _lock.EnterReadLock(); try { foreach (IClientSession session in _sessionsAll) { session.SendPacket(generatePacketCallback(session)); } } finally { _lock.ExitReadLock(); } } public void Broadcast(Func 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> lambdaAsync) { _lock.EnterReadLock(); try { foreach (IClientSession session in _sessionsAll) { session.SendPacket(await lambdaAsync(session)); } } finally { _lock.ExitReadLock(); } } public async Task BroadcastAsync(Func> 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 packet) where T : IPacket { Broadcast(Serializer.Serialize(packet)); } protected void FlushPackets() { var packets = new List(); 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(); } } }