public static void HandleLandblockPerformance(Session session, params string[] parameters) { var sb = new StringBuilder(); var loadedLandblocks = LandblockManager.GetLoadedLandblocks(); // Filter out landblocks that haven't recorded at least 1000 events var sortedByAverage = loadedLandblocks.Where(r => r.Monitor1h.TotalEvents >= 1000).OrderByDescending(r => r.Monitor1h.AverageEventDuration).Take(10); sb.Append($"Most Busy Landblock - By Average{'\n'}"); sb.Append($"~1h Hits Avg Long Last Tot - Location Players Creatures{'\n'}"); foreach (var entry in sortedByAverage) { int players = 0, creatures = 0; foreach (var worldObject in entry.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } } sb.Append($"{entry.Monitor1h.TotalEvents.ToString().PadLeft(7)} {entry.Monitor1h.AverageEventDuration:N4} {entry.Monitor1h.LongestEvent:N3} {entry.Monitor1h.LastEvent:N3} {((int)entry.Monitor1h.TotalSeconds).ToString().PadLeft(4)} - " + $"0x{entry.Id.Raw:X8} {players.ToString().PadLeft(7)} {creatures.ToString().PadLeft(9)}{'\n'}"); } var sortedByLong = loadedLandblocks.Where(r => r.Monitor1h.TotalEvents >= 1000).OrderByDescending(r => r.Monitor1h.LongestEvent).Take(10); sb.Append($"Most Busy Landblock - By Longest{'\n'}"); sb.Append($"~1h Hits Avg Long Last Tot - Location Players Creatures{'\n'}"); foreach (var entry in sortedByLong) { int players = 0, creatures = 0; foreach (var worldObject in entry.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } } sb.Append($"{entry.Monitor1h.TotalEvents.ToString().PadLeft(7)} {entry.Monitor1h.AverageEventDuration:N4} {entry.Monitor1h.LongestEvent:N3} {entry.Monitor1h.LastEvent:N3} {((int)entry.Monitor1h.TotalSeconds).ToString().PadLeft(4)} - " + $"0x{entry.Id.Raw:X8} {players.ToString().PadLeft(7)} {creatures.ToString().PadLeft(9)}{'\n'}"); } CommandHandlerHelper.WriteOutputInfo(session, sb.ToString()); }
public static void HandleServerStatus(Session session, params string[] parameters) { // This is formatted very similarly to GDL. var sb = new StringBuilder(); var proc = Process.GetCurrentProcess(); sb.Append($"Server Status:{'\n'}"); sb.Append($"Host Info: {Environment.OSVersion}, vCPU: {Environment.ProcessorCount}{'\n'}"); var runTime = DateTime.Now - proc.StartTime; sb.Append($"Server Runtime: {(int)runTime.TotalHours}h {runTime.Minutes}m {runTime.Seconds}s{'\n'}"); sb.Append($"Total CPU Time: {(int)proc.TotalProcessorTime.TotalHours}h {proc.TotalProcessorTime.Minutes}m {proc.TotalProcessorTime.Seconds}s, Threads: {proc.Threads.Count}{'\n'}"); // todo, add actual system memory used/avail sb.Append($"{(proc.PrivateMemorySize64 >> 20):N0} MB used{'\n'}"); // sb.Append($"{(proc.PrivateMemorySize64 >> 20)} MB used, xxxx / yyyy MB physical mem free.{'\n'}"); sb.Append($"{NetworkManager.GetSessionCount():N0} connections, {NetworkManager.GetUniqueSessionEndpointCount():N0} unique connections, {PlayerManager.GetAllOnline().Count:N0} players online{'\n'}"); sb.Append($"Total Accounts Created: {DatabaseManager.Authentication.GetAccountCount():N0}, Total Characters Created: {(PlayerManager.GetAllOffline().Count + PlayerManager.GetAllOnline().Count):N0}{'\n'}"); // 330 active objects, 1931 total objects(16777216 buckets.) // todo, expand this var loadedLandblocks = LandblockManager.GetLoadedLandblocks(); int dormantLandblocks = 0, activeDungeonLandblocks = 0, dormantDungeonLandblocks = 0; int players = 0, creatures = 0, missiles = 0, other = 0, total = 0; foreach (var landblock in loadedLandblocks) { if (landblock.IsDormant) { dormantLandblocks++; } if (landblock.IsDungeon) { if (landblock.IsDormant) { dormantDungeonLandblocks++; } else { activeDungeonLandblocks++; } } foreach (var worldObject in landblock.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } else if (worldObject.Missile ?? false) { missiles++; } else { other++; } total++; } } sb.Append($"Landblocks: {(loadedLandblocks.Count - dormantLandblocks):N0} active ({activeDungeonLandblocks:N0} dungeons), {dormantLandblocks:N0} dormant ({dormantDungeonLandblocks:N0} dungeons) - Players: {players:N0}, Creatures: {creatures:N0}, Missiles: {missiles:N0}, Other: {other:N0}, Total: {total:N0}.{'\n'}"); // 11 total blocks loaded. 11 active. 0 pending dormancy. 0 dormant. 314 unloaded. // 11 total blocks loaded. 11 active. 0 pending dormancy. 0 dormant. 314 unloaded. if (ServerPerformanceMonitor.IsRunning) { sb.Append($"Server Performance Monitor - UpdateGameWorld ~5m {ServerPerformanceMonitor.GetEventHistory5m(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire).AverageEventDuration:N3}, ~1h {ServerPerformanceMonitor.GetEventHistory1h(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire).AverageEventDuration:N3} s{'\n'}"); } else { sb.Append($"Server Performance Monitor - Not running. To start use /serverperformance start{'\n'}"); } sb.Append($"Physics Cache Counts - BSPCache: {BSPCache.Count:N0}, GfxObjCache: {GfxObjCache.Count:N0}, PolygonCache: {PolygonCache.Count:N0}, VertexCache: {VertexCache.Count:N0}{'\n'}"); sb.Append($"Total Server Objects: {ServerObjectManager.ServerObjects.Count:N0}{'\n'}"); sb.Append($"World DB Cache Counts - Weenies: {DatabaseManager.World.GetWeenieCacheCount():N0}, LandblockInstances: {DatabaseManager.World.GetLandblockInstancesCacheCount():N0}, PointsOfInterest: {DatabaseManager.World.GetPointsOfInterestCacheCount():N0}, Cookbooks: {DatabaseManager.World.GetCookbookCacheCount():N0}, Spells: {DatabaseManager.World.GetSpellCacheCount():N0}, Encounters: {DatabaseManager.World.GetEncounterCacheCount():N0}, Events: {DatabaseManager.World.GetEventsCacheCount():N0}{'\n'}"); sb.Append($"Shard DB Counts - Biotas: {DatabaseManager.Shard.GetBiotaCount():N0}{'\n'}"); sb.Append(GuidManager.GetDynamicGuidDebugInfo() + '\n'); sb.Append($"Portal.dat has {DatManager.PortalDat.FileCache.Count:N0} files cached of {DatManager.PortalDat.AllFiles.Count:N0} total{'\n'}"); sb.Append($"Cell.dat has {DatManager.CellDat.FileCache.Count:N0} files cached of {DatManager.CellDat.AllFiles.Count:N0} total{'\n'}"); CommandHandlerHelper.WriteOutputInfo(session, $"{sb}"); }
public static void HandleLandblockPerformance(Session session, params string[] parameters) { var sb = new StringBuilder(); var loadedLandblocks = LandblockManager.GetLoadedLandblocks(); // Filter out landblocks that haven't recorded a certain amount of events var sortedBy5mAverage = loadedLandblocks.Where(r => r.Monitor5m.EventHistory.TotalEvents >= 10).OrderByDescending(r => r.Monitor5m.EventHistory.AverageEventDuration).Take(10).ToList(); var sortedBy1hrAverage = loadedLandblocks.Where(r => r.Monitor1h.EventHistory.TotalEvents >= 1000).OrderByDescending(r => r.Monitor1h.EventHistory.AverageEventDuration).Take(10).ToList(); var combinedByAverage = sortedBy5mAverage.Concat(sortedBy1hrAverage).Distinct().OrderByDescending(r => Math.Max(r.Monitor5m.EventHistory.AverageEventDuration, r.Monitor1h.EventHistory.AverageEventDuration)).Take(10); sb.Append($"Most Busy Landblock - By Average{'\n'}"); sb.Append($"~5m Hits Avg Long Last - ~1h Hits Avg Long Last - Location Players Creatures{'\n'}"); foreach (var entry in combinedByAverage) { int players = 0, creatures = 0; foreach (var worldObject in entry.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } } sb.Append($"{entry.Monitor5m.EventHistory.TotalEvents.ToString().PadLeft(7)} {entry.Monitor5m.EventHistory.AverageEventDuration:N4} {entry.Monitor5m.EventHistory.LongestEvent:N3} {entry.Monitor5m.EventHistory.LastEvent:N3} - " + $"{entry.Monitor1h.EventHistory.TotalEvents.ToString().PadLeft(7)} {entry.Monitor1h.EventHistory.AverageEventDuration:N4} {entry.Monitor1h.EventHistory.LongestEvent:N3} {entry.Monitor1h.EventHistory.LastEvent:N3} - " + $"0x{entry.Id.Raw:X8} {players.ToString().PadLeft(7)} {creatures.ToString().PadLeft(9)}{'\n'}"); } var sortedBy5mLong = loadedLandblocks.OrderByDescending(r => r.Monitor5m.EventHistory.LongestEvent).Take(10); var sortedBy1hrLong = loadedLandblocks.OrderByDescending(r => r.Monitor1h.EventHistory.LongestEvent).Take(10); var combinedByLong = sortedBy5mLong.Concat(sortedBy1hrLong).Distinct().OrderByDescending(r => Math.Max(r.Monitor5m.EventHistory.LongestEvent, r.Monitor1h.EventHistory.LongestEvent)).Take(10); sb.Append($"Most Busy Landblock - By Longest{'\n'}"); sb.Append($"~5m Hits Avg Long Last - ~1h Hits Avg Long Last - Location Players Creatures{'\n'}"); foreach (var entry in combinedByLong) { int players = 0, creatures = 0; foreach (var worldObject in entry.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } } sb.Append($"{entry.Monitor5m.EventHistory.TotalEvents.ToString().PadLeft(7)} {entry.Monitor5m.EventHistory.AverageEventDuration:N4} {entry.Monitor5m.EventHistory.LongestEvent:N3} {entry.Monitor5m.EventHistory.LastEvent:N3} - " + $"{entry.Monitor1h.EventHistory.TotalEvents.ToString().PadLeft(7)} {entry.Monitor1h.EventHistory.AverageEventDuration:N4} {entry.Monitor1h.EventHistory.LongestEvent:N3} {entry.Monitor1h.EventHistory.LastEvent:N3} - " + $"0x{entry.Id.Raw:X8} {players.ToString().PadLeft(7)} {creatures.ToString().PadLeft(9)}{'\n'}"); } CommandHandlerHelper.WriteOutputInfo(session, sb.ToString()); }