303 lines
No EOL
7 KiB
C#
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();
|
|
}
|
|
}
|
|
} |