초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
using Nettention.Proud;
namespace GameServer;
public interface IHostMigrator
{
public Result defineHost(HostID p2pGroupId, SuperPeerSelectionPolicy policy, HostID[] excludees);
public Result modifyHost(string userGuid);
public Result removeHost();
public string getHostUserGuid();
public (Result, bool) migrateCheck(bool ignoreInterval = false);
public void setGroupHostId(HostID groupId);
}

View File

@@ -0,0 +1,19 @@
namespace GameServer;
public interface IP2PDataLogState
{
public void enter()
{
//상태에 처음 진입할 때 실행되는 코드
}
public Task update()
{
return Task.CompletedTask;
}
public void exit()
{
// 마무리 필요할때 처리해주는 로직
}
public bool getActive();
}

View File

@@ -0,0 +1,90 @@
using System.Collections.Concurrent;
using Newtonsoft.Json;
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer;
public class P2PDataAction : EntityActionBase
{
//단순 p2p 데이터 기록을 위한 Action
public ConcurrentDictionary<UInt32, P2PPacketSummery> m_data { get; set; } = new();
public DateTime m_next_logging_time { get; set; } = DateTimeHelper.Current;
public DateTime m_last_update_time { get; set; } = DateTimeHelper.Current;
readonly Int32 m_logging_time_interval_sec;
public P2PDataAction(Player owner) : base(owner)
{
m_logging_time_interval_sec = 30;
}
public override void onClear()
{
return;
}
public override async Task<Result> onInit()
{
await Task.CompletedTask;
var result = new Result();
return result;
}
public async Task<Result> accumulateP2PData(UInt32 packetId, byte[] array)
{
if (false == m_data.TryGetValue(packetId, out var summery))
{
summery = new P2PPacketSummery(array.Length);
}
summery.accumulateData(array.Length);
m_data[packetId] = summery;
var now = DateTimeHelper.Current;
m_last_update_time = now;
if (m_next_logging_time <= now)
{
Log.getLogger().info($"P2P Packet Data received total : {JsonConvert.SerializeObject(m_data)}");
m_next_logging_time = m_next_logging_time.AddSeconds(m_logging_time_interval_sec);
}
if (P2PDataLogManager.It.logActive() == false)
{
await P2PDataLogManager.It.activeMonitoring();
}
var result = new Result();
return result;
}
}
public class P2PPacketSummery
{
public long m_packet_count { get; set; } = 0;
public long m_total_packet_size { get; set; } = 0;
public P2PPacketSummery(long packetSize)
{
m_packet_count = 1;
m_total_packet_size = packetSize;
}
public P2PPacketSummery(long packetCount, long packetSize)
{
m_packet_count = packetCount;
m_total_packet_size = packetSize;
}
public void accumulateData(long packetSize)
{
m_packet_count += 1;
m_total_packet_size += packetSize;
}
}

View File

@@ -0,0 +1,63 @@
using System.Collections.Concurrent;
using NeoSmart.AsyncLock;
using ServerCore;
using ServerCommon;
namespace GameServer;
public class P2PDataInfoLog
{
public long m_total_packet_count { get; set; } = 0;
public long m_total_packet_size { get; set; } = 0;
public DateTime m_last_recorded_time { get; set; } = DateTimeHelper.Current;
}
public class P2PDataLogManager : Singleton<P2PDataLogManager>
{
public DateTime m_last_check_time { get; set; } = DateTimeHelper.Current;
private AsyncLock m_async_lock = new(); //state 바꿀때 사용
private IP2PDataLogState m_current_log_state;
public P2PDataLogManager()
{
m_current_log_state = new P2PDataWriteIdleState();
m_current_log_state.enter();
}
public void changeLogWriteState(IP2PDataLogState nextState)
{
m_current_log_state.exit();
m_current_log_state = nextState;
m_current_log_state.enter();
}
public async Task activeMonitoring()
{
if (m_current_log_state.getActive()) return;
using (var _ = await getAsyncLock())
{
if (m_current_log_state.getActive()) return;
changeLogWriteState(new P2PDataWriteState());
}
}
public async Task inactiveMonitoring()
{
if (m_current_log_state.getActive() == false) return;
using (var releaser = await getAsyncLock())
{
if (m_current_log_state.getActive() == false) return;
changeLogWriteState(new P2PDataWriteIdleState());
}
}
public async Task<IDisposable> getAsyncLock() => await m_async_lock.LockAsync();
public bool logActive() => m_current_log_state.getActive();
}

View File

@@ -0,0 +1,16 @@
namespace GameServer;
public abstract class P2PDataLogStateBase : IP2PDataLogState
{
protected readonly bool m_is_active = false;
public P2PDataLogStateBase(bool isActive)
{
m_is_active = isActive;
}
public abstract void enter();
public abstract Task update();
public abstract void exit();
public bool getActive() => m_is_active;
}

View File

@@ -0,0 +1,27 @@
using ServerCore;
namespace GameServer;
public class P2PDataWriteIdleState : P2PDataLogStateBase
{
public P2PDataWriteIdleState() : base(false)
{
}
public override void enter()
{
Log.getLogger().debug("P2PDataWriteIdleState enter");
}
public override Task update()
{
//update 로직.
Log.getLogger().debug("P2PDataWriteIdleState update");
return Task.CompletedTask;
}
public override void exit()
{
// 마무리 필요할때 처리해주는 로직
Log.getLogger().debug("P2PDataWriteIdleState exit");
}
}

View File

@@ -0,0 +1,186 @@
using System.Collections.Concurrent;
using ServerCommon;
using ServerCore;
namespace GameServer;
public class P2PDataWriteState : P2PDataLogStateBase
{
private ConcurrentDictionary<string /*user_guid*/, P2PDataInfoLog> m_all_user_p2p_packet_infos = new();
private CancellationTokenSource m_cancel_token = new();
public DateTime m_last_check_time { get; set; } = DateTimeHelper.Current;
readonly int m_record_check_time_min = 1;
private PeriodicTaskTimer? m_task_nullable = null;
public P2PDataWriteState() : base(true)
{
}
public override void enter()
{
try
{
m_cancel_token = new();
m_task_nullable = new PeriodicTaskTimer( GetType().Name, Constant.P2P_PACKET_DATA_CHECK_INTERVAL_MSEC, m_cancel_token, onTaskTick);
Log.getLogger().debug("activeMonitoring task created");
}
catch(Exception e)
{
var err_msg = $"Exception !!!, new PeriodicTaskTimer() : exception:{e}";
Log.getLogger().error(err_msg);
}
}
public override async Task update()
{
//if (m_check_active == false) return;
Log.getLogger().debug("p2p monitoring update start");
var users = GameServerApp.getServerLogic().getPlayerManager().getUsers();
foreach (var player in users.Values)
{
if (player is null) continue;
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
if (false == user_create_or_load_action.isCompletedLoadUser())
{
continue;
}
dataAccumulate(player);
}
recordDataTotalInfo();
//더이상 패킷이 들어오지 않는 데이터는 삭제 처리
deleteOldData();
await dataAccumulateStateCheck();
Log.getLogger().debug("p2p monitoring update done");
}
public override async void exit()
{
try
{
if (m_cancel_token != null && !m_cancel_token.IsCancellationRequested)
{
m_cancel_token.Cancel();
}
if (m_task_nullable != null)
{
try
{
await m_task_nullable.getTask();
}
catch (Exception ex)
{
Log.getLogger().warn($"Task 예외 발생 (무시됨): {ex}");
}
m_task_nullable = null;
}
m_cancel_token?.Dispose();
//m_cancel_token = null;
}
catch (Exception e)
{
Log.getLogger().error($"Exception !!!, stopTaskSafelyAsync() : exception:{e}");
}
ServerBase.Monitor.It.setReceivedP2PDataInfo();
Log.getLogger().debug("p2p monitoring exit");
}
private async Task dataAccumulateStateCheck()
{
if (m_all_user_p2p_packet_infos.Keys.Count == 0)
{
await P2PDataLogManager.It.inactiveMonitoring();
Log.getLogger().debug("p2p incactive monitoring");
}
}
private async Task onTaskTick()
{
await update();
}
public void deleteOldData()
{
var now = DateTimeHelper.Current;
var delete_users = new List<string>();
foreach (var infos in m_all_user_p2p_packet_infos)
{
var user_guid = infos.Key;
var info = infos.Value;
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
if (player_manager.tryGetUserByPrimaryKey(user_guid, out var found_user) == false) continue;
var p2p_data_action = found_user.getEntityAction<P2PDataAction>();
if (p2p_data_action is null)
{
m_all_user_p2p_packet_infos.TryRemove(user_guid, out _);
continue;
}
var elapsed_update_time = p2p_data_action.m_last_update_time.AddMinutes(m_record_check_time_min);
if (elapsed_update_time < now)
{
delete_users.Add(user_guid);
}
}
foreach (var user_guid in delete_users)
{
m_all_user_p2p_packet_infos.TryRemove(user_guid, out _);
Log.getLogger().debug($"delete old p2p packet data userGuid : {user_guid}");
}
}
public void dataAccumulate(Player player)
{
if (false == m_all_user_p2p_packet_infos.TryGetValue(player.getUserGuid(), out var info_log))
{
info_log = new P2PDataInfoLog();
m_all_user_p2p_packet_infos.TryAdd(player.getUserGuid(), info_log);
}
var p2p_data_action = player.getEntityAction<P2PDataAction>();
var now = DateTimeHelper.Current;
foreach (var data in p2p_data_action.m_data)
{
var id = data.Key;
var packet_count = data.Value.m_packet_count;
var packet_size = data.Value.m_total_packet_size;
if (packet_count == info_log.m_total_packet_count) continue;
info_log.m_total_packet_count = packet_count;
info_log.m_total_packet_size = packet_size;
info_log.m_last_recorded_time = now;
m_last_check_time = now;
}
}
public void recordDataTotalInfo()
{
var user_count = m_all_user_p2p_packet_infos.Keys.Count;
long total_count = 0;
long total_size = 0;
foreach (var info in m_all_user_p2p_packet_infos.Values)
{
total_count += info.m_total_packet_count;
total_size += info.m_total_packet_size;
}
ServerBase.Monitor.It.setReceivedP2PDataInfo(total_size, total_count, user_count);
Log.getLogger().debug($"recordDataTotalInfo data send total_size : {total_size}, total_count : {total_count}, user_count : {user_count}");
}
}

View File

@@ -0,0 +1,64 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Nettention.Proud;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class P2PPacketHandler : P2PPacketRecvHandler
{
public override async Task<Result> onProcessP2PPacket(ISession session, ByteArray receivedBytes)
{
var result = new Result();
try
{
var bytes = receivedBytes.data;
if(bytes is null) return result;
if (receivedBytes.Count < 4)
{
return result;
}
// var byte_json = receivedBytes.ToJson();
// Log.getLogger().debug($"p2p packet process packet json : {byte_json}");
byte[] headerBytes = bytes.Take(4).ToArray(); // 첫 4바이트만 추출
uint packet_id = BitConverter.ToUInt32(headerBytes, 0);
//Log.getLogger().debug($"Extracted header value: {packet_id}");
var player = session as Player;
if (player is null)
{
Log.getLogger().debug($"player is nulll: {session.toBasicString()}");
return result;
}
var p2p_data_action = player.getEntityAction<P2PDataAction>();
if (p2p_data_action is null)
{
Log.getLogger().debug($"p2p_data_action is null !!: {player.toBasicString()}");
return result;
}
await p2p_data_action.accumulateP2PData(packet_id, bytes);
//이부분은 고도화 될때 별도 처리
//패킷 단위로 로직 처리 분류 필요할 경우 고도화 처리 한다.
}
catch (Exception ex)
{
Log.getLogger().info($"p2p packet process error {ex.Message}");
return result;
}
return result;
}
}