public async Task ServerInfo(string serverKey, ServerInfo serverInfo, OnlinePlayer[] onlinePlayers) { var context = _contextManager.GetServer(serverKey); if (context == null) { return; } // store the server key in this connection (could probably do this within authentication later) if (!Context.Items.ContainsKey("serverKey")) { Context.Items.Add("serverKey", serverKey); } else { Context.Items["serverKey"] = serverKey; } context.Data.ServerInfo = serverInfo; var unixTime = DateTimeOffset.FromUnixTimeMilliseconds(context.Data.ServerInfo.UtcTime); await _databaseRepo.AddorUpdatePlayers(onlinePlayers.Select(x => { var loginTime = unixTime.AddSeconds(x.Time - context.Data.ServerInfo.GameTime).UtcDateTime; return(ulong.Parse(x.SteamId), serverKey, (DateTime?)loginTime, DateTime.UtcNow, true); }).ToArray()); }
private void OnManuallyTriggerServerUpdate(string serverKey) { var context = _contextManager.GetServer(serverKey); if (context == null) { MessageBox.Show($"Could not find server instance '{serverKey}'", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } _contextManager.QueueUpdateServerManual(context); }
public async Task Servers([Remainder] string arguments = null) { var args = CommandHelper.ParseArgs(arguments, new { cluster = false, clusters = false }, x => x.For(y => y.cluster, flag: true) .For(y => y.clusters, flag: true)); if (_config.Servers != null) { var embed = new EmbedBuilder(); embed.WithTitle("Server List"); foreach (var server in _config.Servers) { var serverContext = _contextManager.GetServer(server.Key); var address = server.DisplayAddress ?? $"{server.Ip}:{server.QueryPort}"; var cluster = args.cluster || args.clusters ? $" (cluster **`{server.ClusterKey}`**)" : ""; embed.AddField($"{ address}", $"steam://connect/{address} (key: `{server.Key}`){cluster}", true); } await Context.Channel.SendMessageAsync("", false, embed.Build()); } else { await Context.Channel.SendMessageAsync("There are no servers available."); return; } }
public async Task <HttpResponseMessage> SaveWorld(string id) { var serverContext = _contextManager.GetServer(id); if (serverContext == null) { return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Server instance key not found!")); } var result = await serverContext.Steam.SendRconCommand($"SaveWorld"); if (result == null) { return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Timeout while waiting for command response...")); } return(Request.CreateResponse(HttpStatusCode.OK, new AdministerResponseViewModel { Message = "World saved! Please wait for server update (new data)..." })); }
public async Task Rcon([Remainder] string arguments = null) { var args = CommandHelper.ParseArgs(arguments, new { ServerKey = "", Command = "" }, x => x.For(y => y.ServerKey, noPrefix: true, isRequired: true) .For(y => y.Command, noPrefix: true, isRequired: true, untilNextToken: true)); var sb = new StringBuilder(); var serverContext = args?.ServerKey != null?_contextManager.GetServer(args.ServerKey) : null; if (serverContext == null) { await Context.Channel.SendMessageAsync($"**Rcon commands need to be prefixed with a valid server instance key.**"); return; } if (args == null) { var syntaxHelp = MethodBase.GetCurrentMethod().GetCustomAttribute <SyntaxHelpAttribute>()?.SyntaxHelp; var name = MethodBase.GetCurrentMethod().GetCustomAttribute <CommandAttribute>()?.Text; await Context.Channel.SendMessageAsync(string.Join(Environment.NewLine, new string[] { $"**My logic circuits cannot process this command! I am just a bot after all... :(**", !string.IsNullOrWhiteSpace(syntaxHelp) ? $"Help me by following this syntax: **!{name}** {syntaxHelp}" : null }.Where(x => x != null))); return; } var result = await serverContext.Steam.SendRconCommand(args.Command); if (result == null) { sb.AppendLine("**Failed to send rcon command... :(**"); } else { sb.AppendLine($"```{result}```"); } var msg = sb.ToString(); if (!string.IsNullOrWhiteSpace(msg)) { await CommandHelper.SendPartitioned(Context.Channel, sb.ToString()); } }
public ServerViewModel Get(string id) //, int? limit) { var context = _contextManager.GetServer(id); if (context == null) { return(null); } var demoMode = IsDemoMode() ? new DemoMode() : null; var result = new ServerViewModel { MapName = context.SaveState?.MapName }; if (HasFeatureAccess("server", "players") && context.Players != null) { result.Players.AddRange(context.Players.Select(x => { var tribe = x.TribeId != null ? context.Tribes?.FirstOrDefault(y => y.Id == x.TribeId) : null; return(new PlayerReferenceViewModel { Id = x.Id, SteamId = x.SteamId, FakeSteamId = demoMode?.GetSteamId(x.SteamId), CharacterName = demoMode?.GetPlayerName(x.Id) ?? x.CharacterName, SteamName = null, TribeName = tribe != null ? demoMode?.GetTribeName(tribe.Id) ?? tribe.Name : null, TribeId = x.TribeId, LastActiveTime = x.LastActiveTime }); }).OrderByDescending(x => x.LastActiveTime).Where(x => x.LastActiveTime >= DateTime.UtcNow.AddDays(-90))); } if (HasFeatureAccess("server", "tribes") && context.Tribes != null) { result.Tribes.AddRange(context.Tribes.Select(x => { var members = context.Players?.Where(y => x.MemberIds.Contains((int)y.Id)).ToList() ?? new List <ArkPlayer>(); return(new TribeReferenceViewModel { Id = x.Id, Name = demoMode?.GetTribeName(x.Id) ?? x.Name, MemberSteamIds = members.Select(y => y.SteamId).ToList(), LastActiveTime = x.LastActiveTime }); }).OrderByDescending(x => x.LastActiveTime).Where(x => x.LastActiveTime >= DateTime.UtcNow.AddDays(-90))); } return(result); }
public async Task TimerUpdateVotes() { using (var db = _databaseContextFactory.Create()) { var elapsedBans = db.Votes.OfType <BanVote>().Where(x => x.Result == VoteResult.Passed && x.BannedUntil.HasValue && x.BannedUntil <= DateTime.Now).ToArray(); foreach (var ban in elapsedBans) { var serverContext = _contextManager.GetServer(ban.ServerKey); if (serverContext == null) { Logging.Log($"Failed to automatically unban player {ban.SteamId} on server ({ban.ServerKey}) because the server was not found.", typeof(ArkDiscordBot), LogLevel.WARN); continue; } if (await serverContext.Steam.SendRconCommand($"unbanplayer {ban.SteamId}") != null) { ban.BannedUntil = null; } } db.SaveChanges(); } }
public ServerViewModel Get(string id) //, int? limit) { var context = _contextManager.GetServer(id); if (context == null) { return(null); } var result = new ServerViewModel { }; if (context.Players != null) { result.Players.AddRange(context.Players.Select(x => { return(new PlayerReferenceViewModel { Id = x.Id, SteamId = x.SteamId, CharacterName = x.CharacterName, SteamName = null, TribeName = x.TribeId != null ? context.Tribes?.FirstOrDefault(y => y.Id == x.TribeId)?.Name : null, TribeId = x.TribeId, LastActiveTime = x.SavedAt }); }).OrderByDescending(x => x.LastActiveTime).Where(x => x.LastActiveTime >= DateTime.UtcNow.AddDays(-90))); } if (context.Tribes != null) { result.Tribes.AddRange(context.Tribes.Select(x => { var members = context.Players?.Where(y => x.MemberIds.Contains((int)y.Id)).ToList() ?? new List <ArkPlayer>(); return(new TribeReferenceViewModel { Id = x.Id, Name = x.Name, MemberSteamIds = members.Select(y => y.SteamId).ToList(), LastActiveTime = members.Count > 0 ? members.Max(y => y.SavedAt) : x.SavedAt }); }).OrderByDescending(x => x.LastActiveTime).Where(x => x.LastActiveTime >= DateTime.UtcNow.AddDays(-90))); } return(result); }
public async Task Servers([Remainder] string arguments = null) { var args = CommandHelper.ParseArgs(arguments, new { cluster = false, clusters = false }, x => x.For(y => y.cluster, flag: true) .For(y => y.clusters, flag: true)); if (_config.Servers != null) { var sb = new StringBuilder(); sb.AppendLine("**Server List**"); foreach (var server in _config.Servers) { var serverContext = _contextManager.GetServer(server.Key); var info = serverContext.Steam.GetServerInfoCached(); string name = null; if (info != null) { var m = new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(info.Name); name = m.Success ? m.Groups["name"].Value : info.Name; } var address = $"{server.Ip}:{server.Port}"; var cluster = args.cluster || args.clusters ? $" (cluster **{server.Cluster}**)" : ""; sb.AppendLine( $"● **{name ?? address}**{(name != null ? $" ({address})" : "")} (key: **{server.Key}**){cluster}"); } await CommandHelper.SendPartitioned(Context.Channel, sb.ToString()); } else { await Context.Channel.SendMessageAsync("There are no servers available."); return; } }
public async Task Servers([Remainder] string arguments = null) { var args = CommandHelper.ParseArgs(arguments, new { cluster = false, clusters = false }, x => x.For(y => y.cluster, flag: true) .For(y => y.clusters, flag: true)); if (_config.Servers != null) { var embed = new EmbedBuilder(); embed.WithTitle("Server List"); foreach (var server in _config.Servers) { var serverContext = _contextManager.GetServer(server.Key); var info = serverContext.Steam.GetServerInfoCached(); string name = null; if (info != null) { var m = new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(info.Name); name = m.Success ? m.Groups["name"].Value : info.Name; } var address = server.DisplayAddress ?? $"{server.Ip}:{server.QueryPort}"; var cluster = args.cluster || args.clusters ? $" (cluster **`{server.ClusterKey}`**)" : ""; embed.AddField($"{ name ?? address}", $"steam://connect/{address} (key: `{server.Key}`){cluster}", true); } await Context.Channel.SendMessageAsync("", false, embed.Build()); } else { await Context.Channel.SendMessageAsync("There are no servers available."); return; } }
public async Task <IActionResult> SaveWorld(string id) { var serverContext = _contextManager.GetServer(id); if (serverContext == null) { return(BadRequest("Server instance key not found!")); } var result = await serverContext.Steam.SendRconCommand($"SaveWorld"); if (result == null) { return(InternalServerError("Timeout while waiting for command response...")); } return(Ok(new AdministerResponseViewModel { Message = "World saved! Please wait for server update (new data)..." })); }
public async Task Run(CommandEventArgs e) { if (!e.Channel.IsPrivate) { return; } var args = CommandHelper.ParseArgs(e, new { logs = false, json = false, save = false, database = false, stats = false, clear = false, key = "", data = "" }, x => x.For(y => y.logs, flag: true) .For(y => y.json, flag: true) .For(y => y.save, flag: true) .For(y => y.database, flag: true) .For(y => y.stats, flag: true) .For(y => y.clear, flag: true) .For(y => y.key, untilNextToken: true) .For(y => y.data, untilNextToken: true)); if (args == null) { await e.Channel.SendMessage(string.Join(Environment.NewLine, new string[] { $"**My logic circuits cannot process this command! I am just a bot after all... :(**", !string.IsNullOrWhiteSpace(SyntaxHelp) ? $"Help me by following this syntax: **!{Name}** {SyntaxHelp}" : null }.Where(x => x != null))); return; } if (args.stats) { var sb = new StringBuilder(); sb.AppendLine("**ARK Survival Discord Bot Statistics**"); if (File.Exists(_constants.DatabaseFilePath)) { sb.AppendLine($"● **Database size:** {FileHelper.ToFileSize(new FileInfo(_constants.DatabaseFilePath).Length)}"); } await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); } else if (args.logs) { var pattern = "*.log"; var files = Directory.GetFiles(".\\logs\\", pattern, SearchOption.TopDirectoryOnly); if (files == null || files.Length <= 0) { await e.Channel.SendMessage("Could not find any logs... :("); return; } if (args.clear) { foreach (var file in files) { File.Delete(file); } await e.Channel.SendMessage("Cleared all log files!"); return; } else { var path = Path.Combine(_config.TempFileOutputDirPath, "logs_" + DateTime.Now.ToString("yyyy-MM-dd.HH.mm.ss.ffff") + ".zip"); try { FileHelper.CreateZipArchive(files, path); await e.Channel.SendFile(path); } catch { await e.Channel.SendMessage("Failed to archive log files... :("); return; } finally { if (File.Exists(path)) { File.Delete(path); } } } } else if (args.json) { if (_config.DisableDeveloperFetchSaveData) { await e.Channel.SendMessage("The administrator have disabled this feature."); return; } var files = new List <string>(); var tempfiles = new List <string>(); var basepath = _config.JsonOutputDirPath; if (!string.IsNullOrEmpty(args.key)) { //todo: no cluster data support var server = _contextManager.GetServer(args.key); if (server == null) { await e.Channel.SendMessage("The key did not exist."); return; } var data = args.data?.Split(',', ';', '|'); if (!(data?.Length > 0)) { await e.Channel.SendMessage("No data items supplied."); return; } foreach (var d in data) { var key = d.Trim().ToLower(); dynamic obj = null; switch (key) { case "wild": obj = server.WildCreatures; break; case "tamed": obj = server.TamedCreatures; break; case "players": obj = server.Players; break; case "tribes": obj = server.Tribes; break; case "items": obj = server.Items; break; case "structures": obj = server.Structures; break; } if (obj != null) { var json = JsonConvert.SerializeObject(obj); var jsonPath = Path.Combine(_config.TempFileOutputDirPath, $"json_{key}_" + DateTime.Now.ToString("yyyy-MM-dd.HH.mm.ss.ffff") + ".json"); tempfiles.Add(jsonPath); files.Add(jsonPath); File.WriteAllText(jsonPath, json); } } basepath = _config.TempFileOutputDirPath; } else { var pattern = "*.json"; var _files = Directory.GetFiles(_config.JsonOutputDirPath, pattern, SearchOption.AllDirectories); if (_files == null || _files.Length <= 0) { await e.Channel.SendMessage("Could not find any json files... :("); return; } files.AddRange(_files); } var path = Path.Combine(_config.TempFileOutputDirPath, "json_" + DateTime.Now.ToString("yyyy-MM-dd.HH.mm.ss.ffff") + ".zip"); string[] results = null; try { results = FileHelper.CreateDotNetZipArchive(new[] { new Tuple <string, string, string[]>(basepath, "", files.ToArray()) }, path, 5 * 1024 * 1024); tempfiles.AddRange(results); foreach (var item in results) { await e.Channel.SendFile(item); } } catch { await e.Channel.SendMessage("Failed to archive json files... :("); return; } finally { foreach (var p in tempfiles) { if (File.Exists(p)) { File.Delete(p); } } } await Task.Delay(500); await e.Channel.SendMessage($"[parts {results.Length}]"); } else if (args.save) { if (_config.DisableDeveloperFetchSaveData) { await e.Channel.SendMessage("The administrator have disabled this feature."); return; } var saveFilePath = _config.SaveFilePath; var clusterSavePath = _config.ClusterSavePath; if (!string.IsNullOrEmpty(args.key)) { var server = _config.Servers?.FirstOrDefault(x => x.Key.Equals(args.key, StringComparison.OrdinalIgnoreCase)); if (server == null) { await e.Channel.SendMessage("The key did not exist."); return; } saveFilePath = server.SaveFilePath; var cluster = !string.IsNullOrEmpty(server.Cluster) ? _config.Clusters?.FirstOrDefault(x => x.Key.Equals(server.Cluster, StringComparison.OrdinalIgnoreCase)) : null; clusterSavePath = cluster?.SavePath; } var dir = Path.GetDirectoryName(saveFilePath); var files = new[] { File.Exists(saveFilePath) ? new Tuple <string, string, string[]>("", "", new [] { saveFilePath }) : null, Directory.Exists(dir) ? new Tuple <string, string, string[]>("", "", Directory.GetFiles(dir, "*.arkprofile", SearchOption.TopDirectoryOnly)) : null, Directory.Exists(dir) ? new Tuple <string, string, string[]>("", "", Directory.GetFiles(dir, "*.arktribe", SearchOption.TopDirectoryOnly)) : null, !string.IsNullOrEmpty(clusterSavePath) ? new Tuple <string, string, string[]>(clusterSavePath, "cluster", Directory.GetFiles(clusterSavePath, "*", SearchOption.AllDirectories)) : null }.Where(x => x != null && x.Item2 != null).ToArray(); if (files == null || !files.Any(x => x.Item2 != null && x.Item2.Length > 0)) { await e.Channel.SendMessage("Could not find any save files... :("); return; } var path = Path.Combine(_config.TempFileOutputDirPath, "save_" + (!string.IsNullOrEmpty(args.key) ? $"{args.key}_" : "") + DateTime.Now.ToString("yyyy-MM-dd.HH.mm.ss.ffff") + ".zip"); string[] results = null; try { results = FileHelper.CreateDotNetZipArchive(files, path, 5 * 1024 * 1024); foreach (var item in results) { await e.Channel.SendFile(item); } } catch { await e.Channel.SendMessage("Failed to archive save files... :("); return; } finally { if (results != null) { foreach (var item in results) { if (File.Exists(item)) { File.Delete(item); } } } } await Task.Delay(500); await e.Channel.SendMessage($"[parts {results.Length}]"); } else if (args.database) { var file = File.Exists(_constants.DatabaseFilePath) ? _constants.DatabaseFilePath : null; if (file == null) { await e.Channel.SendMessage("Could not find the database file... :("); return; } var path = Path.Combine(_config.TempFileOutputDirPath, "database_" + DateTime.Now.ToString("yyyy-MM-dd.HH.mm.ss.ffff") + ".zip"); string[] results = null; try { results = FileHelper.CreateDotNetZipArchive(new[] { new Tuple <string, string, string[]>("", "", new[] { file }) }, path, 5 * 1024 * 1024); foreach (var item in results) { await e.Channel.SendFile(item); } } catch { await e.Channel.SendMessage("Failed to archive database file... :("); return; } finally { if (results != null) { foreach (var item in results) { if (File.Exists(item)) { File.Delete(item); } } } } } }
public async Task Run(CommandEventArgs e) { if (!_context.IsInitialized) { await e.Channel.SendMessage($"**The data is loading but is not ready yet...**"); return; } //var args = CommandHelper.ParseArgs(e, new { Extended = false }, x => // x.For(y => y.Extended, flag: true)); var playersx = e.Message.Text.StartsWith("!playersx", StringComparison.OrdinalIgnoreCase); var serverContext = _contextManager.GetServer(_config.ServerKey); var serverInfo = serverContext.Steam.GetServerInfoCached(); var playerInfo = serverContext.Steam.GetServerPlayersCached(); var sb = new StringBuilder(); if (serverInfo == null || playerInfo == null) { sb.AppendLine($"**Player list is currently unavailable!**"); } else { var players = playerInfo?.Where(x => !string.IsNullOrEmpty(x.Name)).ToArray() ?? new PlayerInfo[] { }; var m = new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(serverInfo.Name); var name = m.Success ? m.Groups["name"].Value : serverInfo.Name; sb.AppendLine($"**{name} ({serverInfo.Players - (playerInfo.Count - players.Length)}/{serverInfo.MaxPlayers})**"); if (playersx) { using (var db = _databaseContextFactory.Create()) { var playerNames = players.Select(x => x.Name).ToArray(); var d = _context.Players.Where(x => playerNames.Contains(x.PlayerName, StringComparer.Ordinal)).Select(x => { long steamId; return(new Tuple <Data.Player, Database.Model.User, User, long?, TimeSpan>( x, null, null, long.TryParse(x.SteamId, out steamId) ? steamId : (long?)null, TimeSpan.Zero)); }).ToDictionary(x => x.Item1.PlayerName, StringComparer.OrdinalIgnoreCase); var ids = new List <int>(); var steamIds = d.Values.Select(x => x.Item4).Where(x => x != null).ToArray(); foreach (var user in db.Users.Where(y => steamIds.Contains(y.SteamId))) { var item = d.Values.FirstOrDefault(x => x.Item4 == user.SteamId); if (item == null) { continue; } ids.Add(item.Item1.Id); var discordUser = e.User?.Client?.Servers?.Select(x => x.GetUser((ulong)user.DiscordId)).FirstOrDefault(); var playedLastSevenDays = TimeSpan.FromSeconds(user?.Played?.OrderByDescending(x => x.Date).Take(7).Sum(x => x.TimeInSeconds) ?? 0); d[item.Item1.PlayerName] = new Tuple <Data.Player, Database.Model.User, User, long?, TimeSpan>(item.Item1, user, discordUser, item.Item4, playedLastSevenDays); } var remaining = d.Values.Where(x => !ids.Contains(x.Item1.Id)).Where(x => x.Item4 != null).Select(x => x.Item4.Value).ToArray(); foreach (var user in db.Played.Where(x => x.SteamId.HasValue && remaining.Contains(x.SteamId.Value)) .GroupBy(x => x.SteamId) .Select(x => new { key = x.Key, items = x.OrderByDescending(y => y.Date).Take(7).ToList() }) .ToArray()) { var item = d.Values.FirstOrDefault(x => x.Item4 == user.key); if (item == null) { continue; } var playedLastSevenDays = TimeSpan.FromSeconds(user?.items?.Sum(x => x.TimeInSeconds) ?? 0); d[item.Item1.PlayerName] = new Tuple <Data.Player, Database.Model.User, User, long?, TimeSpan>(item.Item1, item.Item2, item.Item3, item.Item4, playedLastSevenDays); } //var playerslist = players.Select(x => { // var extra = d.ContainsKey(x.Name) ? d[x.Name] : null; // return new // { // Steam = x.Name, // Name = extra?.Item1?.Name, // Tribe = extra?.Item1?.TribeName, // Discord = extra != null && extra.Item3 != null ? $"{extra.Item3.Name}#{extra.Item3.Discriminator}" : null, // TimeOnline = x.Time.ToStringCustom(), // PlayedLastSevenDays = extra != null && extra.Item5.TotalMinutes > 1 ? extra?.Item5.ToStringCustom() : null // }; //}).ToArray(); //sb.AppendLine("```"); //sb.AppendLine(FixedWidthTableHelper.ToString(playerslist, x => x // .For(y => y.TimeOnline, "Online For", alignment: 1) // .For(y => y.PlayedLastSevenDays, "Played/last 7 days", alignment: 1))); //sb.AppendLine("```"); foreach (var player in players) { var extra = d.ContainsKey(player.Name) ? d[player.Name] : null; sb.AppendLine($"● **{player.Name}" + (extra != null && extra.Item1.Name != null ? $" ({extra.Item1.Name})" + (extra.Item1.TribeName != null ? $" [{extra.Item1.TribeName}]" : "") : "") + "**" + (extra != null && extra.Item3 != null ? $" - **{extra.Item3.Name}#{extra.Item3.Discriminator}**" : "") + (player.Time != TimeSpan.Zero ? " (" + player.Time.ToStringCustom() + ")" : "") + (extra != null && extra.Item5.TotalMinutes > 1 ? " [" + extra.Item5.ToStringCustom() + " last 7d]" : null)); } } } else { foreach (var player in players) { sb.AppendLine($"● **{player.Name}** ({player.Time.ToStringCustom()})"); } } } await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); }
public async Task Admin([Remainder] string arguments = null) { //if (!e.Channel.IsPrivate) return; var args = CommandHelper.ParseArgs(arguments, new { ServerKey = "", StartServer = false, StartServers = false, ShutdownServer = false, ShutdownServers = false, StopServer = false, StopServers = false, TerminateServer = false, RestartServer = false, RestartServers = false, UpdateServer = false, UpdateServers = false, Backups = false, SteamId = 0L, SaveWorld = false, DestroyWildDinos = false, EnableVoting = false, SetVotingAllowed = 0L, //steam id KickPlayer = 0L, //steam id BanPlayer = 0L, //steam id UnbanPlayer = 0L, //steam id KillPlayer = 0L, //ark player id DoExit = false, Broadcast = "", ListPlayers = false, RenamePlayer = "", RenameTribe = "", NewName = "", ServerChat = "", ServerChatTo = 0L, //steam id ServerChatToPlayer = "", Message = "", GetPlayerIDForSteamID = 0L, //steam id GetSteamIDForPlayerID = 0L, //ark player id GetTribeIdPlayerList = 0L, SetTimeOfDay = "", Countdown = "", True = false, False = false }, x => x.For(y => y.ServerKey, noPrefix: true) .For(y => y.StartServer, flag: true) .For(y => y.StartServers, flag: true) .For(y => y.ShutdownServer, flag: true) .For(y => y.ShutdownServers, flag: true) .For(y => y.StopServer, flag: true) .For(y => y.StopServers, flag: true) .For(y => y.TerminateServer, flag: true) .For(y => y.RestartServer, flag: true) .For(y => y.RestartServers, flag: true) .For(y => y.UpdateServer, flag: true) .For(y => y.UpdateServers, flag: true) .For(y => y.Backups, flag: true) .For(y => y.SaveWorld, flag: true) .For(y => y.DestroyWildDinos, flag: true) .For(y => y.EnableVoting, flag: true) .For(y => y.DoExit, flag: true) .For(y => y.ListPlayers, flag: true) .For(y => y.Broadcast, untilNextToken: true) .For(y => y.RenamePlayer, untilNextToken: true) .For(y => y.RenameTribe, untilNextToken: true) .For(y => y.NewName, untilNextToken: true) .For(y => y.ServerChat, untilNextToken: true) .For(y => y.ServerChatToPlayer, untilNextToken: true) .For(y => y.Message, untilNextToken: true) .For(y => y.Countdown, untilNextToken: true) .For(y => y.True, flag: true) .For(y => y.False, flag: true)); var _rTimeOfDay = new Regex(@"^\s*\d{2,2}\:\d{2,2}(\:\d{2,2})?\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); var _rCountdown = new Regex(@"^\s*(?<min>\d+)\s+(?<reason>.+)$", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); var sb = new StringBuilder(); var isCountdown = !string.IsNullOrEmpty(args.Countdown) && _rCountdown.IsMatch(args.Countdown); var isMultiServerCommand = args != null && (isCountdown || args.StartServer || args.StartServers || args.StopServer || args.StopServers || args.ShutdownServer || args.ShutdownServers || args.RestartServer || args.RestartServers || args.UpdateServer || args.UpdateServers); var serverContext = args?.ServerKey != null?_contextManager.GetServer(args.ServerKey) : null; if (serverContext == null && !isMultiServerCommand) { await Context.Channel.SendMessageAsync($"**Admin commands need to be prefixed with a valid server instance key.**"); return; } // collection of servers that this countdown applies to var serverContexts = serverContext == null && !string.IsNullOrWhiteSpace(args.ServerKey) ? null : serverContext == null?_contextManager.Servers.ToArray() : new ArkServerContext[] { serverContext }; if (serverContexts == null) { await Context.Channel.SendMessageAsync($"**The given server instance key is not valid.**"); return; } if (isCountdown) { var m = _rCountdown.Match(args.Countdown); var reason = m.Groups["reason"].Value; var delayInMinutes = int.Parse(m.Groups["min"].Value); if (delayInMinutes < 1) { delayInMinutes = 1; } Func <Task> react = null; if (args.StopServer || args.StopServers || args.ShutdownServer || args.ShutdownServers) { react = new Func <Task>(async() => { var tasks = serverContexts.Select(x => Task.Run(async() => { string message = null; if (!await _arkServerService.ShutdownServer(x.Config.Key, (s) => { message = s; return(Task.FromResult((IUserMessage)null)); })) { Logging.Log($@"Countdown to shutdown server ({x.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } })).ToArray(); await Task.WhenAll(tasks); }); } else if (args.UpdateServer || args.UpdateServers) { react = new Func <Task>(async() => { var tasks = serverContexts.Select(x => Task.Run(async() => { string message = null; if (!await _arkServerService.UpdateServer(x.Config.Key, (s) => { message = s; return(Task.FromResult((IUserMessage)null)); }, (s) => s.FirstCharToUpper(), 300)) { Logging.Log($@"Countdown to update server ({x.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } })).ToArray(); await Task.WhenAll(tasks); }); } else if (args.RestartServer || args.RestartServers) { react = new Func <Task>(async() => { var tasks = serverContexts.Select(x => Task.Run(async() => { string message = null; if (!await _arkServerService.RestartServer(x.Config.Key, (s) => { message = s; return(Task.FromResult((IUserMessage)null)); })) { Logging.Log($@"Countdown to restart server ({x.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } })).ToArray(); await Task.WhenAll(tasks); }); } sb.AppendLine($"**Countdown{(serverContext == null ? "" : $" on server {serverContext.Config.Key}")} have been initiated. Announcement will be made.**"); await _scheduledTasksManager.StartCountdown(serverContext, reason, delayInMinutes, react); }
public WildCreaturesViewModel Get(string id) { var context = _contextManager.GetServer(id); if (context == null) { return(null); } var demoMode = IsDemoMode() ? new DemoMode() : null; var result = new WildCreaturesViewModel { }; // access control var incWildCreatures = HasFeatureAccess("server", "wildcreatures", id); var incWildCreaturesBaseStats = HasFeatureAccess("server", "wildcreatures-basestats", id); var incStatistics = HasFeatureAccess("server", "wildcreatures-statistics", id); var speciesGroups = context.WildCreatures.GroupBy(x => x.ClassName) .ToDictionary(x => x.Key, x => new { items = x.ToArray(), aliases = ArkSpeciesAliases.Instance.GetAliases(x.Key) }); if (incWildCreatures) { var species = speciesGroups.Select(x => { var vms = new WildCreatureSpeciesViewModel { ClassName = x.Key, Name = x.Value.aliases?.FirstOrDefault(), Aliases = x.Value.aliases?.Skip(2).ToArray() ?? new string[] { }, //skip primary name and class name IsTameable = !UntameableClassNames.Contains(x.Key, StringComparer.OrdinalIgnoreCase) }; vms.Creatures.AddRange(x.Value.items.Select(y => { var vmc = new WildCreatureViewModel { Id1 = y.Id1, Id2 = y.Id2, Gender = y.Gender.ToString(), BaseLevel = y.BaseLevel, X = y.Location?.X.Round(0), Y = y.Location?.Y.Round(0), Z = y.Location?.Z.Round(0), IsTameable = y.IsTameable, Latitude = y.Location?.Latitude, Longitude = y.Location?.Longitude, TopoMapX = y.Location?.TopoMapX, TopoMapY = y.Location?.TopoMapY }; if (incWildCreaturesBaseStats) { //0: health //1: stamina //2: torpor //3: oxygen //4: food //5: water //6: temperature //7: weight //8: melee damage //9: movement speed //10: fortitude //11: crafting speed vmc.BaseStats = new CreatureBaseStatsViewModel { Health = y.BaseStats[0], Stamina = y.BaseStats[1], Oxygen = y.BaseStats[3], Food = y.BaseStats[4], Weight = y.BaseStats[7], Melee = y.BaseStats[8], MovementSpeed = y.BaseStats[9] }; } return(vmc); }).OrderByDescending(y => y.BaseLevel).ThenBy(y => y.Gender)); return(vms); }).ToArray(); foreach (var s in species) { result.Species.Add(s.ClassName, s); } } var totalCount = context.WildCreatures.Length; var stats = new WildCreatureStatistics { CreatureCount = totalCount }; if (incStatistics) { stats.Species.AddRange(speciesGroups.Select(x => { var vmcs = new WildCreatureSpeciesStatistics { ClassName = x.Key, Name = x.Value.aliases?.FirstOrDefault(), Aliases = x.Value.aliases?.Skip(2).ToArray() ?? new string[] { }, //skip primary name and class name Count = x.Value.items.Count(), Fraction = x.Value.items.Count() / (float)totalCount }; return(vmcs); }).OrderBy(x => x.Name).ThenByDescending(x => x.Count)); } result.Statistics = stats; return(result); }
public async Task Run(CommandEventArgs e) { //if (!e.Channel.IsPrivate) return; var args = CommandHelper.ParseArgs(e, new { ServerKey = "", StartServer = false, ShutdownServer = false, StopServer = false, RestartServer = false, UpdateServer = false, Backups = false, SaveWorld = false, DestroyWildDinos = false, EnableVoting = false, SetVotingAllowed = 0L, //steam id KickPlayer = 0L, //steam id BanPlayer = 0L, //steam id UnbanPlayer = 0L, //steam id KillPlayer = 0L, //ark player id DoExit = false, Broadcast = "", ListPlayers = false, RenamePlayer = "", RenameTribe = "", NewName = "", ServerChat = "", ServerChatTo = 0L, //steam id ServerChatToPlayer = "", Message = "", GetPlayerIDForSteamID = 0L, //steam id GetSteamIDForPlayerID = 0L, //ark player id GetTribeIdPlayerList = 0L, SetTimeOfDay = "", Countdown = "", True = false, False = false }, x => x.For(y => y.ServerKey, noPrefix: true, isRequired: true) .For(y => y.StartServer, flag: true) .For(y => y.ShutdownServer, flag: true) .For(y => y.StopServer, flag: true) .For(y => y.RestartServer, flag: true) .For(y => y.UpdateServer, flag: true) .For(y => y.Backups, flag: true) .For(y => y.SaveWorld, flag: true) .For(y => y.DestroyWildDinos, flag: true) .For(y => y.EnableVoting, flag: true) .For(y => y.DoExit, flag: true) .For(y => y.ListPlayers, flag: true) .For(y => y.Broadcast, untilNextToken: true) .For(y => y.RenamePlayer, untilNextToken: true) .For(y => y.RenameTribe, untilNextToken: true) .For(y => y.NewName, untilNextToken: true) .For(y => y.ServerChat, untilNextToken: true) .For(y => y.ServerChatToPlayer, untilNextToken: true) .For(y => y.Message, untilNextToken: true) .For(y => y.Countdown, untilNextToken: true) .For(y => y.True, flag: true) .For(y => y.False, flag: true)); var _rTimeOfDay = new Regex(@"^\s*\d{2,2}\:\d{2,2}(\:\d{2,2})?\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); var _rCountdown = new Regex(@"^\s*(?<min>\d+)\s+(?<reason>.+)$", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); var sb = new StringBuilder(); var serverContext = args?.ServerKey != null?_contextManager.GetServer(args.ServerKey) : null; if (serverContext == null) { await e.Channel.SendMessage($"**Admin commands need to be prefixed with a valid server instance key.**"); return; } if (args.StartServer) { await _arkServerService.StartServer(serverContext.Config.Key, (s) => e.Channel.SendMessageDirectedAt(e.User.Id, s)); } else if (args.Countdown == null && (args.ShutdownServer || args.StopServer)) { await _arkServerService.ShutdownServer(serverContext.Config.Key, (s) => e.Channel.SendMessageDirectedAt(e.User.Id, s)); } else if (args.Countdown == null && args.RestartServer) { await _arkServerService.RestartServer(serverContext.Config.Key, (s) => e.Channel.SendMessageDirectedAt(e.User.Id, s)); } else if (args.Countdown == null && args.UpdateServer) { await _arkServerService.UpdateServer(serverContext.Config.Key, (s) => e.Channel.SendMessageDirectedAt(e.User.Id, s), (s) => e.Channel.GetMessageDirectedAtText(e.User.Id, s), 300); } else if (args.SaveWorld) { await _arkServerService.SaveWorld(serverContext.Config.Key, (s) => e.Channel.SendMessageDirectedAt(e.User.Id, s), 180); } else if (args.Backups) { var result = _savegameBackupService.GetBackupsList(serverContext.Config.Key); if (result?.Count > 0) { var data = result.OrderByDescending(x => x.DateModified).Take(25).Select(x => new { Path = x.Path, Age = (DateTime.Now - x.DateModified).ToStringCustom(), FileSize = x.ByteSize.ToFileSize() }).ToArray(); var table = FixedWidthTableHelper.ToString(data, x => x .For(y => y.Path, header: "Backup") .For(y => y.Age, alignment: 1) .For(y => y.FileSize, header: "File Size", alignment: 1)); sb.Append($"```{table}```"); } else { sb.AppendLine("**Could not find any savegame backups...**"); } } else if (args.DestroyWildDinos) { var result = await serverContext.Steam.SendRconCommand("destroywilddinos"); if (result == null) { sb.AppendLine("**Failed to wipe wild dinos... :(**"); } else { sb.AppendLine("**Wild dinos wiped!**"); } } else if (args.DoExit) { var result = await serverContext.Steam.SendRconCommand("doexit"); if (result == null) { sb.AppendLine("**Failed to shutdown server... :(**"); } else { sb.AppendLine("**Server shutting down!**"); } } else if (args.ListPlayers) { var result = await serverContext.Steam.SendRconCommand("listplayers"); if (result == null) { sb.AppendLine("**Failed to get a list of players... :(**"); } else { sb.AppendLine(result); } } else if (!string.IsNullOrWhiteSpace(args.Broadcast)) { var result = await serverContext.Steam.SendRconCommand($"broadcast {args.Broadcast}"); if (result == null) { sb.AppendLine("**Failed to broadcast message... :(**"); } else { sb.AppendLine("**Broadcast successfull!**"); } } else if (!string.IsNullOrWhiteSpace(args.ServerChat)) { var result = await serverContext.Steam.SendRconCommand($"serverchat {args.ServerChat}"); if (result == null) { sb.AppendLine("**Failed to send chat message... :(**"); } else { sb.AppendLine("**Chat message send!**"); } } else if (args.ServerChatTo > 0 && !string.IsNullOrWhiteSpace(args.Message)) { var result = await serverContext.Steam.SendRconCommand($@"serverchatto {args.ServerChatTo} ""{args.Message}"""); if (result == null) { sb.AppendLine("**Failed to send direct chat message... :(**"); } else { sb.AppendLine("**Direct chat message send!**"); } } else if (!string.IsNullOrWhiteSpace(args.ServerChatToPlayer) && !string.IsNullOrWhiteSpace(args.Message)) { var result = await serverContext.Steam.SendRconCommand($@"serverchattoplayer ""{args.ServerChatToPlayer}"" ""{args.Message}"""); if (result == null) { sb.AppendLine("**Failed to send direct chat message... :(**"); } else { sb.AppendLine("**Direct chat message send!**"); } } else if (!string.IsNullOrWhiteSpace(args.RenamePlayer) && !string.IsNullOrWhiteSpace(args.NewName)) { var result = await serverContext.Steam.SendRconCommand($@"renameplayer ""{args.RenamePlayer}"" {args.NewName}"); if (result == null) { sb.AppendLine("**Failed to rename player... :(**"); } else { sb.AppendLine("**Player renamed!**"); } } else if (!string.IsNullOrWhiteSpace(args.RenameTribe) && !string.IsNullOrWhiteSpace(args.NewName)) { var result = await serverContext.Steam.SendRconCommand($@"renametribe ""{args.RenameTribe}"" {args.NewName}"); if (result == null) { sb.AppendLine("**Failed to rename tribe... :(**"); } else { sb.AppendLine("**Tribe renamed!**"); } } else if (!string.IsNullOrWhiteSpace(args.SetTimeOfDay) && _rTimeOfDay.IsMatch(args.SetTimeOfDay)) { var result = await serverContext.Steam.SendRconCommand($"settimeofday {args.SetTimeOfDay}"); if (result == null) { sb.AppendLine("**Failed to set time of day... :(**"); } else { sb.AppendLine("**Time of day set!**"); } } else if (args.KickPlayer > 0) { var result = await serverContext.Steam.SendRconCommand($"kickplayer {args.KickPlayer}"); if (result == null) { sb.AppendLine($"**Failed to kick player with steamid {args.KickPlayer}... :(**"); } else { sb.AppendLine($"**Kicked player with steamid {args.KickPlayer}!**"); } } else if (args.EnableVoting) { if (!(args.True || args.False)) { sb.AppendLine($"**This command requires additional arguments!**"); } else { using (var context = _databaseContextFactory.Create()) { _savedstate.VotingDisabled = !args.True; _savedstate.Save(); sb.AppendLine($"**Voting system is now {(_savedstate.VotingDisabled ? "disabled" : "enabled")}!**"); } } //var result = await CommandHelper.SendRconCommand(_config, $"kickplayer {args.KickPlayer}"); //if (result == null) sb.AppendLine($"**Failed to kick player with steamid {args.KickPlayer}... :(**"); //else sb.AppendLine($"**Kicked player with steamid {args.KickPlayer}!**"); } else if (args.SetVotingAllowed > 0) { if (!(args.True || args.False)) { sb.AppendLine($"**This command requires additional arguments!**"); } else { using (var context = _databaseContextFactory.Create()) { var user = context.Users.FirstOrDefault(x => x != null && x.DiscordId == (long)e.User.Id); if (user != null) { user.DisallowVoting = !args.True; context.SaveChanges(); sb.AppendLine($"**The user is now {(user.DisallowVoting ? "unable" : "allowed")} to vote!**"); } else { sb.AppendLine($"**The user is not linked!**"); } } } //var result = await CommandHelper.SendRconCommand(_config, $"kickplayer {args.KickPlayer}"); //if (result == null) sb.AppendLine($"**Failed to kick player with steamid {args.KickPlayer}... :(**"); //else sb.AppendLine($"**Kicked player with steamid {args.KickPlayer}!**"); } else if (args.BanPlayer > 0) { var result = await serverContext.Steam.SendRconCommand($"ban {args.BanPlayer}"); if (result == null) { sb.AppendLine($"**Failed to ban player with steamid {args.BanPlayer}... :(**"); } else { sb.AppendLine($"**Banned player with steamid {args.BanPlayer}!**"); } } else if (args.UnbanPlayer > 0) { var result = await serverContext.Steam.SendRconCommand($"unban {args.UnbanPlayer}"); if (result == null) { sb.AppendLine($"**Failed to unban player with steamid {args.UnbanPlayer}... :(**"); } else { sb.AppendLine($"**Unbanned player with steamid {args.UnbanPlayer}!**"); } } else if (args.KillPlayer > 0) { var result = await serverContext.Steam.SendRconCommand($"killplayer {args.KillPlayer}"); if (result == null) { sb.AppendLine($"**Failed to kill player with id {args.KillPlayer}... :(**"); } else { sb.AppendLine($"**Killed player with id {args.KillPlayer}!**"); } } else if (args.GetSteamIDForPlayerID > 0) { var result = await serverContext.Steam.SendRconCommand($"GetSteamIDForPlayerID {args.GetSteamIDForPlayerID}"); if (result == null) { sb.AppendLine($"**Failed to get steamid from id {args.GetSteamIDForPlayerID}... :(**"); } else { sb.AppendLine(result); } } else if (args.GetPlayerIDForSteamID > 0) { var result = await serverContext.Steam.SendRconCommand($"GetPlayerIDForSteamID {args.GetPlayerIDForSteamID}"); if (result == null) { sb.AppendLine($"**Failed to get id from steamid {args.GetPlayerIDForSteamID}... :(**"); } else { sb.AppendLine(result); } } else if (args.GetTribeIdPlayerList > 0) { var result = await serverContext.Steam.SendRconCommand($"GetTribeIdPlayerList {args.GetTribeIdPlayerList}"); if (result == null) { sb.AppendLine("**Failed to get a list of players in tribe... :(**"); } else { sb.AppendLine(result); } } else if (!string.IsNullOrEmpty(args.Countdown) && _rCountdown.IsMatch(args.Countdown)) { var m = _rCountdown.Match(args.Countdown); var reason = m.Groups["reason"].Value; var delayInMinutes = int.Parse(m.Groups["min"].Value); if (delayInMinutes < 1) { delayInMinutes = 1; } Func <Task> react = null; if (args.StopServer || args.ShutdownServer) { react = new Func <Task>(async() => { string message = null; if (!await _arkServerService.ShutdownServer(serverContext.Config.Key, (s) => { message = s; return(Task.FromResult((Message)null)); })) { Logging.Log($@"Countdown to shutdown server ({serverContext.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } }); } else if (args.UpdateServer) { react = new Func <Task>(async() => { string message = null; if (!await _arkServerService.UpdateServer(serverContext.Config.Key, (s) => { message = s; return(Task.FromResult((Message)null)); }, (s) => s.FirstCharToUpper(), 300)) { Logging.Log($@"Countdown to update server ({serverContext.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } }); } else if (args.RestartServer) { react = new Func <Task>(async() => { string message = null; if (!await _arkServerService.RestartServer(serverContext.Config.Key, (s) => { message = s; return(Task.FromResult((Message)null)); })) { Logging.Log($@"Countdown to restart server ({serverContext.Config.Key}) execution failed (""{message ?? ""}"")", GetType(), LogLevel.DEBUG); } }); } sb.AppendLine($"**Countdown have been initiated. Announcement will be made.**"); await _scheduledTasksManager.StartCountdown(serverContext, reason, delayInMinutes, react); } else { await e.Channel.SendMessage(string.Join(Environment.NewLine, new string[] { $"**My logic circuits cannot process this command! I am just a bot after all... :(**", !string.IsNullOrWhiteSpace(SyntaxHelp) ? $"Help me by following this syntax: **!{Name}** {SyntaxHelp}" : null }.Where(x => x != null))); return; } var msg = sb.ToString(); if (!string.IsNullOrWhiteSpace(msg)) { await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); } }
public async Task Run(CommandEventArgs e) { if (!_context.IsInitialized) { await e.Channel.SendMessage($"**The data is loading but is not ready yet...**"); return; } var serverContext = _contextManager.GetServer(_config.ServerKey); var info = serverContext.Steam.GetServerInfoCached(); var rules = serverContext.Steam.GetServerRulesCached(); var sb = new StringBuilder(); if (info == null || rules == null) { sb.AppendLine($"**Server status is currently unavailable!**"); } else { var m = new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(info.Name); var name = m.Success ? m.Groups["name"].Value : info.Name; var version = m.Success ? m.Groups["version"] : null; var currentTime = rules.FirstOrDefault(x => x.Name == "DayTime_s")?.Value; var tamedDinosCount = _context.Creatures?.Count(); var uploadedDinosCount = _context.Cluster?.Creatures?.Count(); var wildDinosCount = _context.Wild?.Count(); var tamedDinosMax = 6000; //todo: remove hardcoded value var structuresCount = _context.Tribes?.SelectMany(x => x.Structures).Sum(x => x.Count); var totalPlayers = _context.Players?.Count(); var totalTribes = _context.Tribes?.Count(); //server uptime DateTime?serverStarted = null; try { serverStarted = Process.GetProcessesByName(_constants.ArkServerProcessName)?.FirstOrDefault()?.StartTime; } catch { /* ignore exceptions */ } sb.AppendLine($"**{name}**"); sb.AppendLine($"● **Address:** {info.Address}"); if (version != null) { sb.AppendLine($"● **Version:** {version}"); } sb.AppendLine($"● **Online:** {info.Players}/{info.MaxPlayers}"); sb.AppendLine($"● **Map:** {info.Map}"); if (currentTime != null) { sb.AppendLine($"● **In-game time:** {currentTime}"); } if (serverStarted != null) { sb.AppendLine($"Server uptime: {(DateTime.Now - serverStarted.Value).ToStringCustom(true)}"); } sb.AppendLine().AppendLine($"**Server Statistics**"); if (tamedDinosCount.HasValue) { sb.AppendLine($"● **Tamed dinos:** {tamedDinosCount.Value:N0}/{tamedDinosMax:N0}"); } if (uploadedDinosCount.HasValue) { sb.AppendLine($"● **Uploaded dinos:** {uploadedDinosCount.Value:N0}"); } if (wildDinosCount.HasValue) { sb.AppendLine($"● **Wild dinos:** {wildDinosCount.Value:N0}"); } if (structuresCount.HasValue) { sb.AppendLine($"● **Structures:** {structuresCount.Value:N0}"); } if (totalPlayers.HasValue) { sb.AppendLine($"● **Players:** {totalPlayers.Value:N0}"); } if (totalTribes.HasValue) { sb.AppendLine($"● **Tribes:** {totalTribes.Value:N0}"); } var nextUpdate = _context.ApproxTimeUntilNextUpdate; var nextUpdateTmp = nextUpdate?.ToStringCustom(); var nextUpdateString = (nextUpdate.HasValue ? (!string.IsNullOrWhiteSpace(nextUpdateTmp) ? $"~{nextUpdateTmp}" : "waiting for new update ...") : null); var lastUpdate = _context.LastUpdate; var lastUpdateString = lastUpdate.ToStringWithRelativeDay(); sb.AppendLine($"● **Last update:** {lastUpdateString}"); if (nextUpdateString != null) { sb.AppendLine($"● **Next update:** {nextUpdateString}"); } } await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); }
public async Task <ServerStatusAllViewModel> Get() { var result = new ServerStatusAllViewModel(); foreach (var context in _contextManager.Servers) { var serverContext = _contextManager.GetServer(context.Config.Key); var status = serverContext.Steam.GetServerStatusCached(); if (status == null || status.Item1 == null || status.Item2 == null) { //Server status is currently unavailable } else { var info = status.Item1; var rules = status.Item2; var playerinfos = status.Item3; var m = new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(info.Name); var name = m.Success ? m.Groups["name"].Value : info.Name; var version = m.Success ? m.Groups["version"] : null; var currentTime = rules.FirstOrDefault(x => x.Name == "DayTime_s")?.Value; var tamedDinosCount = context.TamedCreatures?.Count(); //var uploadedDinosCount = _context.Cluster?.Creatures?.Count(); var wildDinosCount = context.WildCreatures?.Count(); //var tamedDinosMax = 6000; //todo: remove hardcoded value var structuresCount = context.Structures?.Count(); var totalPlayers = context.Players?.Count(); var totalTribes = context.Tribes?.Count(); //server uptime //DateTime? serverStarted = null; //try //{ // serverStarted = Process.GetProcessesByName(_constants.ArkServerProcessName)?.FirstOrDefault()?.StartTime; //} //catch { /* ignore exceptions */ } var nextUpdate = context.ApproxTimeUntilNextUpdate; var nextUpdateTmp = nextUpdate?.ToStringCustom(); var nextUpdateString = (nextUpdate.HasValue ? (!string.IsNullOrWhiteSpace(nextUpdateTmp) ? $"~{nextUpdateTmp}" : "waiting for new update ...") : null); var lastUpdate = context.LastUpdate; var lastUpdateString = lastUpdate.ToStringWithRelativeDay(); var sr = new ServerStatusViewModel { Key = context.Config.Key, Name = name, Address = info.Address, Version = version.ToString(), OnlinePlayerCount = info.Players, OnlinePlayerMax = info.MaxPlayers, MapName = info.Map, InGameTime = currentTime, TamedCreatureCount = tamedDinosCount ?? 0, WildCreatureCount = wildDinosCount ?? 0, StructureCount = structuresCount ?? 0, PlayerCount = totalPlayers ?? 0, TribeCount = totalTribes ?? 0, LastUpdate = lastUpdateString, NextUpdate = nextUpdateString }; var players = playerinfos?.Where(x => !string.IsNullOrEmpty(x.Name)).ToArray() ?? new PlayerInfo[] { }; using (var db = _databaseContextFactory.Create()) { Dictionary <string, Tuple <ArkPlayer, Database.Model.User, User, long?, TimeSpan, ArkTribe> > d = null; if (context.Players != null) { var playerNames = players.Select(x => x.Name).ToArray(); d = context.Players.Where(x => playerNames.Contains(x.Name, StringComparer.Ordinal)).Select(x => { long steamId; return(new Tuple <ArkPlayer, Database.Model.User, User, long?, TimeSpan, ArkTribe>( x, null, null, long.TryParse(x.SteamId, out steamId) ? steamId : (long?)null, TimeSpan.Zero, null)); }).ToDictionary(x => x.Item1.Name, StringComparer.OrdinalIgnoreCase); var ids = new List <ulong>(); var steamIds = d.Values.Select(x => x.Item4).Where(x => x != null).ToArray(); foreach (var user in db.Users.Where(y => steamIds.Contains(y.SteamId))) { var item = d.Values.FirstOrDefault(x => x.Item4 == user.SteamId); if (item == null) { continue; } ids.Add(item.Item1.Id); var discordUser = (User)null; //e.User?.Client?.Servers?.Select(x => x.GetUser((ulong)user.DiscordId)).FirstOrDefault(); var playedLastSevenDays = TimeSpan.MinValue; //TimeSpan.FromSeconds(user?.Played?.OrderByDescending(x => x.Date).Take(7).Sum(x => x.TimeInSeconds) ?? 0); d[item.Item1.Name] = Tuple.Create(item.Item1, user, discordUser, item.Item4, playedLastSevenDays, item.Item1.TribeId.HasValue ? context.Tribes?.FirstOrDefault(x => x.Id == item.Item1.TribeId.Value) : null); } var remaining = d.Values.Where(x => !ids.Contains(x.Item1.Id)).Where(x => x.Item4 != null).Select(x => x.Item4.Value).ToArray(); foreach (var user in db.Played.Where(x => x.SteamId.HasValue && remaining.Contains(x.SteamId.Value)) .GroupBy(x => x.SteamId) .Select(x => new { key = x.Key, items = x.OrderByDescending(y => y.Date).Take(7).ToList() }) .ToArray()) { var item = d.Values.FirstOrDefault(x => x.Item4 == user.key); if (item == null) { continue; } var playedLastSevenDays = TimeSpan.FromSeconds(user?.items?.Sum(x => x.TimeInSeconds) ?? 0); d[item.Item1.Name] = Tuple.Create(item.Item1, item.Item2, item.Item3, item.Item4, playedLastSevenDays, item.Item1.TribeId.HasValue ? context.Tribes?.FirstOrDefault(x => x.Id == item.Item1.TribeId.Value) : null); } } //var playerslist = players.Select(x => { // var extra = d.ContainsKey(x.Name) ? d[x.Name] : null; // return new // { // Steam = x.Name, // Name = extra?.Item1?.Name, // Tribe = extra?.Item1?.TribeName, // Discord = extra != null && extra.Item3 != null ? $"{extra.Item3.Name}#{extra.Item3.Discriminator}" : null, // TimeOnline = x.Time.ToStringCustom(), // PlayedLastSevenDays = extra != null && extra.Item5.TotalMinutes > 1 ? extra?.Item5.ToStringCustom() : null // }; //}).ToArray(); foreach (var player in players) { var extra = d?.ContainsKey(player.Name) == true ? d[player.Name] : null; sr.OnlinePlayers.Add(new OnlinePlayerViewModel { SteamName = player.Name, CharacterName = extra?.Item1?.Name, TribeName = extra?.Item6?.Name, DiscordName = extra != null && extra.Item3 != null ? $"{extra.Item3.Name}#{extra.Item3.Discriminator}" : null, TimeOnline = player.Time.ToStringCustom(), TimeOnlineSeconds = (int)Math.Round(player.Time.TotalSeconds) }); } } result.Servers.Add(sr); } } foreach (var context in _contextManager.Clusters) { var cc = new ClusterStatusViewModel { Key = context.Config.Key, ServerKeys = _contextManager.Servers .Where(x => x.Config.Cluster.Equals(context.Config.Key, StringComparison.OrdinalIgnoreCase)) .Select(x => x.Config.Key).ToArray() }; result.Clusters.Add(cc); } return(result); }
public async Task <ServerStatusAllViewModel> Get() { var demoMode = IsDemoMode() ? new DemoMode() : null; var anonymize = _config.AnonymizeWebApiData; var user = WebApiHelper.GetUser(HttpContext, _config); if (anonymize) { var serverContext = _contextManager?.Servers?.FirstOrDefault(); var player = serverContext?.Players?.Where(x => x.Tribe != null && x.Tribe.Creatures != null && x.Tribe.Structures != null && x.Tribe.Creatures.Any(y => y.IsBaby) && x.Tribe.Structures.OfType <ArkStructureCropPlot>().Any() && x.Tribe.Structures.OfType <ArkStructureElectricGenerator>().Any() ).OrderByDescending(x => x.Creatures.Length).FirstOrDefault(); if (player == null) { user = null; } else { user.Name = player.Name; user.SteamId = player.SteamId; user.Roles = _config?.WebApp?.AccessControl?.SelectMany(x => x.Value.Values) .SelectMany(x => x) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(x => x) .ToArray(); } } var result = new ServerStatusAllViewModel { User = user, AccessControl = BuildViewModelForAccessControl(_config) }; if (_contextManager == null) { return(result); } if (_contextManager.Servers != null) { foreach (var context in _contextManager.Servers) { var serverContext = _contextManager.GetServer(context.Config.Key); var tamedDinosCount = context.TamedCreatures?.Count(); var uploadedDinosCount = context.CloudCreatures?.Count(); var wildDinosCount = context.WildCreatures?.Count(); var structuresCount = context.Structures?.Count(); var totalPlayers = context.Players?.Count(); var totalTribes = context.Tribes?.Count(); var serverStarted = _serverService.GetServerStartTime(context.Config.Key); var nextUpdate = context.ApproxTimeUntilNextUpdate; var nextUpdateTmp = nextUpdate?.ToStringCustom(); var nextUpdateString = nextUpdate.HasValue ? !string.IsNullOrWhiteSpace(nextUpdateTmp) ? $"~{nextUpdateTmp}" : "waiting for new update ..." : null; var lastUpdate = context.LastUpdate; var lastUpdateString = lastUpdate.ToStringWithRelativeDay(); var anonymizedServer = anonymize ? _anonymizeData.GetServer(context.Config.Key) : null; var serverStatusViewModel = new ServerStatusViewModel { Key = anonymizedServer?.Key ?? context.Config.Key, Name = anonymizedServer?.Name ?? context.Data.ServerInfo?.ServerName, Address = anonymizedServer?.Address ?? context.Config.DisplayAddress ?? context.Data.ServerInfo?.Address, Version = context.Data.ServerInfo != null ? $"{context.Data.ServerInfo.MajorVersion}.{context.Data.ServerInfo.MinorVersion}" : null, OnlinePlayerMax = context.Data.ServerInfo?.MaxPlayers ?? 0, MapName = context.Data.ServerInfo?.MapName, InGameTime = context.Data.ServerInfo?.DayNumber.ToString(), TamedCreatureCount = tamedDinosCount ?? 0, CloudCreatureCount = uploadedDinosCount ?? 0, WildCreatureCount = wildDinosCount ?? 0, StructureCount = structuresCount ?? 0, TribeCount = totalTribes ?? 0, LastUpdate = lastUpdateString, NextUpdate = nextUpdateString, ServerStarted = serverStarted }; result.Servers.Add(serverStatusViewModel); } } if (_contextManager.Clusters != null) { foreach (var context in _contextManager.Clusters) { var cc = new ClusterStatusViewModel { Key = context?.Config?.Key, ServerKeys = _contextManager.Servers .Where(x => x.Config != null && x.Config.ClusterKey != null && x.Config.ClusterKey.Equals(context.Config.Key, StringComparison.OrdinalIgnoreCase)) .Select(x => x.Config.Key).ToArray() }; result.Clusters.Add(cc); } } return(result); }
public async Task <bool> SaveWorld(string serverKey, Func <string, Task <IUserMessage> > sendMessageDirected, int timeoutSeconds = _saveWorldDefaultTimeoutSeconds, bool noUpdateForThisCall = false) { //todo: it would be much better is SaveWorld considered if the save request ends up in a queue or not. if (timeoutSeconds <= 0) { timeoutSeconds = _saveWorldDefaultTimeoutSeconds; } var serverContext = _contextManager.GetServer(serverKey); if (serverContext == null) { if (sendMessageDirected != null) { await sendMessageDirected($"could not find server instance {serverKey}"); } return(false); } if (sendMessageDirected != null) { await sendMessageDirected($"saving world (may take a while)..."); } try { //if (noUpdateForThisCall) _context.DisableContextUpdates(); if (await serverContext.Steam.SendRconCommand("saveworld") == null) { //failed to connect/exception/etc. if (sendMessageDirected != null) { await sendMessageDirected($"failed to save world."); } return(false); } //wait for a save file change event Tuple <ArkServerContext, bool, SavegameBackupResult> state = null; var now = DateTime.Now; while (true) { var timeout = TimeSpan.FromSeconds(timeoutSeconds) - (DateTime.Now - now); if (timeout.TotalSeconds <= 0 || !_signaller.Wait(timeout, out state)) { if (sendMessageDirected != null) { await sendMessageDirected($"timeout while waiting for savegame write (save status unknown)."); } return(false); } if (state?.Item1.Config.Key.Equals(serverKey, StringComparison.OrdinalIgnoreCase) != true) { continue; } if (_config.Backups.Enabled && !(state?.Item3?.ArchivePaths?.Length >= 1)) { if (sendMessageDirected != null) { await sendMessageDirected($"savegame backup failed..."); } return(false); } break; } } finally { //if (noUpdateForThisCall) _context.EnableContextUpdates(); } if (sendMessageDirected != null) { await sendMessageDirected($"world saved!"); } return(true); }
public ServerViewModel Get(string id) //, int? limit) { var context = _contextManager.GetServer(id); if (context == null) { return(null); } var demoMode = IsDemoMode() ? new DemoMode() : null; var result = new AdminServerViewModel { }; var creatureCounts = context.NoRafts?.GroupBy(x => x.TargetingTeam).ToDictionary(x => x.Key, x => x.Count()); var structureCounts = context.Structures?.Where(x => x.TargetingTeam.HasValue).GroupBy(x => x.TargetingTeam.Value).ToDictionary(x => x.Key, x => x.Count()); if (HasFeatureAccess("admin-server", "players") && context.Players != null) { result.Players.AddRange(context.Players.Select(x => { int cc1 = 0, cc2 = 0, sc1 = 0, sc2 = 0; creatureCounts?.TryGetValue(x.Id, out cc1); structureCounts?.TryGetValue(x.Id, out sc1); if (x.TribeId.HasValue) { creatureCounts?.TryGetValue(x.TribeId.Value, out cc2); structureCounts?.TryGetValue(x.TribeId.Value, out sc2); } var tribe = x.TribeId != null ? context.Tribes?.FirstOrDefault(y => y.Id == x.TribeId) : null; return(new AdminPlayerReferenceViewModel { Id = x.Id, SteamId = x.SteamId, FakeSteamId = demoMode?.GetSteamId(x.SteamId), CharacterName = demoMode?.GetPlayerName(x.Id) ?? x.CharacterName, SteamName = null, TribeName = tribe != null ? demoMode?.GetTribeName(tribe.Id) ?? tribe.Name : null, TribeId = x.TribeId, CreatureCount = cc1 + cc2, StructureCount = sc1 + sc2, LastActiveTime = x.LastActiveTime }); }).OrderByDescending(x => x.LastActiveTime)); } if (HasFeatureAccess("admin-server", "tribes") && context.Tribes != null) { result.Tribes.AddRange(context.Tribes.Select(x => { int cc1 = 0, sc1 = 0; creatureCounts?.TryGetValue(x.Id, out cc1); structureCounts?.TryGetValue(x.Id, out sc1); foreach (var m in x.MemberIds) { int cc2 = 0, sc2 = 0; creatureCounts?.TryGetValue(m, out cc2); structureCounts?.TryGetValue(m, out sc2); cc1 += cc2; sc1 += sc2; } var members = context.Players?.Where(y => x.MemberIds.Contains(y.Id)).ToList() ?? new List <ArkPlayer>(); return(new AdminTribeReferenceViewModel { Id = x.Id, Name = demoMode?.GetTribeName(x.Id) ?? x.Name, MemberSteamIds = members.Select(y => y.SteamId).ToList(), CreatureCount = cc1, StructureCount = sc1, LastActiveTime = x.LastActiveTime }); }).OrderByDescending(x => x.LastActiveTime)); } return(result); }
public async Task Run(CommandEventArgs e) { if (_savedstate.VotingDisabled) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"the voting system is currently disabled."); return; } //!vote ban24h <player name> reason <text> //!votes //!vote alpha yes //!vote alpha no var args = CommandHelper.ParseArgs(e, new { ServerKey = "", Ban = "", Ban24h = "", Unban = "", SetTimeOfDay = "", DestroyWildDinos = false, UpdateServer = false, RestartServer = false, Reason = "", Yes = false, No = false, Veto = false, History = false, Alfa = false, Bravo = false, Charlie = false, Delta = false, Echo = false, Foxtrot = false, Golf = false, Hotel = false, India = false, Juliett = false, Kilo = false, Lima = false, Mike = false, November = false, Oscar = false, Papa = false, Quebec = false, Romeo = false, Sierra = false, Tango = false, Uniform = false, Victor = false, Whiskey = false, Xray = false, Yankee = false, Zulu = false }, x => x.For(y => y.ServerKey, noPrefix: true) .For(y => y.Ban, untilNextToken: true) .For(y => y.Unban, untilNextToken: true) .For(y => y.Ban24h, untilNextToken: true) .For(y => y.Reason, untilNextToken: true) .For(y => y.DestroyWildDinos, flag: true) .For(y => y.UpdateServer, flag: true) .For(y => y.RestartServer, flag: true) .For(y => y.Yes, flag: true) .For(y => y.No, flag: true) .For(y => y.Veto, flag: true) .For(y => y.History, flag: true) .For(y => y.Alfa, flag: true) .For(y => y.Bravo, flag: true) .For(y => y.Charlie, flag: true) .For(y => y.Delta, flag: true) .For(y => y.Echo, flag: true) .For(y => y.Foxtrot, flag: true) .For(y => y.Golf, flag: true) .For(y => y.Hotel, flag: true) .For(y => y.India, flag: true) .For(y => y.Juliett, flag: true) .For(y => y.Kilo, flag: true) .For(y => y.Lima, flag: true) .For(y => y.Mike, flag: true) .For(y => y.November, flag: true) .For(y => y.Oscar, flag: true) .For(y => y.Papa, flag: true) .For(y => y.Quebec, flag: true) .For(y => y.Romeo, flag: true) .For(y => y.Sierra, flag: true) .For(y => y.Tango, flag: true) .For(y => y.Uniform, flag: true) .For(y => y.Victor, flag: true) .For(y => y.Whiskey, flag: true) .For(y => y.Xray, flag: true) .For(y => y.Yankee, flag: true) .For(y => y.Zulu, flag: true)); var identifiers = args.Alfa || args.Bravo || args.Charlie || args.Delta || args.Echo || args.Foxtrot || args.Golf || args.Hotel || args.India || args.Juliett || args.Kilo || args.Lima || args.Mike || args.November || args.Oscar || args.Papa || args.Quebec || args.Romeo || args.Sierra || args.Tango || args.Uniform || args.Victor || args.Whiskey || args.Xray || args.Yankee || args.Zulu; var identifierStrings = TypeDescriptor.GetProperties(args.GetType()).OfType <PropertyDescriptor>().Where(x => _identifierStrings.Contains(x.Name, StringComparer.OrdinalIgnoreCase) && x.PropertyType == typeof(bool) && (bool)x.GetValue(args)).Select(x => x.Name).ToArray(); var voteStrings = TypeDescriptor.GetProperties(args.GetType()).OfType <PropertyDescriptor>().Where(x => _voteStrings.Contains(x.Name, StringComparer.OrdinalIgnoreCase) && x.PropertyType == typeof(bool) && (bool)x.GetValue(args)).Select(x => x.Name).ToArray(); var isAdminOrDev = _discord.Servers.Any(x => x.Roles.Any(y => y != null && new[] { _config.AdminRoleName, _config.DeveloperRoleName }.Contains(y.Name, StringComparer.OrdinalIgnoreCase) == true && y.Members.Any(z => z.Id == e.User.Id))); if (args == null || (identifiers && (voteStrings.Length == 0 || voteStrings.Length > 1 || identifierStrings.Length == 0 || identifierStrings.Length > 1)) //votes require an identifier and a Yes/No/Veto ) { await e.Channel.SendMessage(string.Join(Environment.NewLine, new string[] { $"**My logic circuits cannot process this command! I am just a bot after all... :(**", !string.IsNullOrWhiteSpace(SyntaxHelp) ? $"Help me by following this syntax: **!{Name}** {SyntaxHelp}" : null }.Where(x => x != null))); return; } var now = DateTime.Now; var sb = new StringBuilder(); //this should match any type of vote if (!string.IsNullOrWhiteSpace(args.Ban) || !string.IsNullOrWhiteSpace(args.Ban24h) || !string.IsNullOrWhiteSpace(args.Unban) || !string.IsNullOrWhiteSpace(args.SetTimeOfDay) || args.DestroyWildDinos || args.UpdateServer || args.RestartServer) { var serverContext = args?.ServerKey != null?_contextManager.GetServer(args.ServerKey) : null; if (serverContext == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"**Votes need to be prefixed with a server instance key.**"); return; } if (!serverContext.IsInitialized) { await e.Channel.SendMessage($"The server data is loading but is not ready yet..."); return; } if (string.IsNullOrWhiteSpace(args.Reason)) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"specifying a reason is mandatory when starting a vote."); return; } //is the user allowed to start a vote? //level >= 50 && days registered >= 7 //is the username valid? //is there already an ongoing vote for the same thing? using (var db = _databaseContextFactory.Create()) { var user = db.Users.FirstOrDefault(x => x.DiscordId == (long)e.User.Id && !x.Unlinked); if (user == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"this command can only be used after you link your Discord user with your Steam account using **!linksteam**."); return; } if (user.DisallowVoting) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"you are not allowed to vote."); return; } if (!isAdminOrDev) { var player = serverContext.Players.FirstOrDefault(x => x.SteamId != null && x.SteamId.Equals(user.SteamId.ToString())); if (player == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"we have no record of you playing in the last month which is a requirement for using this command."); return; } if (player.CharacterLevel < 50) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"you have to reach level 50 in order to initiate votes."); return; } var firstPlayed = user.Played?.Count > 0 ? user.Played?.Min(x => x.Date) : null; if (!firstPlayed.HasValue || (now - user.Played.Min(x => x.Date)).TotalDays < 7d) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"you have to have played for atleast seven days in order to initiate votes."); return; } } var availableIdentifiers = _identifierStrings.Except(db.Votes.Where(x => x.Result == VoteResult.Undecided).Select(x => x.Identifier).ToArray(), StringComparer.OrdinalIgnoreCase).ToArray(); var identifier = availableIdentifiers.Length > 0 ? availableIdentifiers.ElementAt(_rnd.Next(availableIdentifiers.Length)) : null; if (identifier == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"there are too many active votes at the moment. Please try again later."); return; } InitiateVoteResult result = null; //handling of specific types if (!string.IsNullOrWhiteSpace(args.Ban)) { result = await BanVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason, args.Ban, 365 * 24 * 50); } else if (!string.IsNullOrWhiteSpace(args.Ban24h)) { result = await BanVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason, args.Ban24h, 24); } else if (!string.IsNullOrWhiteSpace(args.Unban)) { result = await UnbanVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason, args.Unban); } else if (!string.IsNullOrWhiteSpace(args.SetTimeOfDay)) { result = await SetTimeOfDayVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason, args.SetTimeOfDay); } else if (args.DestroyWildDinos) { result = await DestroyWildDinosVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason); } else if (args.UpdateServer) { result = await UpdateServerVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason); } else if (args.RestartServer) { result = await RestartServerVoteHandler.Initiate(e.Channel, serverContext, _config, db, e.User.Id, identifier, now, args.Reason); } else { //this should never happen throw new ApplicationException("The vote type is not handled in code..."); } if (result == null || result.Vote == null) { return; } result.Vote.Votes.Add(new UserVote { InitiatedVote = true, Reason = args.Reason, VotedFor = true, User = user, UserId = user.Id, VoteType = isAdminOrDev ? UserVoteType.Admin : UserVoteType.Trusted, When = now }); db.Votes.Add(result.Vote); db.SaveChanges(); if (!string.IsNullOrWhiteSpace(result.MessageInitiator)) { await e.Channel.SendMessageDirectedAt(e.User.Id, result.MessageInitiator); } try { if (!string.IsNullOrWhiteSpace(result.MessageRcon)) { await serverContext.Steam.SendRconCommand($"serverchat {result.MessageRcon.ReplaceRconSpecialChars()}"); } if (!string.IsNullOrWhiteSpace(result.MessageAnnouncement) && !string.IsNullOrWhiteSpace(_config.AnnouncementChannel)) { var channels = _discord.Servers.Select(x => x.TextChannels.FirstOrDefault(y => _config.AnnouncementChannel.Equals(y.Name, StringComparison.OrdinalIgnoreCase))).Where(x => x != null); foreach (var channel in channels) { await channel.SendMessage(result.MessageAnnouncement); } } } catch { /*ignore all exceptions */ } serverContext.OnVoteInitiated(result.Vote); return; } } else if (identifiers && (args.Yes || args.No || args.Veto)) { if (!_context.IsInitialized) { await e.Channel.SendMessage($"The server data is loading but is not ready yet..."); return; } //does the identifier match an ongoing vote? //have the user already voted? using (var db = _databaseContextFactory.Create()) { var identifier = identifierStrings.First(); var allvotes = db.Votes.ToArray(); var votes = db.Votes.Where(x => x.Result == VoteResult.Undecided && x.Finished > now && x.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase)).ToArray(); if (votes.Length == 0) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"there is no active vote with the given identifier."); return; } if (votes.Length > 1) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"there are multiple active votes with this identifier. This is a bug and the vote cannot be cast."); return; } var vote = votes.First(); if (args.Veto && !isAdminOrDev) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"you do not have this permission."); return; } var user = db.Users.FirstOrDefault(x => x.DiscordId == (long)e.User.Id && !x.Unlinked); if (user == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"this command can only be used after you link your Discord user with your Steam account using **!linksteam**."); return; } if (user.DisallowVoting) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"you are not allowed to vote."); return; } //todo: players are only considered for one server var player = _context.Players.FirstOrDefault(x => x.SteamId != null && x.SteamId.Equals(user.SteamId.ToString())); if (player == null) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"we have no record of you playing in the last month which is a requirement for using this command."); return; } string message = null; UserVote uservote = null; if ((uservote = vote.Votes.FirstOrDefault(x => x.UserId == user.Id)) != null) { //await e.Channel.SendMessageDirectedAt(e.User.Id, $"you have already voted."); //return; uservote.Reason = args.Reason; uservote.VotedFor = args.Veto ? false : args.Yes; uservote.Vetoed = args.Veto; uservote.When = now; message = $"your vote has been changed!"; } else { var firstPlayed = user.Played?.Count > 0 ? user.Played.Min(x => x.Date) : (DateTime?)null; vote.Votes.Add(new UserVote { InitiatedVote = false, Reason = args.Reason, VotedFor = args.Veto ? false : args.Yes, Vetoed = args.Veto, User = user, UserId = user.Id, VoteType = isAdminOrDev ? UserVoteType.Admin : !firstPlayed.HasValue || (now - user.Played.Min(x => x.Date)).TotalDays < 7d ? UserVoteType.NewMember : player.Level < 50 ? UserVoteType.Member : UserVoteType.Trusted, When = now }); message = $"your vote has been recorded!"; } db.SaveChanges(); if (args.Veto) { var serverContext = _contextManager.GetServer(vote.ServerKey); if (serverContext != null) { serverContext.OnVoteResultForced(vote, VoteResult.Vetoed); message = $"you have vetoed this vote."; } else { message = $"could not veto vote because there was no server key."; } } await e.Channel.SendMessageDirectedAt(e.User.Id, message); } } else { using (var db = _databaseContextFactory.Create()) { if (args.History) { var votes = db.Votes.OrderByDescending(x => x.Started).Where(x => x.Result != VoteResult.Undecided && System.Data.Entity.DbFunctions.DiffDays(now, x.Started) <= 7).ToArray(); if (votes.Length == 0) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"there appear to be no history of votes from the last seven days."); return; } sb.AppendLine("**Previous votes**"); sb.AppendLine("--------------------"); foreach (var vote in votes) { sb.AppendLine($"***{vote.Started:yyyy-MM-dd HH:mm}***"); sb.AppendLine("**" + vote.ToString() + "**"); sb.AppendLine(vote.Result == VoteResult.Passed ? ":white_check_mark: The vote passed" : vote.Result == VoteResult.Failed ? ":x: The vote failed" : vote.Result == VoteResult.Vetoed ? ":x: The vote was vetoed" : "Result is unknown").AppendLine(); } } else { var votes = db.Votes.OrderByDescending(x => x.Started).Where(x => x.Result == VoteResult.Undecided).ToArray(); if (votes.Length == 0) { await e.Channel.SendMessageDirectedAt(e.User.Id, $"there are no active votes at this time."); return; } sb.AppendLine("**Active Votes**"); sb.AppendLine("--------------------"); foreach (var vote in votes) { sb.AppendLine("**" + vote.ToString() + "**"); sb.AppendLine($"To vote use the command: **!vote {vote.Identifier} yes**/**no**").AppendLine(); } } } } var msg = sb.ToString(); if (!string.IsNullOrWhiteSpace(msg)) { await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); } }
public async Task <ServerStatusAllViewModel> Get() { var demoMode = IsDemoMode() ? new DemoMode() : null; var anonymize = _config.AnonymizeWebApiData; var user = WebApiHelper.GetUser(Request, _config); if (anonymize) { var serverContext = _contextManager.Servers.FirstOrDefault(); var player = serverContext?.Players.Where(x => x.Tribe != null && x.Tribe.Creatures.Any(y => y.IsBaby) && x.Tribe.Structures.OfType <ArkStructureCropPlot>().Any() && x.Tribe.Structures.OfType <ArkStructureElectricGenerator>().Any() ).OrderByDescending(x => x.Creatures.Length).FirstOrDefault(); if (player == null) { user = null; } else { user.Name = player.Name; user.SteamId = player.SteamId; user.Roles = _config.AccessControl.SelectMany(x => x.Value.Values) .SelectMany(x => x) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(x => x) .ToArray(); } } var result = new ServerStatusAllViewModel { User = user, AccessControl = BuildViewModelForAccessControl(_config) }; foreach (var context in _contextManager.Servers) { var serverContext = _contextManager.GetServer(context.Config.Key); var status = serverContext.Steam.GetServerStatusCached(); //if (status == null || status.Item1 == null || status.Item2 == null) //{ // //Server status is currently unavailable //} //else //{ var info = status?.Item1; var rules = status?.Item2; var playerinfos = status?.Item3; var m = info != null ? new Regex(@"^(?<name>.+?)\s+-\s+\(v(?<version>\d+\.\d+)\)?$", RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(info.Name) : null; var name = m?.Success == true ? m.Groups["name"].Value : (info?.Name ?? context.Config.Key); var version = m?.Success == true ? m.Groups["version"] : null; var currentTime = rules?.FirstOrDefault(x => x.Name == "DayTime_s")?.Value; var tamedDinosCount = context.TamedCreatures?.Count(); var uploadedDinosCount = context.CloudCreatures?.Count(); var wildDinosCount = context.WildCreatures?.Count(); //var tamedDinosMax = 6000; //todo: remove hardcoded value var structuresCount = context.Structures?.Count(); var totalPlayers = context.Players?.Count(); var totalTribes = context.Tribes?.Count(); var serverStarted = _serverService.GetServerStartTime(context.Config.Key); var nextUpdate = context.ApproxTimeUntilNextUpdate; var nextUpdateTmp = nextUpdate?.ToStringCustom(); var nextUpdateString = (nextUpdate.HasValue ? (!string.IsNullOrWhiteSpace(nextUpdateTmp) ? $"~{nextUpdateTmp}" : "waiting for new update ...") : null); var lastUpdate = context.LastUpdate; var lastUpdateString = lastUpdate.ToStringWithRelativeDay(); var anonymizedServer = anonymize ? _anonymizeData.GetServer(context.Config.Key) : null; var sr = new ServerStatusViewModel { Key = anonymizedServer?.Key ?? context.Config.Key, Name = anonymizedServer?.Name ?? name, Address = anonymizedServer?.Address ?? context.Config.DisplayAddress ?? info?.Address, Version = version?.ToString(), OnlinePlayerCount = info?.Players ?? 0, OnlinePlayerMax = info?.MaxPlayers ?? 0, MapName = info?.Map, InGameTime = currentTime, TamedCreatureCount = tamedDinosCount ?? 0, CloudCreatureCount = uploadedDinosCount ?? 0, WildCreatureCount = wildDinosCount ?? 0, StructureCount = structuresCount ?? 0, PlayerCount = totalPlayers ?? 0, TribeCount = totalTribes ?? 0, LastUpdate = lastUpdateString, NextUpdate = nextUpdateString, ServerStarted = serverStarted }; if (HasFeatureAccess("home", "online")) { var onlineplayers = playerinfos?.Where(x => !string.IsNullOrEmpty(x.Name)).ToArray() ?? new PlayerInfo[] { }; if (anonymize) { int n = 0; foreach (var player in context.Players.OrderByDescending(x => x.LastActiveTime).Take(onlineplayers.Length)) { sr.OnlinePlayers.Add(new OnlinePlayerViewModel { SteamName = player.Name, CharacterName = player.CharacterName, TribeName = player.Tribe?.Name, DiscordName = null, TimeOnline = onlineplayers[n].Time.ToStringCustom(), TimeOnlineSeconds = (int)Math.Round(onlineplayers[n].Time.TotalSeconds) }); n++; } } else { using (var db = _databaseContextFactory.Create()) { // Names of online players (steam does not provide ids) var onlineplayerNames = onlineplayers.Select(x => x.Name).ToArray(); // Get the player data for each name (null when no matching name or when multiple players share the same name) var onlineplayerData = context.Players != null ? (from k in onlineplayerNames join p in context.Players on k equals p.Name into grp select grp.Count() == 1 ? grp.ElementAt(0) : null).ToArray() : new ArkPlayer[] { }; // Parse all steam ids var parsedSteamIds = onlineplayerData.Select(x => { long steamId; return(x?.SteamId != null ? long.TryParse(x.SteamId, out steamId) ? steamId : (long?)null : null); }).ToArray(); // Get the player data for each name var databaseUsers = (from k in parsedSteamIds join u in db.Users on k equals u?.SteamId into grp select grp.FirstOrDefault()).ToArray(); // Get the discord users var discordUsers = databaseUsers.Select(x => x != null ? _discordManager.GetDiscordUserNameById((ulong)x.DiscordId) : null).ToArray(); int n = 0; foreach (var player in onlineplayers) { var extra = onlineplayerData.Length > n ? new { player = onlineplayerData[n], user = databaseUsers[n], discordName = discordUsers[n] } : null; var demoPlayerName = demoMode?.GetPlayerName(); sr.OnlinePlayers.Add(new OnlinePlayerViewModel { SteamName = demoPlayerName ?? player.Name, CharacterName = demoPlayerName ?? extra?.player?.CharacterName, TribeName = demoMode?.GetTribeName() ?? extra?.player?.Tribe?.Name, DiscordName = demoMode != null ? null : extra?.discordName, TimeOnline = player.Time.ToStringCustom(), TimeOnlineSeconds = (int)Math.Round(player.Time.TotalSeconds) }); n++; } } } } else { sr.OnlinePlayers = null; } result.Servers.Add(sr); //} } foreach (var context in _contextManager.Clusters) { var cc = new ClusterStatusViewModel { Key = context.Config.Key, ServerKeys = _contextManager.Servers .Where(x => x.Config.ClusterKey.Equals(context.Config.Key, StringComparison.OrdinalIgnoreCase)) .Select(x => x.Config.Key).ToArray() }; result.Clusters.Add(cc); } return(result); }
public async Task Run(CommandEventArgs e) { var args = CommandHelper.ParseArgs(e, new { ServerKey = "" }, x => x.For(y => y.ServerKey, noPrefix: true, isRequired: false)); var serverContext = _contextManager.GetServer(args.ServerKey ?? _config.ServerKey); if (serverContext == null) { await e.Channel.SendMessage($"**Specified server instance key is not valid.**"); return; } if (!serverContext.IsInitialized) { await e.Channel.SendMessage($"**The data is loading but is not ready yet...**"); return; } var player = await CommandHelper.GetCurrentPlayerOrSendErrorMessage(e, _databaseContextFactory, serverContext); if (player == null) { return; } var playercreatures = serverContext.NoRafts.Where(x => (ulong)x.TargetingTeam == player.Id || (x.OwningPlayerId.HasValue && (ulong)x.OwningPlayerId == player.Id)).ToArray(); var tribecreatures = player.TribeId.HasValue ? serverContext.NoRafts.Where(x => x.TargetingTeam == player.TribeId.Value && !playercreatures.Any(y => y.Id == x.Id)).ToArray() : new ArkTamedCreature[] { }; var mydinos = playercreatures.Select(x => new { c = x, o = "player" }).Concat(tribecreatures.Select(x => new { c = x, o = "tribe" })).Select(item => { var currentFood = item.c.CurrentStatusValues?.Length > 4 ? item.c.CurrentStatusValues[4] : null; var maxFood = item.c.BaseStats?.Length > 4 && item.c.TamedStats?.Length > 4 ? ArkContext.CalculateMaxStat( ArkSpeciesStatsData.Stat.Food, item.c.ClassName, item.c.BaseStats[4], item.c.TamedStats[4], (decimal)(item.c.DinoImprintingQuality ?? 0f), (decimal)(item.c.TamedIneffectivenessModifier ?? 0f)) : null; //baby food formula: max * 0.1 + (max - (max * 0.1)) * age if (maxFood.HasValue && item.c.BabyAge.HasValue) { maxFood = maxFood.Value * 0.1 + (maxFood.Value - (maxFood.Value * 0.1)) * item.c.BabyAge.Value; } var fs = currentFood.HasValue && maxFood.HasValue ? currentFood.Value / (float)maxFood.Value : (float?)null; if (fs.HasValue && fs > 1f) { fs = 1f; } var aliases = ArkSpeciesAliases.Instance.GetAliases(item.c.ClassName); return(new { c = item.c, o = item.o, food = fs }); }).ToArray(); //var mydinos = serverContext.NoRafts // .Where(x => ((x.OwningPlayerId.HasValue && x.OwningPlayerId.Value == player.Id) || (x.Team.Value == player.TribeId)) && !x.IsBaby) // .Select(x => // { // //!_context.ArkSpeciesStatsData.SpeciesStats.Any(y => y.Name.Equals(x.SpeciesName, StringComparison.OrdinalIgnoreCase)) ? _context.ArkSpeciesStatsData.SpeciesStats.Select(y => new { name = y.Name, similarity = StatisticsHelper.CompareToCharacterSequence(x.Name, x.SpeciesName.ToCharArray()) }).OrderByDescending(y => y.similarity).FirstOrDefault()?.name : null; // return new // { // creature = x, // maxFood = ArkContext.CalculateMaxStat(Data.ArkSpeciesStatsData.Stat.Food, x.SpeciesClass ?? x.SpeciesName, x.WildLevels?.Food, x.TamedLevels?.Food, x.ImprintingQuality, x.TamedIneffectivenessModifier) // }; // }) // .ToArray(); //var foodStatus = mydinos?.Where(x => x.creature.CurrentFood.HasValue && x.maxFood.HasValue).Select(x => (double)x.creature.CurrentFood.Value / x.maxFood.Value) // .Where(x => x <= 1d).OrderBy(x => x).ToArray(); //var starving = mydinos?.Where(x => x.creature.CurrentFood.HasValue && x.maxFood.HasValue).Select(x => new { creature = x.creature, p = (double)x.creature.CurrentFood.Value / x.maxFood.Value }) // .Where(x => x.p <= (1 / 2d)).OrderBy(x => x.p).ToArray(); //any dino below 1/2 food is considered to be starving var foodStatus = mydinos.Where(x => x.food.HasValue).Select(x => x.food.Value).OrderBy(x => x).ToArray(); var starving = mydinos.Where(x => !x.food.HasValue || x.food <= (1 / 2d)).OrderBy(x => x.food).ToArray(); //any dino below 1/2 food is considered to be starving if (foodStatus.Length <= 0) { await e.Channel.SendMessage($"<@{e.User.Id}>, we could not get the food status of your dinos! :("); return; } var min = foodStatus.Min(); var avg = foodStatus.Average(); var max = foodStatus.Max(); var stateFun = min <= 0.25 ? "starving... :(" : min <= 0.5 ? "hungry... :|" : min <= 0.75 ? "feeling satisfied :)" : "feeling happy! :D"; var sb = new StringBuilder(); sb.AppendLine($"**Your dinos are {stateFun}**"); sb.AppendLine($"{min:P0} ≤ {avg:P0} ≤ {max:P0}"); if (starving.Length > 0) { var tmp = starving.Select(x => { var aliases = ArkSpeciesAliases.Instance.GetAliases(x.c.ClassName); return($"{x.c.Name ?? aliases.FirstOrDefault() ?? x.c.ClassName}, lvl {x.c.Level}" + $" ({(x.food.HasValue ? x.food.Value.ToString("P0") : "Unknown")})"); }).ToArray().Join((n, l) => n == l ? " and " : ", "); sb.AppendLine(tmp); } await CommandHelper.SendPartitioned(e.Channel, sb.ToString()); var filepath = Path.Combine(_config.TempFileOutputDirPath, "chart.jpg"); if (CommandHelper.AreaPlotSaveAs(foodStatus.Select((x, i) => new DataPoint(i, x)).ToArray(), filepath)) { await e.Channel.SendFile(filepath); } if (File.Exists(filepath)) { File.Delete(filepath); } }