using Campofinale.Commands; using Campofinale.Database; using Campofinale.Game; using Campofinale.Http; using Campofinale.Protocol; using Campofinale.Resource; using Pastel; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.InteropServices; using System.ServiceProcess; namespace Campofinale { public static class DateTimeExtensions { private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static long ToUnixTimestampMilliseconds(this DateTime dateTime) { return (long)(dateTime - UnixEpoch).TotalMilliseconds; } } public class Server { public class HandlerAttribute : Attribute { public CsMsgId CmdId { get; set; } public HandlerAttribute(CsMsgId cmdID) { this.CmdId = cmdID; } public delegate void HandlerDelegate(Player client, int cmdId, Network.Packet packet); } public class CommandAttribute : Attribute { public string command; public string desc; public bool requiredTarget; public CommandAttribute(string cmdName, string desc = "No description", bool requireTarget=false) { this.command = cmdName; this.desc = desc; this.requiredTarget = requireTarget; } public delegate void HandlerDelegate(Player sender, string command, string[] args, Player target); } public static List clients = new List(); public static string ServerVersion = "1.1.5-dev"; public static bool Initialized = false; public static bool showLogs = true; public static bool showWarningLogs = true; public static bool showBodyLogs = false; public static Dispatch dispatch; public static ResourceManager resourceManager; public static ConfigFile config; public static List csMessageToHide = new() { CsMsgId.CsMoveObjectMove, CsMsgId.CsBattleOp,CsMsgId.CsPing }; public static List scMessageToHide = new() { ScMsgId.ScMoveObjectMove, ScMsgId.ScPing }; public static ResourceManager GetResources() { return resourceManager; } public void Start(ConfigFile config) { { Assembly assembly = Assembly.GetExecutingAssembly(); Type[] types = assembly.GetTypes(); foreach (var type in types) { NotifyManager.AddReqGroupHandler(type); CommandManager.AddReqGroupHandler(type); } NotifyManager.Init(); CommandManager.Init(); } Logger.Initialize(); Server.config = config; showLogs = config.logOptions.packets; showWarningLogs = config.logOptions.packetWarnings; showBodyLogs = config.logOptions.packetBodies; Logger.Print($"Starting server version {ServerVersion} with supported client version: WINDOWS-{GameConstants.GAME_VERSION} and MOBILE-{GameConstants.GAME_VERSION_ANDROID}"); Logger.Print($"Logs are {(showLogs ? "enabled" : "disabled")}"); Logger.Print($"Warning logs are {(showWarningLogs ? "enabled" : "disabled")}"); Logger.Print($"Packet body logs are {(showBodyLogs ? "enabled" : "disabled")}"); StartDBService(); DatabaseManager.Init(); ResourceManager.Init(); new Thread(new ThreadStart(DispatchServer)).Start(); IPAddress ipAddress = IPAddress.Parse(Server.config.gameServer.bindAddress); int port = Server.config.gameServer.bindPort; Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); new Thread(new ThreadStart(CmdListener)).Start(); new Thread(new ThreadStart(Update)).Start(); try { serverSocket.Bind(new IPEndPoint(ipAddress, port)); serverSocket.Listen(int.MaxValue); Logger.Print($"Server listening on {ipAddress}:{port}"); Initialized = true; while (true) { Socket clientSocket = serverSocket.Accept(); if (clientSocket.Connected) { Logger.Print("Connected new client: " + clients.Count()+1); try { Player client = new Player(clientSocket); clients.Add(client); client.receivorThread.Start(); } catch (Exception e) { Logger.PrintError($" {e.Message}"); } } } } catch (Exception ex) { Logger.PrintError($" {ex.Message}"); } finally { serverSocket.Close(); Logger.Print("Server stopped."); } } public void Update() { while (true) { try { clients.ForEach(client => { if (client != null) client.Update(); }); Thread.Sleep(1000); } catch (Exception ex) { } } } public void CmdListener() { while (true) { try { string cmd = Console.ReadLine()!; string[] split = cmd.Split(" "); string[] args = cmd.Split(" ").Skip(1).ToArray(); string command = split[0].ToLower(); CommandManager.Notify(null,command, args,clients.Find(c=>c.accountId==CommandManager.targetId)); } catch (Exception ex) { Logger.PrintError(ex.Message); } } } public void DispatchServer() { dispatch = new Dispatch(); dispatch.Start(); } public static CsMsgId[] hideLog = []; public static string ColoredText(string text, string color) { return text.Pastel(color); } public static void Shutdown() { foreach (Player player in clients) { if(player.Initialized) player.Save(); player.Kick(CODE.ErrServerClosed); } } private static void StartDBService() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) try { string mongodbService = "MongoDB"; using (ServiceController service = new ServiceController(mongodbService)) { if (service.Status != ServiceControllerStatus.Running) { Logger.Print($"Starting {mongodbService} service..."); service.Start(); service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30)); Logger.Print($"Started {mongodbService} service"); } } } catch (Exception e) { Logger.PrintError($"Failed to Start MongoDB service: {e}"); } } } }