using Nettention.Proud; using ServerCore; using ServerBase; using ServerCommon; using MetaAssets; namespace GameServer; public class HostMigrationFactory { public static IHostMigrator createCommonHostMigrator(int battleModeId, GameServerLogic gameServerLogic) { // battleModeId <- 게임 모드 ID 테이블 참조용 // TODO: battleModeId를 사용하여 HostMigrationPolicy 생성하는 것으로 변경 예정 int game_mode_option_data_id = 1; var host_migration_policy = createHostMigrationPolicyByMeta(game_mode_option_data_id); var net_server = gameServerLogic.getProudNetListener().getNetServer(); NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!!"); var host_migration_system = new HostMigrationSystem(net_server, host_migration_policy); var host_migrator = new CommonHostMigrator(host_migration_system, gameServerLogic); return host_migrator; } private static HostMigrationPolicy createHostMigrationPolicyByMeta(int gameModeOptionDataId) { var meta = getMeta(gameModeOptionDataId); return new HostMigrationPolicy { HostKickFpsThreshold = meta.HostKickFpsThreshold, HostKickFpsDuration = TimeSpan.FromSeconds(meta.HostKickFpsDuration), HostKickPingThreshold = meta.HostKickPingThreshold, HostKickPingDuration = TimeSpan.FromSeconds(meta.HostKickPingDuration), }; GameModeOptionMetaData getMeta(int gameModeOptionDataId) { var game_mode_option_meta_table = MetaData.Instance.Meta.GameModeOptionMetaTable; game_mode_option_meta_table.GameModeOptionDataListbyGameModeOptionId.TryGetValue(gameModeOptionDataId, out var game_mode_option_meta); NullReferenceCheckHelper.throwIfNull(game_mode_option_meta, () => $"game_mode_option_meta is null !!!!"); return game_mode_option_meta; } } } public class CommonHostMigrator : IHostMigrator { private readonly HostMigrationSystem m_host_migration_system; private string m_host_user_guid = string.Empty; private readonly GameServerLogic m_game_server_logic; private DateTime m_last_loop_time = DateTime.MinValue; private readonly TimeSpan m_loop_interval = TimeSpan.FromSeconds(1); public HostID SuperPeerHostId => m_host_migration_system.SuperPeerHostId; public HostMigrationSystem HostMigrationSystem => m_host_migration_system; public CommonHostMigrator(HostMigrationSystem hostMigrationSystem, GameServerLogic gameServerLogic) { m_host_migration_system = hostMigrationSystem; m_game_server_logic = gameServerLogic; } public (Result, bool) migrateCheck(bool ignoreInterval = false) { if (!ignoreInterval && isOnMigrationLoopInterval()) { return (new Result(), false); } var (is_migrated, new_super_peer_id) = m_host_migration_system.migrateCheck(); if (is_migrated) { var (result, user_guid) = getUserGuidByHostId(new_super_peer_id); if (result.isFail()) { return (result, is_migrated); } var host_change_success = m_host_migration_system.changeSuperPeerHostId(new_super_peer_id); if (!host_change_success) { return (new Result { ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer." }, is_migrated); } m_host_user_guid = user_guid; return (result, is_migrated); } return (new Result(), false); } public void setGroupHostId(HostID groupId) { m_host_migration_system.setGroupHostId(groupId); } //================================================================= // 삭제 예정 //================================================================= public Result defineHost(HostID p2pGroupId = HostID.HostID_None, SuperPeerSelectionPolicy policy = null!, HostID[] excludes = null!) { // m_host_migration_system.setGroupHostId(p2pGroupId); // // var (is_migrated, new_super_peer_id) = m_host_migration_system.migrateCheck(); // // if (is_migrated) // { // var (result, user_guid) = getUserGuidByHostId(new_super_peer_id); // if (result.isFail()) // { // return result; // } // // var host_change_success = m_host_migration_system.changeSuperPeerHostId(new_super_peer_id); // if (!host_change_success) // { // return new Result // { // ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer." // }; // } // m_host_user_guid = user_guid; // return result; // } return new Result(); } public Result modifyHost(string userGuid) { var (result, host_id) = getHostIdByUserGuid(userGuid); if (result.isFail()) { return result; } if (m_host_migration_system.changeSuperPeerHostId(host_id)) { m_host_user_guid = userGuid; return result; } return new Result { ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer." }; } public Result removeHost() { m_host_migration_system.changeSuperPeerHostId(HostID.HostID_None); m_host_user_guid = string.Empty; return new Result(); } public string getHostUserGuid() { return m_host_user_guid; } private (Result, string) getUserGuidByHostId(HostID hostId) { string err_msg; var result = new Result(); if (hostId == HostID.HostID_None) { err_msg = $"there is not suitable super peer !!!! host_id : {hostId}"; result.setFail(ServerErrorCode.NotFoundUser, err_msg); return (result, string.Empty); } var session = m_game_server_logic.getProudNetListener().onLookupEntityWithSession((int)hostId); if (session is null) { err_msg = $"session is null!!!! host_id : {hostId}"; result.setFail(ServerErrorCode.NotFoundUser, err_msg); return (result, string.Empty); } var player = session as Player; if (player is null) { err_msg = $"player is null!!!! host_id : {hostId}"; result.setFail(ServerErrorCode.NotFoundUser, err_msg); return (result, string.Empty); } return (result, player.getUserGuid()); } private (Result, HostID) getHostIdByUserGuid(string userGuid) { string err_msg; var result = new Result(); // todo: 임시 다른 방법 모색 - 비용이 비쌀 수 있음 var session_pair = m_game_server_logic.getProudNetListener() .getEntityWithSessions() .FirstOrDefault(x => x.Value.getUserGuid() == userGuid); var session = session_pair.Value; if (session is null) { err_msg = $"session is null!!!! user_guid : {userGuid}"; result.setFail(ServerErrorCode.NotFoundUser, err_msg); return (result, HostID.HostID_None); } if (session is not Player player) { err_msg = $"player is null!!!! user_guid : {userGuid}"; result.setFail(ServerErrorCode.NotFoundUser, err_msg); return (result, HostID.HostID_None); } return (result, player.getHostId()); } //================================================================= // 호스트 마이그레이션 루프 인터벌 중인지 여부 //================================================================= private bool isOnMigrationLoopInterval() { if (m_last_loop_time == DateTime.MinValue) { m_last_loop_time = DateTime.UtcNow; return false; } if (m_last_loop_time.Add(m_loop_interval) < DateTime.UtcNow) { return true; } m_last_loop_time = DateTime.UtcNow; return false; } }