diff --git a/Command/Command.csproj b/Command/Command.csproj index 50071390..555b228c 100644 --- a/Command/Command.csproj +++ b/Command/Command.csproj @@ -8,6 +8,10 @@ DanhengCommand + + + + diff --git a/Common/Common.csproj b/Common/Common.csproj index 4766b2b4..691a01c6 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -18,6 +18,7 @@ + diff --git a/Common/Enums/PlayerStatusEnum.cs b/Common/Enums/PlayerStatusEnum.cs new file mode 100644 index 00000000..ee406ac5 --- /dev/null +++ b/Common/Enums/PlayerStatusEnum.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EggLink.DanhengServer.Enums +{ + public enum PlayerStatusEnum + { + Offline = 0, + Explore = 1, + Rogue = 2, + Challenge = 3, + Mission = 4 + } +} diff --git a/GameServer/Game/ChessRogue/ChessRogueInstance.cs b/GameServer/Game/ChessRogue/ChessRogueInstance.cs index b38bfeca..14fdd126 100644 --- a/GameServer/Game/ChessRogue/ChessRogueInstance.cs +++ b/GameServer/Game/ChessRogue/ChessRogueInstance.cs @@ -214,10 +214,10 @@ namespace EggLink.DanhengServer.Game.ChessRogue }; RogueCells.Add(item.Key, cell); - if (cell.GetCellId() == CurBoardExcel.MapInfo!.EndGridItemID) // last cell - { + //if (cell.GetCellId() == CurBoardExcel.MapInfo!.EndGridItemID) // last cell + //{ cell.Init(); - } + //} } } diff --git a/GameServer/GameServer.csproj b/GameServer/GameServer.csproj index 947cd21b..5b334718 100644 --- a/GameServer/GameServer.csproj +++ b/GameServer/GameServer.csproj @@ -32,6 +32,7 @@ + diff --git a/Program/Program.csproj b/Program/Program.csproj index 287be6a9..0e4e0d70 100644 --- a/Program/Program.csproj +++ b/Program/Program.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/Program/Program/EntryPoint.cs b/Program/Program/EntryPoint.cs index 2f918d23..f3b9c58c 100644 --- a/Program/Program/EntryPoint.cs +++ b/Program/Program/EntryPoint.cs @@ -13,6 +13,7 @@ using EggLink.DanhengServer.Command; using EggLink.DanhengServer.Server.Packet; using EggLink.DanhengServer.GameServer.Command; using EggLink.DanhengServer.WebServer.Server; +using EggLink.DanhengServer.Enums; namespace EggLink.DanhengServer.Program { @@ -139,6 +140,40 @@ namespace EggLink.DanhengServer.Program }; MuipManager.OnExecuteCommand += CommandManager.HandleCommand; + MuipManager.OnGetServerInformation += x => + { + foreach (var con in Listener.Connections.Values) + { + if (con.Player != null) + { + x.Add(con.Player.Uid, con.Player.Data); + } + } + }; + MuipManager.OnGetPlayerStatus += (int uid, out PlayerStatusEnum status) => + { + foreach (var con in Listener.Connections.Values) + { + if (con.Player != null && con.Player.Uid == uid) + { + if (con.Player.RogueManager?.GetRogueInstance() != null) + { + status = PlayerStatusEnum.Rogue; + } + else if (con.Player.ChallengeManager?.ChallengeInstance != null) + { + status = PlayerStatusEnum.Challenge; + } + else + { + status = PlayerStatusEnum.Explore; + } + return; + } + } + + status = PlayerStatusEnum.Offline; + }; // generate the handbook HandbookGenerator.Generate(); diff --git a/WebServer/Controllers/MuipServerRoutes.cs b/WebServer/Controllers/MuipServerRoutes.cs index 7abf5b02..06a7ac89 100644 --- a/WebServer/Controllers/MuipServerRoutes.cs +++ b/WebServer/Controllers/MuipServerRoutes.cs @@ -29,5 +29,19 @@ namespace EggLink.DanhengServer.WebServer.Controllers var resp = MuipManager.ExecuteCommand(req.SessionId, req.Command, req.TargetUid); return new JsonResult(resp); } + + [HttpGet("/muip/server_information")] + public IActionResult GetServerInformation([FromBody] ServerInformationRequest req) + { + var resp = MuipManager.GetInformation(req.SessionId); + return new JsonResult(resp); + } + + [HttpGet("/muip/player_information")] + public IActionResult GetPlayerInformation([FromBody] PlayerInformationRequest req) + { + var resp = MuipManager.GetPlayerInformation(req.SessionId, req.Uid); + return new JsonResult(resp); + } } } diff --git a/WebServer/Request/InformationRequest.cs b/WebServer/Request/InformationRequest.cs new file mode 100644 index 00000000..3d67f19d --- /dev/null +++ b/WebServer/Request/InformationRequest.cs @@ -0,0 +1,13 @@ +namespace EggLink.DanhengServer.WebServer.Request +{ + public class ServerInformationRequest + { + public string SessionId { get; set; } = ""; + } + + public class PlayerInformationRequest + { + public string SessionId { get; set; } = ""; + public int Uid { get; set; } + } +} diff --git a/WebServer/Response/InformationResponse.cs b/WebServer/Response/InformationResponse.cs new file mode 100644 index 00000000..05c40fd7 --- /dev/null +++ b/WebServer/Response/InformationResponse.cs @@ -0,0 +1,59 @@ +using EggLink.DanhengServer.Enums; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace EggLink.DanhengServer.WebServer.Response +{ + public class ServerInformationResponse(int code, string message, ServerInformationData? data = null) : BaseResponse(code, message, data) + { + } + + public class ServerInformationData + { + public List OnlinePlayers { get; set; } = []; + public long ServerTime { get; set; } = 0; + public float MaxMemory { get; set; } = 0; + public float UsedMemory { get; set; } = 0; + public float ProgramUsedMemory { get; set; } = 0; + } + + public class SimplePlayerInformationData + { + public int Uid { get; set; } + public string Name { get; set; } = ""; + public int HeadIconId { get; set; } + } + + public class PlayerInformationResponse(int code, string message, PlayerInformationData? data = null) : BaseResponse(code, message, data) + { + } + + public class PlayerInformationData + { + // Basic info + public int Uid { get; set; } + public string Name { get; set; } = ""; + public string Signature { get; set; } = ""; + public int HeadIconId { get; set; } + + // Scene info + public int CurPlaneId { get; set; } + public int CurFloorId { get; set; } + + // Player info + [JsonConverter(typeof(StringEnumConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] + public PlayerStatusEnum PlayerStatus { get; set; } = PlayerStatusEnum.Explore; + public int Stamina { get; set; } = 0; + public int RecoveryStamina { get; set; } = 0; + public List AssistAvatarList { get; set; } = []; + public List DisplayAvatarList { get; set; } = []; + + // Mission info + public List FinishedMainMissionIdList { get; set; } = []; + public List FinishedSubMissionIdList { get; set; } = []; + public List AcceptedMainMissionIdList { get; set; } = []; + public List AcceptedSubMissionIdList { get; set; } = []; + + } +} diff --git a/WebServer/Server/MuipManager.cs b/WebServer/Server/MuipManager.cs index 29573e62..4c572d45 100644 --- a/WebServer/Server/MuipManager.cs +++ b/WebServer/Server/MuipManager.cs @@ -7,6 +7,14 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Math; using Org.BouncyCastle.X509; using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; +using EggLink.DanhengServer.Database.Player; +using EggLink.DanhengServer.Database; +using EggLink.DanhengServer.Database.Avatar; +using EggLink.DanhengServer.Database.Mission; +using EggLink.DanhengServer.Enums; +using Spectre.Console; namespace EggLink.DanhengServer.WebServer.Server { @@ -14,6 +22,10 @@ namespace EggLink.DanhengServer.WebServer.Server { public delegate void ExecuteCommandDelegate(string message, MuipCommandSender sender); public static event ExecuteCommandDelegate? OnExecuteCommand; + public delegate void ServerInformationDelegate(Dictionary resultData); + public static event ServerInformationDelegate? OnGetServerInformation; + public delegate void GetPlayerStatusDelegate(int uid, out PlayerStatusEnum status); + public static event GetPlayerStatusDelegate? OnGetPlayerStatus; public static string RsaPublicKey { get; private set; } = ""; public static string RsaPrivateKey { get; private set; } = ""; @@ -113,6 +125,108 @@ namespace EggLink.DanhengServer.WebServer.Server return new(2, "Session not found!"); } + public static ServerInformationResponse GetInformation(string sessionId) + { + if (Sessions.TryGetValue(sessionId, out MuipSession? value)) + { + var session = value; + if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec()) + { + Sessions.Remove(sessionId); + return new(1, "Session has expired!", null); + } + Process currentProcess = Process.GetCurrentProcess(); + + long currentProcessMemory = currentProcess.WorkingSet64; + + // get system info + var totalMemory = -1f; + var availableMemory = -1f; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + totalMemory = GetTotalMemoryWindows(); + availableMemory = GetAvailableMemoryWindows(); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + totalMemory = GetTotalMemoryLinux(); + availableMemory = GetAvailableMemoryLinux(); + } + + var result = new Dictionary(); + var sync = Task.Run(() => OnGetServerInformation?.Invoke(result)); + + sync.Wait(); + + return new(0, "Success", new() + { + ServerTime = DateTime.Now.ToUnixSec(), + MaxMemory = totalMemory, + ProgramUsedMemory = currentProcessMemory / 1024 / 1024, + UsedMemory = totalMemory - availableMemory, + OnlinePlayers = result.Values.Select(x => new SimplePlayerInformationData() + { + Name = x.Name ?? "", + HeadIconId = x.HeadIcon, + Uid = x.Uid + }).ToList(), + }); + } + return new(2, "Session not found!", null); + } + + public static PlayerInformationResponse GetPlayerInformation(string sessionId, int uid) + { + if (Sessions.TryGetValue(sessionId, out MuipSession? value)) + { + var session = value; + if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec()) + { + Sessions.Remove(sessionId); + return new(1, "Session has expired!", null); + } + + var result = new Dictionary(); + var sync = Task.Run(() => OnGetServerInformation?.Invoke(result)); + + sync.Wait(); + + result.TryGetValue(uid, out var player); + if (player == null) return new(2, "Player not exist or is offline!", null); + + var status = PlayerStatusEnum.Offline; + + var statusSync = Task.Run(() => OnGetPlayerStatus?.Invoke(player.Uid, out status)); + + statusSync.Wait(); + + var avatarData = DatabaseHelper.Instance!.GetInstance(player.Uid)!; + var missionData = DatabaseHelper.Instance!.GetInstance(player.Uid)!; + + return new(0, "Success", new() + { + Uid = player.Uid, + Name = player.Name ?? "", + Signature = player.Signature ?? "", + Stamina = player.Stamina, + RecoveryStamina = (int)player.StaminaReserve, + HeadIconId = player.HeadIcon, + CurFloorId = player.FloorId, + CurPlaneId = player.PlaneId, + AssistAvatarList = avatarData.AssistAvatars, + DisplayAvatarList = avatarData.DisplayAvatars, + AcceptedSubMissionIdList = missionData.RunningSubMissionIds, + AcceptedMainMissionIdList = missionData.RunningMainMissionIds, + FinishedMainMissionIdList = missionData.FinishedMainMissionIds, + FinishedSubMissionIdList = missionData.FinishedSubMissionIds, + PlayerStatus = status + }); + } + return new(3, "Session not found!", null); + } + + #region Tools + /// /// get rsa key pair /// @@ -167,5 +281,57 @@ namespace EggLink.DanhengServer.WebServer.Server return result; } + + public static float GetTotalMemoryWindows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem"); + foreach (var obj in searcher.Get()) + { + var memory = Convert.ToUInt64(obj["TotalPhysicalMemory"]); + return memory / 1024 / 1024; + } + } + return 0; + } + + public static float GetAvailableMemoryWindows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var pc = new PerformanceCounter("Memory", "Available MBytes"); + return pc.NextValue(); + } + return 0; + } + + public static float GetTotalMemoryLinux() + { + string[] lines = File.ReadAllLines("/proc/meminfo"); + foreach (string line in lines) + { + if (line.StartsWith("MemTotal")) + { + return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024; + } + } + return 0; + } + + public static float GetAvailableMemoryLinux() + { + string[] lines = File.ReadAllLines("/proc/meminfo"); + foreach (string line in lines) + { + if (line.StartsWith("MemAvailable")) + { + return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024; + } + } + return 0; + } + + #endregion } } diff --git a/WebServer/WebServer.csproj b/WebServer/WebServer.csproj index 3e1dff7d..7d1e0f58 100644 --- a/WebServer/WebServer.csproj +++ b/WebServer/WebServer.csproj @@ -19,6 +19,7 @@ +