163 lines
4.5 KiB
C#
163 lines
4.5 KiB
C#
namespace GameServer.Contents.GameMode.Helper;
|
|
|
|
using Nettention.Proud;
|
|
|
|
public class PingLatencyPolicy
|
|
{
|
|
public int PingKickThreshold { get; set; } = 600;
|
|
public TimeSpan PingKickDuration { get; set; } = TimeSpan.FromSeconds(30);
|
|
}
|
|
|
|
//=====================================================================
|
|
// LatencyChecker - 플레이가 불가능한 핑 지연을 체크한다. super peer와의 핑을 체크
|
|
//=====================================================================
|
|
public class PingLatencyKicker
|
|
{
|
|
public class ClientLatency
|
|
{
|
|
public HostID HostId { get; set; }
|
|
public int PingSum { get; set; }
|
|
public int PingCheckCount { get; set; }
|
|
public DateTime PingCheckBeginTime { get; set; } = DateTime.UtcNow;
|
|
public int PingAverage => PingCheckCount > 0 ? PingSum / PingCheckCount: 0;
|
|
}
|
|
|
|
private readonly PingLatencyPolicy m_ping_latency_policy;
|
|
private readonly SortedList<HostID, ClientLatency> m_host_latencies = new();
|
|
private HostID m_group_id;
|
|
private HostID m_super_peer_id;
|
|
private readonly NetServer m_server;
|
|
|
|
public PingLatencyKicker(NetServer server, PingLatencyPolicy pingLatencyPolicy)
|
|
{
|
|
m_ping_latency_policy = pingLatencyPolicy;
|
|
m_server = server;
|
|
}
|
|
|
|
public void setGroupHostId(HostID groupId)
|
|
{
|
|
m_group_id = groupId;
|
|
}
|
|
|
|
public void setSuperPeerId(HostID superPeerId)
|
|
{
|
|
m_super_peer_id = superPeerId;
|
|
}
|
|
|
|
//=================================================================
|
|
// 호스트 그룹에 속한 클라이언트의 핑 지연을 체크하여, 게임이 불가한 지연이 발생한 경우 해당 호스트를 반환
|
|
//==============================================================
|
|
public IEnumerable<HostID> shouldKick()
|
|
{
|
|
if (!isValidGroup())
|
|
{
|
|
return [];
|
|
}
|
|
|
|
checkAndValidateSuperPeer();
|
|
|
|
if (!isValidSuperPeer())
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var kick_host_ids = getGroupMemberHostIds().Where(x => checkLatency(x) == true);
|
|
return kick_host_ids;
|
|
}
|
|
|
|
public async Task<IEnumerable<HostID>> shouldKickAsync()
|
|
{
|
|
return await Task.Run(shouldKick);
|
|
}
|
|
|
|
//=================================================================
|
|
// 핑 지연 체크
|
|
//=================================================================
|
|
private bool checkLatency(HostID hostId)
|
|
{
|
|
var ping_to_super_peer = getP2PRecentPingMs(hostId);
|
|
m_host_latencies.TryGetValue(hostId, out var client_latency);
|
|
if (ping_to_super_peer > m_ping_latency_policy.PingKickThreshold)
|
|
{
|
|
if (client_latency == null)
|
|
{
|
|
client_latency = new ClientLatency
|
|
{
|
|
HostId = hostId, PingSum = 0, PingCheckCount = 0, PingCheckBeginTime = DateTime.UtcNow
|
|
};
|
|
m_host_latencies.Add(hostId, client_latency);
|
|
}
|
|
}
|
|
|
|
if (client_latency != null)
|
|
{
|
|
if (client_latency.PingCheckBeginTime + m_ping_latency_policy.PingKickDuration > DateTime.UtcNow)
|
|
{
|
|
if (client_latency.PingAverage > m_ping_latency_policy.PingKickThreshold)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
m_host_latencies.Remove(hostId);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private int getP2PRecentPingMs(HostID hostId)
|
|
{
|
|
return m_server.GetP2PRecentPingMs(hostId, m_super_peer_id);
|
|
}
|
|
|
|
private IEnumerable<HostID> getGroupMemberHostIds()
|
|
{
|
|
var host_ids = new List<HostID>();
|
|
var group_info = m_server.GetP2PGroupInfo(m_group_id);
|
|
for (int i = 0; i < group_info.members.GetCount(); i++)
|
|
{
|
|
host_ids.Add(group_info.members.At(i));
|
|
}
|
|
|
|
return host_ids;
|
|
}
|
|
|
|
//=================================================================
|
|
// 호스트 그룹이 삭제됐는 지 확인
|
|
//=================================================================
|
|
private bool isValidGroup()
|
|
{
|
|
if (m_group_id == HostID.HostID_None)
|
|
return false;
|
|
|
|
var group_info = m_server.GetP2PGroupInfo(m_group_id);
|
|
if (group_info == null || group_info.members.GetCount() == 0)
|
|
{
|
|
m_group_id = HostID.HostID_None;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//=================================================================
|
|
// 수퍼 피어가 퇴장한 경우 등을 체크
|
|
//=================================================================
|
|
private void checkAndValidateSuperPeer()
|
|
{
|
|
// 수퍼 피어가 퇴장한 경우 등을 체크
|
|
if (m_super_peer_id != HostID.HostID_None && m_server.GetClientInfo(m_super_peer_id) == null)
|
|
{
|
|
m_super_peer_id = HostID.HostID_None;
|
|
}
|
|
}
|
|
|
|
//=================================================================
|
|
// 수퍼 피어가 설정되어 있는지 체크
|
|
//=================================================================
|
|
private bool isValidSuperPeer()
|
|
{
|
|
return m_super_peer_id != HostID.HostID_None;
|
|
}
|
|
}
|