57 lines
2.2 KiB
C#
57 lines
2.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace XWorld.Server.Gateway
|
|
{
|
|
// pid -> Session。只在 actor 线程被改,故无锁。
|
|
public sealed class SessionManager
|
|
{
|
|
private readonly Dictionary<int, Session> _byPid = new Dictionary<int, Session>();
|
|
|
|
public Session OnConnect(int pid, IClientConnection conn)
|
|
{
|
|
if (_byPid.TryGetValue(pid, out var s))
|
|
{
|
|
s.Connection = conn; // 重连:重绑新连接,保留 RoomId
|
|
s.Connected = true;
|
|
return s;
|
|
}
|
|
s = new Session { PlayerId = pid, Connection = conn, Connected = true };
|
|
_byPid[pid] = s;
|
|
return s;
|
|
}
|
|
|
|
public void OnDisconnect(int pid, IClientConnection conn, long currentTick)
|
|
{
|
|
// 仅当断的是"当前连接"才标离线,避免旧连接的迟到断线清掉已重连的新连接
|
|
if (_byPid.TryGetValue(pid, out var s) && ReferenceEquals(s.Connection, conn))
|
|
{
|
|
s.Connected = false;
|
|
s.DisconnectedAtTick = currentTick;
|
|
}
|
|
}
|
|
|
|
public IClientConnection GetConnection(int pid)
|
|
=> _byPid.TryGetValue(pid, out var s) && s.Connected ? s.Connection : null;
|
|
|
|
public bool IsConnected(int pid) => _byPid.TryGetValue(pid, out var s) && s.Connected;
|
|
|
|
public Session Get(int pid) => _byPid.TryGetValue(pid, out var s) ? s : null;
|
|
|
|
/// <summary>移除断线且"严格越过"重连窗口的会话(currentTick - DisconnectedAtTick > windowTicks)。返回被移除的会话;无则空数组。</summary>
|
|
public IReadOnlyList<Session> SweepExpired(long currentTick, long windowTicks)
|
|
{
|
|
List<Session> removed = null;
|
|
foreach (var kv in _byPid)
|
|
{
|
|
var s = kv.Value;
|
|
if (!s.Connected && currentTick - s.DisconnectedAtTick > windowTicks)
|
|
(removed ??= new List<Session>()).Add(s);
|
|
}
|
|
if (removed != null)
|
|
foreach (var s in removed) _byPid.Remove(s.PlayerId);
|
|
return removed ?? (IReadOnlyList<Session>)Array.Empty<Session>();
|
|
}
|
|
}
|
|
}
|