//using GameServer.World; //using Nettention.Proud; //using ServerCommon; //using ServerCommon.Redis; //using ServerCore; using ServerBase; //using System.Diagnostics; //using System.Net; //using ControlCenter.NamedPipe; //namespace GameServer //{ // internal class GameServer // { // static public GameServer Instance { get; } = new(); // static public AtomicBool m_user_login_block_enable = new(false); // public NetServer _srv { get; } = new(); // PClientToGame.Stub _stub = new(); // public PClientToGame.Proxy _proxy { get; } = new(); // CancellationTokenSource _cts = new(); // TaskCompletionSource? _runTask; // public RabbitMQ4Game _rabbitMQ4Game = null!; // public string ServerName { get; private set; } = string.Empty; // public string WorldServerName { get; private set; } = string.Empty; // public AwsNewInstanceInfo myServerInfo = new AwsNewInstanceInfo(); // List periodicTasks = new(10); // List ChannelInfoList = new(1000); // public Map? Map; // public ChatCommand ChatCommand { get; private set; } = new ChatCommand(); // private GameServer() // { //#pragma warning disable CS1998 // 이 비동기 메서드에는 'await' 연산자가 없으며 메서드가 동시에 실행됩니다. // _srv.ClientJoinHandler = async (clientInfo) => // { // using (clientInfo) // { // Log.getLogger().debug($"Client {clientInfo.hostID.ToString()} ip:{clientInfo.m_TcpLocalAddrFromServer.ToString()} connected."); // ClientSession session = new ClientSession(clientInfo.hostID, "", ""); // ClientSessionManager.Instance.AddHost(session); // NamedPipeClientHelper.Instance.SetCurrentClientConnection(true); // } // }; // // set a routine for client leave event. // _srv.ClientLeaveHandler = async (clientInfo, errorInfo, comment) => // { // using (clientInfo) // { // Log.getLogger().debug($"Client {clientInfo.hostID.ToString()} ip:{clientInfo.tcpAddrFromServer.IPToString()} disconnected."); // NamedPipeClientHelper.Instance.SetCurrentClientConnection(false); // ClientSession? client = ClientSessionManager.Instance.GetSession(clientInfo.hostID); // if (client == null) // { // Log.getLogger().error($"Notfound Session hostId:{clientInfo.hostID}"); // return; // } // // 세션종료로 레디스에 지운 정보를 백그라운드에서 다시 등록하는 것을 방지하기 위해 먼저 뺀다. // // Close시에 이미 세션매니저에서는 제거된 상태임을 주의 바람. // _ = client._serializer.post(async () => // { // ClientSessionManager.Instance.ReleaseSession(client); // await client.Close(); // }); // } // }; // _srv.ErrorHandler = (ErrorInfo Info) => // { // using (Info) // { // Log.getLogger().error(Info.ToString()); // } // }; // _srv.ExceptionHandler = (Exception ex) => // { // Log.getLogger().error(ex.ToString()); // }; // _srv.WarningHandler = (ErrorInfo Info) => // { // using (Info) // { // Log.getLogger().warn(Info.ToString()); // } // }; // _srv.InformationHandler = (ErrorInfo Info) => // { // using (Info) // { // Log.getLogger().info(Info.ToString()); // } // }; // _srv.ClientHackSuspectedHandler = (HostID clientID, HackType hackType) => // { // var clientInfo = _srv.GetClientInfo(clientID); // using (clientInfo) // { // ClientSession? client = ClientSessionManager.Instance.GetSession(clientID); // if (client != null) // { // Log.getLogger().error($"hostID:{clientID} HanckType:{hackType} {clientInfo.m_TcpLocalAddrFromServer.ToString()}, AccountID:{client.Id}"); // } // else // { // Log.getLogger().error($"hostID:{clientID} HanckType:{hackType} {clientInfo.m_TcpLocalAddrFromServer.ToString()}"); // } // } // }; //#pragma warning restore CS1998 // 이 비동기 메서드에는 'await' 연산자가 없으며 메서드가 동시에 실행됩니다. // } // void InitStub() // { // _stub.Message = (HostID remote, RmiContext rmiContext, ClientToGame message) => // { // _ = AuthHandler.ProcessRequestPacket(remote, rmiContext, message.Request); // return true; // }; // } // public async Task StartServer(Options option) // { // //서버 중복시 종료 // if (ServerUtil.isExistProcess(Process.GetCurrentProcess().ProcessName + Convert.ToString(option.Port))) // { // Log.getLogger().error("Duplicate Port : " + Process.GetCurrentProcess().ProcessName + Convert.ToString(option.Port)); // return false; // } // InitStub(); // _srv.AttachStub(_stub); // _srv.AttachProxy(_proxy); // string ip = string.Empty; // if (GameServerApp.Instance.Config.ServiceType == "Dev") // { // ip = ServerUtil.GetLocalIPv4(); // } // else // { // ip = ServerUtil.GetPublicIPv4(); // } // m_user_login_block_enable.set(GameServerApp.Instance.Config.AccountLoginBlockEnable); // ServerType serverType = GameServerApp.Instance.Config.GameServerType == EGameServerType.Channel ? ServerType.Game : ServerType.Indun; // myServerInfo.worldId = option.worldid; // myServerInfo.channel = option.channel; // myServerInfo.ip = ip; // myServerInfo.port = option.Port; // myServerInfo.serverType = (int)serverType; // myServerInfo.capacity = GameServerApp.Instance.Config.DefaultMaxUser; // Constant.g_MaxUser = GameServerApp.Instance.Config.DefaultMaxUser; // if (GameServerApp.Instance.Config.AWS.Enable) // { // myServerInfo.instanceId = await ServerUtil.GetAwsInstanceID(); // } // if (GameServerApp.Instance.Config.GameGuard == true) // { // uint uReturn = GameGuardHelper.InitCSAuth3("./support/GameGuard/"); // if (uReturn != 0) // { // Log.getLogger().error("Failed to Init GameGuard."); // return false; // } // } // _srv.AllowEmptyP2PGroup(true); // string name = GameServerApp.Instance.Config.GameServerType.ToString(); // ServerName = ServerUtil.CreateServerName(serverType, ip, // option.Port, myServerInfo.worldId, myServerInfo.channel); // if (GameServerApp.Instance.Config.AWS.CloudWatchLog.Enable) // { // ServerLog.Init($"{serverType}Server", ip, option.Port, // GameServerApp.Instance.Config.AWS.CloudWatchLog.CloudWatchLogGroup, // GameServerApp.Instance.Config.AWS.CloudWatchLog.CloudWatchLogNamePattern, // GameServerApp.Instance.Config.AWS.CloudWatchLog.CloudWatchLogLevel, // GameServerApp.Instance.Config.AWS.Region, // GameServerApp.Instance.Config.AWS.AccessKey, // GameServerApp.Instance.Config.AWS.SecretKey, // GameServerApp.Instance.Config.AWS.CloudWatchLog.CloudWatchLogLayout); // } // else // { // ServerLog.Init($"{serverType}Server", ip, option.Port); // } // string WorldServerName = $"{serverType}:{ServerUtil.MakeWorldidToString(myServerInfo.worldId)}"; // // 적용되지 않음. concurrentWrites=true 로 해결 인던서버와 게임서버를 로칼에서 실행할때 // // 로그파일이름이 중복되어 옵션을 켜줌. 실서비스시에는 끄는것이 좋음. // //ServerLog.Init(logFileName); // var param = new StartServerParameter(); // param.protocolVersion = new Nettention.Proud.Guid(ServerCommon.Constant.Version); // param.tcpPorts.Add(option.Port); // param.clientEmergencyLogMaxLineCount = 10; // param.hostIDGenerationPolicySimplePacketMode = HostIDGenerationPolicy.HostIDGenerationPolicy_NoRecycle; // param.m_enableAutoConnectionRecoveryOnServer = false; // param.enableNagleAlgorithm = false; // ///param.udpAssignMode = ServerUdpAssignMode.ServerUdpAssignMode_PerClient; // //int udpPort = option.Port; // //if (serverType != EServerType.Game) // //{ // // udpPort = option.Port + 2500; // //} // //for (int i = 0; i < 2500; i++) // //{ // // param.udpPorts.Add(udpPort + i); // //} // try // { //#if DEBUG // // 서버와 오랫동안 통신이 되지 않을 때 서버와의 연결을 끊기 위한 타임아웃(초)의 임계값을 설정 // const Int32 SESSION_KEEP_ALIVE_TIME_MS = (60 * 60 * 1000) * 1; // 1시간 설정 // _srv.SetDefaultTimeoutTimeMs(SESSION_KEEP_ALIVE_TIME_MS); //#else // int keep_alive_time = GameServerApp.Instance.Config.SessionKeepAliveTimeSec * ConstValue.default_1000_millisec; // _srv.SetDefaultTimeoutTimeMs(keep_alive_time); //#endif//DEBUG // //_srv.SetMessageMaxLength(ServerCommon.Constant.MaxPacketSize); // _srv.Start(param); // //_srv.EnableSpeedHackDetector(); // } // catch (Exception ex) // { // Log.getLogger().error("Failed to start server~!!" + ex.ToString()); // return false; // } // if (GameServerApp.Instance.Config.GameServerType == EGameServerType.Channel) // { // if (TableData.Instance._WorldDataTable.TryGetValue(myServerInfo.worldId, out var value) == false) // { // Log.getLogger().error("Failed to start server~!! : Failed to read WorldDataTable."); // return false; // } // Map = new Map(value.MapPath); // } // _runTask = new TaskCompletionSource(); // Log.getLogger().info($"running server on {option.Port}, {GameServerApp.Instance.Config.GameServerType}"); // _rabbitMQ4Game = new RabbitMQ4Game(ServerName // , GameServerApp.Instance.Config.Rabbitmq.HostName // , GameServerApp.Instance.Config.Rabbitmq.Port // , GameServerApp.Instance.Config.Rabbitmq.UserName // , GameServerApp.Instance.Config.Rabbitmq.Password // , GameServerApp.Instance.Config.Rabbitmq.SSL); // if (false == _rabbitMQ4Game.StartConsumer4Game()) // { // Log.getLogger().error($"Failed to start server~!! : Failed to startConsumer RabbitMQ4Game !!!"); // return false; // } // ServerAuthClient serverAuthClient = new(); // _ = serverAuthClient.SendIPAsync(ServerName); // string hostName = Dns.GetHostName(); // // 주기적 실행 task // // 아래 StartNew의 호출 인자는 Task updateTask = Task.Run(() => Update()); 호출과 같음 // // https://code-maze.com/csharp-task-run-vs-task-factory-startnew/ // /* // Task updateTask = LogicThread.Factory.StartNew(() => Update(), // CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // */ // bool firstInit = true; // Task updateCUTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // await sessionUpdate(); // if (firstInit == true) // { // await Task.Run(async Task? () => // { // await Task.Delay(1000); // //서버 처음 뜰때 한번 호출 UpdateServerCU 이후에 부르기 위함. // bool ret = await GameServerApp.Instance.ServerCUStorage.initAddSortedServerKey( // ServerName, // serverType, // myServerInfo.worldId); // if (ret == false) // { // Log.getLogger().error($"Add Sorted Server Key fail."); // return false; // } // return true; // }, _cts.Token); // firstInit = false; // } // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } //#if DEBUG // using (NetServerStats stat = _srv.GetStats()) // { // //Log.getLogger().info($"tcp RCV:{stat.totalTcpReceiveBytes} tcp SND:{stat.totalTcpSendBytes} udp RCV:{stat.totalUdpReceiveBytes} udp SND:{stat.totalUdpSendBytes}"); // } //#endif // }, // TimeSpan.FromMilliseconds(5000), _cts.Token); // Task updateTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // //Stopwatch stopwatch = Stopwatch.StartNew(); // await Update(); // /*stopwatch.Stop(); // if(stopwatch.ElapsedMilliseconds> 1000) // Log.getLogger().error($"updateTask Slow log {stopwatch.ElapsedMilliseconds}"); // */ // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, // TimeSpan.FromMilliseconds(300), _cts.Token); // Task updateLoginTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // //Stopwatch stopwatch= Stopwatch.StartNew(); // await ClientSessionManager.Instance.ForEach(async (ClientSession session) => // { // if (session.IsClosedProcessed == false) // { // //ClientSessionManager.Instance.ReleaseSession(session); // //return false; // await session.KeepLogin(); // await Task.Delay(10); // } // return true; // }); // /* // stopwatch.Stop(); // if (stopwatch.ElapsedMilliseconds > 1000) // Log.getLogger().error($"updateLoginTask Slow log {stopwatch.ElapsedMilliseconds}"); // */ // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, TimeSpan.FromMilliseconds(ServerCommon.Constant.KEEP_LOGIN_UPDATE_TIME), _cts.Token); // //이벤트 업데이트가 100밀리 세컨드까지 필요할까? 1초면 될듯.. // Task updateEventCheckTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // EventUpdate(); // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, // TimeSpan.FromMilliseconds(1000), _cts.Token); // //퀘스트는 1초마다 처리해주면 될것 같은데... 이벤트랑 합쳐서 타이머를 돌리는 것도 나쁘지 않을듯.... // Task updateQuestCheckTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // await QuestUpdate(); // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, // TimeSpan.FromMilliseconds(100), _cts.Token); // if (serverType == ServerType.Game) // { // Task updateChannelInfoTask = ServerUtil.RunPeriodicTask(async () => // { // try // { // ChannelInfoList.Clear(); // var serverInfoList = await GameServerApp.Instance.ServerCUStorage. // getGameServerChannelInWorldServerCU( // GameServer.Instance.ServerName); // foreach (var channel in serverInfoList) // { // ChannelInfo channelInfo = new ChannelInfo(); // channelInfo.Channel = channel.Channel; // channelInfo.Language = (int)ServerUtil.getLanguageByChannel(channel.Channel); // channelInfo.Trafficlevel = GetTrafficLevel(channel.Sessions, channel.Capacity); // ChannelInfoList.Add(channelInfo); // } // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, TimeSpan.FromMilliseconds(ServerCommon.Constant.CHANNEL_UPDATE_TIME), _cts.Token); // periodicTasks.Add(updateChannelInfoTask); // } // if (GameServerApp.Instance.Config.GameGuard == true) // { // Task updateGameGuardTask = ServerUtil.RunPeriodicTask(async () =>// -- GameGuard // { // try // { // await ClientSessionManager.Instance.ForEach(async (ClientSession session) => // { // if (GameGuardHelper.getGameGuardPacket(session.GameGuardInstance, out var packet, out var packetSize) == false) // { // await session.Close(); // } // ClientToGame clientToGame = new ClientToGame(); // clientToGame.Message = new(); // clientToGame.Message.GameGuardAuthNoti = new(); // clientToGame.Message.GameGuardAuthNoti.AuthValue.AddRange(Array.ConvertAll(packet, Convert.ToInt32).ToList()); // clientToGame.Message.GameGuardAuthNoti.AuthValueSize = packetSize; // session.Send(RmiContext.ReliableSend, clientToGame); // return true; // }); // } // catch (Exception e) // { // Log.getLogger().error(e.ToString()); // } // }, TimeSpan.FromMinutes(ServerCommon.Constant.UPDATE_GAMEGUARD_AUTH), _cts.Token); // periodicTasks.Add(updateGameGuardTask); // } // Task updateChatTask = ServerUtil.RunPeriodicTask(async () => // { // NoticeChatManager.Instance.UpdateChat(); // }, TimeSpan.FromMilliseconds(ServerCommon.Constant.NOTICE_CHAT_UPDATE_TIME), _cts.Token); // var keepPartyTask = PartyManager.Instance.KeepParty(_cts.Token); // periodicTasks.Add(updateLoginTask); // periodicTasks.Add(updateTask); // periodicTasks.Add(updateCUTask); // periodicTasks.Add(updateChatTask); // periodicTasks.Add(keepPartyTask); // periodicTasks.Add(updateEventCheckTask); // return true; // } // public async Task sessionUpdate() // { // int roomCapacity = 0; // if (GameServerApp.Instance.Config.GameServerType == EGameServerType.Indun) // { // roomCapacity = InstanceRoomManager.Instance.Capacity; // } // (bool ret, _) = await GameServerApp.Instance.ServerCUStorage.UpdateServerCU( // GameServer.Instance.ServerName, // GameServer.Instance.myServerInfo.ip, // GameServer.Instance.myServerInfo.port, // ClientSessionManager.Instance.Count, // Constant.g_MaxUser, // GameServer.Instance.myServerInfo.instanceId, // GameServer.Instance.myServerInfo.worldId, // GameServer.Instance.myServerInfo.channel, // ServerUtil.getLanguageByChannel(GameServer.Instance.myServerInfo.channel), // roomCapacity); // if (ret == false) // { // Log.getLogger().warn( // $"GameServerCU Login Update fail {GameServerApp.Instance.Config.GameServerType}{GameServer.Instance.myServerInfo.ip}:{GameServer.Instance.myServerInfo.port} count:{ClientSessionManager.Instance.Count}"); // } // ServerType serverType = GameServerApp.Instance.Config.GameServerType == EGameServerType.Channel ? ServerType.Game : ServerType.Indun; // MQHelper.SendSessionCount(GameServer.Instance._rabbitMQ4Game, GameServer.Instance.myServerInfo.instanceId, ClientSessionManager.Instance.Count, (int)serverType, GameServer.Instance.myServerInfo.worldId); // } // public async Task StopServer() // { // await GameServerApp.Instance.ServerCUStorage.DeleteServerInfo(ServerName); // _srv.Stop(); // _cts.Cancel(); // _rabbitMQ4Game?.stop(); // if (GameServerApp.Instance.Config.GameGuard == true) // { // GameGuardHelper.CloseCSAuth3(); // } // await NamedPipeMonitor.StopNamedPipeService(); // Task.WaitAll(periodicTasks.ToArray()); // _runTask?.SetResult(true); // } // public Task? Running() // { // return _runTask?.Task; // } // public bool Send(HostID hostID, RmiContext rmi, ClientToGame msg) // { // if (msg.Message is null || msg.Message.MsgCase != ClientToGameMessage.MsgOneofCase.MoveActor) // { // Log.getLogger().info($"{msg.MsgCase} size:{msg.CalculateSize()}"); // } // return _proxy.Message(hostID, rmi, msg); // } // public bool Send(HostID[] hostID, ClientToGame msg) // { // Log.getLogger().info($"{msg.MsgCase} size:{msg.CalculateSize()}"); // return _proxy.Message(hostID, ServerCore.ProudNetHelper.compressRmi(), msg); // } // public bool BroadCastingAll(ClientToGame msg) // { // Log.getLogger().info($"{msg.MsgCase} size:{msg.CalculateSize()}"); // return _proxy.Message(_srv.GetClientHostIDs(), ServerCore.ProudNetHelper.compressRmi(), msg); // } // async Task Update() // { // await ProcessBuff(); // } // private static async Task ProcessBuff() // { // await ClientSessionManager.Instance.ForEach((ClientSession session) => // { // session.CheckBuff(); // return Task.FromResult(true); // }); // } // void EventUpdate() // { // EventManager.Instance.ClaimEventActiveCheck(); // } // async Task QuestUpdate() // { // } // public List GetChannelInfoList() // { // return ChannelInfoList; // } // public int GetTrafficLevel(int CurUser, int MaxUser) // { // double trafficPercent = (double)CurUser / (double)MaxUser * (double)100; // int trafficLevel = 0; // if (0 <= trafficPercent && trafficPercent < 80.0f) // { // trafficLevel = 0; // } // else if (80.0f <= trafficPercent && trafficPercent < 100.0f) // { // trafficLevel = 1; // } // else if (100.0f <= trafficPercent) // { // trafficLevel = 2; // } // return trafficLevel; // } // public AtomicBool getUserLoginBlockEnable() // { // return m_user_login_block_enable; // } // public async Task logoutUserAllByKick() // { // var sessions = ClientSessionManager.Instance.getClientSessions().Values.ToList(); // foreach (var session in sessions) // { // await ClientSessionManager.Instance.Kick(session.getUserNickname()); // } // } // } //}