/// <summary> /// adds or updates meta key and value to the database /// </summary> /// <param name="metaKey">key of meta data</param> /// <param name="metaValue">value of the meta data</param> /// <param name="client">client to save the meta for</param> /// <returns></returns> public async Task AddPersistentMeta(string metaKey, string metaValue, EFClient client) { // this seems to happen if the client disconnects before they've had time to authenticate and be added if (client.ClientId < 1) { return; } using (var ctx = new DatabaseContext()) { var existingMeta = await ctx.EFMeta .Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.ClientId == client.ClientId) .FirstOrDefaultAsync(); if (existingMeta != null) { existingMeta.Value = metaValue; existingMeta.Updated = DateTime.UtcNow; } else { ctx.EFMeta.Add(new EFMeta() { ClientId = client.ClientId, Created = DateTime.UtcNow, Key = metaKey, Value = metaValue }); } await ctx.SaveChangesAsync(); } }
public void SetAdditionalPropertyShouldSucceed() { var client = new EFClient(); int newProp = 5; client.SetAdditionalProperty("NewProp", newProp); }
private static DatabaseContext AddClient(DatabaseContext context, EFClient client, int count, int commitCount, bool recreateContext) { context.Clients.Add(client); if (count % commitCount == 0) { try { context.SaveChanges(); } catch (Exception) { } if (recreateContext) { context.Dispose(); context = new DatabaseContext(); context.Configuration.AutoDetectChangesEnabled = false; context.Configuration.LazyLoadingEnabled = false; context.Configuration.ProxyCreationEnabled = false; } } return(context); }
private async Task OnClientUpdate(EFClient origin) { var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(origin)); if (client != null) { client.Ping = origin.Ping; client.Score = origin.Score; // update their IP if it hasn't been set yet if (client.IPAddress == null && !client.IsBot && client.State == ClientState.Connected) { try { await client.OnJoin(origin.IPAddress); } catch (Exception e) { origin.CurrentServer.Logger.WriteWarning($"Could not execute on join for {origin}"); origin.CurrentServer.Logger.WriteDebug(e.GetExceptionInfo()); } } } }
public async Task salute(EFClient player, Server S) { bool alreadyVoted = false; foreach (KeyValuePair <int, bool> entry in votes) { if (player.AliasLinkId == entry.Key) { alreadyVoted = true; if (entry.Value) { player.Tell("^2You've voted: ^5" + S.Maps[nextMap]); } else { player.Tell("^2You've voted: ^5Current map"); } player.Tell("^3You can still change your vote:"); break; } } if (!alreadyVoted) { player.Tell("^3Vote next map now!"); } player.Tell("^5#0 ^7-> ^2Current map"); player.Tell("^5#1 ^7-> ^2" + S.Maps[nextMap]); player.Tell("^5#c ^7-> ^2Vote to change map now"); }
public void ReportClientShouldSucceed() { while (!Manager.IsInitialized) { Thread.Sleep(100); } var client = Manager.Servers.First().GetClientsAsList().FirstOrDefault(); Assert.False(client == null, "no client found to report"); // fail var player = new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer }; player.SetAdditionalProperty("_reportCount", 3); var reportEvent = client.Report("test report", player); reportEvent.OnProcessed.Wait(TestTimeout); Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Throttle & client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 0, $"too many reports were applied [{reportEvent.FailReason.ToString()}]"); // succeed reportEvent = client.Report("test report", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer }); reportEvent.OnProcessed.Wait(TestTimeout); Assert.True(!reportEvent.Failed && client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"report was not applied [{reportEvent.FailReason.ToString()}]"); // fail reportEvent = client.Report("test report", new EFClient() { ClientId = 1, NetworkId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer }); Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Permission && client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"report was applied without proper permission [{reportEvent.FailReason.ToString()},{ client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId)}]"); // fail reportEvent = client.Report("test report", client); Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Invalid && client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"report was applied to self"); // fail reportEvent = client.Report("test report", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer }); Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Exception && client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"duplicate report was applied"); }
public async Task vote(EFClient player, Server S, char choice) { if (choice == '0') { player.Tell("^2You've voted: ^5Current map"); votes[player.AliasLinkId] = false; } else if (choice == '1') { player.Tell("^2You've voted: ^5" + S.Maps[nextMap]); votes[player.AliasLinkId] = true; } else if (choice == 'c') { player.Tell("^2You've voted: ^5change map now"); changenow.Add(player.AliasLinkId); if (changenow.Count >= S.ClientNum - 1) { await countvotes(S); changedMap = true; S.Broadcast("^6Changing map now!"); await S.LoadMap(S.Maps[selectedMap].Name); } } }
public async void LockerGunStatus(EFClient client, string mapName) { if ((await _metaService.GetPersistentMeta($"{mapName}_gun", client)) == null) { await _metaService.AddPersistentMeta($"{mapName}_gun", "none", client); } }
public async Task OnEventAsync(GameEvent E, Server S) { if (E.Type == GameEvent.EventType.Join) { EFClient newPlayer = E.Origin; if (newPlayer.Level >= Permission.Trusted && !E.Origin.Masked) { E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage, newPlayer)); } newPlayer.Tell(await ProcessAnnouncement(_configHandler.Configuration().UserWelcomeMessage, newPlayer)); if (newPlayer.Level == Permission.Flagged) { string penaltyReason; using (var ctx = new DatabaseContext(disableTracking: true)) { penaltyReason = await ctx.Penalties .Where(p => p.OffenderId == newPlayer.ClientId && p.Type == EFPenalty.PenaltyType.Flag) .OrderByDescending(p => p.When) .Select(p => p.AutomatedOffense ?? p.Offense) .FirstOrDefaultAsync(); } E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!"); } else { E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage, newPlayer)); } } }
public static void ImportClients(IList <Player> clients) { DatabaseContext context = null; try { context = new DatabaseContext(); context.Configuration.AutoDetectChangesEnabled = false; context.Configuration.LazyLoadingEnabled = false; context.Configuration.ProxyCreationEnabled = false; int count = 0; foreach (var entityToInsert in clients) { ++count; var link = new EFAliasLink() { Active = true }; var alias = new EFAlias() { Active = true, DateAdded = entityToInsert.LastConnection, IPAddress = entityToInsert.IPAddress, Link = link, Name = entityToInsert.Name, }; var client = new EFClient() { Active = true, AliasLink = link, Connections = entityToInsert.Connections, CurrentAlias = alias, FirstConnection = entityToInsert.LastConnection, Level = entityToInsert.Level, LastConnection = entityToInsert.LastConnection, TotalConnectionTime = entityToInsert.TotalConnectionTime, Masked = entityToInsert.Masked, NetworkId = entityToInsert.NetworkId }; context = AddClient(context, client, count, 1000, true); } context.SaveChanges(); } finally { if (context != null) { context.Dispose(); } } }
public async Task <int> GetBankMeta(EFClient C) { if (await _metaService.GetPersistentMeta("BankBalance", C) == null) { _ = _metaService.AddPersistentMeta("BankBalance", "0", C); return(0); } return(Convert.ToInt32((await _metaService.GetPersistentMeta("BankBalance", C)).Value)); }
public void GetAdditionalPropertyShouldSucceed() { var client = new EFClient(); int newProp = 5; client.SetAdditionalProperty("NewProp", newProp); Assert.True(client.GetAdditionalProperty <int>("NewProp") == 5, "added property does not match retrieved property"); }
public void Broadcast(IEnumerable <string> messages, EFClient sender = null) { foreach (var message in messages) { #pragma warning disable 4014 Broadcast(message, sender).WaitAsync(); #pragma warning restore 4014 } }
/// <summary> /// retrieves meta data for given client and key /// </summary> /// <param name="metaKey">key to retrieve value for</param> /// <param name="client">client to retrieve meta for</param> /// <returns></returns> public async Task <EFMeta> GetPersistentMeta(string metaKey, EFClient client) { using (var ctx = new DatabaseContext(disableTracking: true)) { return(await ctx.EFMeta .Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.ClientId == client.ClientId) .FirstOrDefaultAsync()); } }
public override void OnActionExecuting(ActionExecutingContext context) { Manager = Program.Manager; User = User ?? new EFClient() { ClientId = -1 }; if (HttpContext.Connection.RemoteIpAddress.ToString() != "127.0.0.1") { try { User.ClientId = Convert.ToInt32(base.User.Claims.First(c => c.Type == ClaimTypes.Sid).Value); User.Level = (Player.Permission)Enum.Parse(typeof(Player.Permission), base.User.Claims.First(c => c.Type == ClaimTypes.Role).Value); User.CurrentAlias = new EFAlias() { Name = base.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value }; } catch (InvalidOperationException) { } } else { User.ClientId = 1; User.Level = Player.Permission.Console; User.CurrentAlias = new EFAlias() { Name = "IW4MAdmin" }; } Authorized = User.ClientId >= 0; ViewBag.Authorized = Authorized; ViewBag.Url = Startup.Configuration["Web:Address"]; ViewBag.User = User; if (Manager.GetApplicationSettings().Configuration().EnableDiscordLink) { string inviteLink = Manager.GetApplicationSettings().Configuration().DiscordInviteCode; if (inviteLink != null) { ViewBag.DiscordLink = inviteLink.Contains("https") ? inviteLink : $"https://discordapp.com/invite/{inviteLink}"; } else { ViewBag.DiscordLink = ""; } } base.OnActionExecuting(context); }
override public async Task OnClientConnected(EFClient clientFromLog) { Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved"); try { EFClient client = await Manager.GetClientService().GetUnique(clientFromLog.NetworkId); // first time client is connecting to server if (client == null) { Logger.WriteDebug($"Client {clientFromLog} first time connecting"); clientFromLog.CurrentServer = this; client = await Manager.GetClientService().Create(clientFromLog); } /// this is only a temporary version until the IPAddress is transmitted client.CurrentAlias = new EFAlias() { Name = clientFromLog.Name, IPAddress = clientFromLog.IPAddress }; Logger.WriteInfo($"Client {client} connected..."); // Do the player specific stuff client.ClientNumber = clientFromLog.ClientNumber; client.IsBot = clientFromLog.IsBot; client.Score = clientFromLog.Score; client.Ping = clientFromLog.Ping; client.CurrentServer = this; Clients[client.ClientNumber] = client; #if DEBUG == true Logger.WriteDebug($"End PreConnect for {client}"); #endif var e = new GameEvent() { Origin = client, Owner = this, Type = GameEvent.EventType.Connect }; Manager.GetEventHandler().AddEvent(e); await client.OnJoin(client.IPAddress); client.State = ClientState.Connected; } catch (Exception ex) { Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog}"); Logger.WriteError(ex.GetExceptionInfo()); } }
private void HandleDisconnectCalculations(EFClient client, HitState state) { // todo: this not added to states fast connect/disconnect var serverStats = state.Hits.FirstOrDefault(stat => stat.ServerId == state.Server.ServerId && stat.WeaponId == null && stat.WeaponAttachmentComboId == null && stat.HitLocationId == null && stat.MeansOfDeathId == null); if (serverStats == null) { _logger.LogWarning("No server hits were found for {serverId} on disconnect for {client}", state.Server.ServerId, client.ToString()); return; } var aggregate = state.Hits.FirstOrDefault(stat => stat.WeaponId == null && stat.WeaponAttachmentComboId == null && stat.HitLocationId == null && stat.MeansOfDeathId == null && stat.ServerId == null); if (aggregate == null) { _logger.LogWarning("No aggregate found for {serverId} on disconnect for {client}", state.Server.ServerId, client.ToString()); return; } var sessionScores = client.GetAdditionalProperty <List <(int, DateTime)> >(SessionScores); if (sessionScores == null) { _logger.LogWarning("No session scores available for {Client}", client.ToString()); return; } foreach (var stat in new[] { serverStats, aggregate }) { stat.Score ??= 0; if (sessionScores.Count == 0) { stat.Score += client.Score > 0 ? client.Score : client.GetAdditionalProperty <int?>(Helpers.StatManager.ESTIMATED_SCORE) ?? 0 * 50; } else { stat.Score += sessionScores.Sum(item => item.Item1) + (sessionScores.Last().Item1 == client.Score && (DateTime.Now - sessionScores.Last().Item2).TotalMinutes < 1 ? 0 : client.Score); } } }
public async Task <IActionResult> ExecuteAsync(long serverId, string command) { var server = Manager.GetServers().First(s => s.EndPoint == serverId); var client = new EFClient() { ClientId = Client.ClientId, Level = Client.Level, NetworkId = Client.NetworkId, CurrentServer = server, CurrentAlias = new EFAlias() { Name = Client.Name } }; var remoteEvent = new GameEvent() { Type = GameEvent.EventType.Command, Data = command, Origin = client, Owner = server, IsRemote = true }; Manager.GetEventHandler().AddEvent(remoteEvent); List <CommandResponseInfo> response; // wait for the event to process if (!(await remoteEvent.WaitAsync(60 * 1000)).Failed) { response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList(); // remove the added command response for (int i = 0; i < response.Count; i++) { server.CommandResult.Remove(response[i]); } } else { response = new List <CommandResponseInfo>() { new CommandResponseInfo() { ClientId = client.ClientId, Response = Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMAND_TIMEOUT"] } }; } return(View("_Response", response)); }
private async Task <string> ProcessAnnouncement(string msg, EFClient joining) { msg = msg.Replace("{{ClientName}}", joining.Name); msg = msg.Replace("{{ClientLevel}}", Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)); // this prevents it from trying to evaluate it every message if (msg.Contains("{{ClientLocation}}")) { msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString)); } msg = msg.Replace("{{TimesConnected}}", TimesConnected(joining)); return(msg); }
String TimesConnected(EFClient P) { int connection = P.Connections; String Prefix = String.Empty; if (connection % 10 > 3 || connection % 10 == 0 || (connection % 100 > 9 && connection % 100 < 19)) { Prefix = "th"; } else { switch (connection % 10) { case 1: Prefix = "st"; break; case 2: Prefix = "nd"; break; case 3: Prefix = "rd"; break; } } switch (connection) { case 0: case 1: return("first"); case 2: return("second"); case 3: return("third"); case 4: return("fourth"); case 5: return("fifth"); default: return(connection.ToString() + Prefix); } }
private async Task <string> ProcessAnnouncement(string msg, EFClient joining) { msg = msg.Replace("{{ClientName}}", joining.Name); msg = msg.Replace("{{ClientLevel}}", $"{Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)}{(string.IsNullOrEmpty(joining.GetAdditionalProperty<string>("ClientTag")) ? "" : $" (Color::White)({joining.GetAdditionalProperty<string>("ClientTag")}(Color::White))")}"); // this prevents it from trying to evaluate it every message if (msg.Contains("{{ClientLocation}}")) { msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString)); } msg = msg.Replace("{{TimesConnected}}", joining.Connections.Ordinalize()); return(msg); }
public async Task <EFMeta> GetPersistentMeta(string metaKey, EFClient client) { using var ctx = _contextFactory.CreateContext(enableTracking: false); return(await ctx.EFMeta .Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.ClientId == client.ClientId) .Select(_meta => new EFMeta() { MetaId = _meta.MetaId, Key = _meta.Key, ClientId = _meta.ClientId, Value = _meta.Value }) .FirstOrDefaultAsync()); }
public async Task RemovePersistentMeta(string metaKey, EFClient client) { await using var context = _contextFactory.CreateContext(); var existingMeta = await context.EFMeta .FirstOrDefaultAsync(meta => meta.Key == metaKey && meta.ClientId == client.ClientId); if (existingMeta == null) { _logger.LogDebug("No meta with key {key} found for client id {id}", metaKey, client.ClientId); return; } _logger.LogDebug("Removing meta for key {key} with id {id}", metaKey, existingMeta.MetaId); context.EFMeta.Remove(existingMeta); await context.SaveChangesAsync(); }
public async Task OnEvent(GameEvent E, Server S) { if (S.Gametype != "zclassic") { return; } switch (E.Type) { case (GameEvent.EventType.PreConnect): case (GameEvent.EventType.Join): case (GameEvent.EventType.MapChange): _ = SetBankDvars(S); break; case (GameEvent.EventType.Disconnect): _ = SetBankDvars(S); break; case (GameEvent.EventType.Unknown): if (Regex.Match(E.Data, @"IW4MBANK;(\d+);(\d+)").Length > 0) { // Saves bank account values string[] matchList = E.Data.Split(';'); EFClient C = S.GetClientsAsList().Find(c => c.NetworkId == Convert.ToInt64(matchList[1])); await SetBankMeta(C, Convert.ToInt32(matchList[2])); _ = SetBankDvars(S); } if (Regex.Match(E.Data, @"IW4MBANK_ALL;(.)+").Length > 0) { // Game ends, saves bank account values string json = E.Data.Substring(13); List <BankClient> bankClients = JsonConvert.DeserializeObject <List <BankClient> >(json); foreach (BankClient client in bankClients) { EFClient C = S.GetClientsAsList().Find(c => c.NetworkId == Convert.ToInt64(client.Guid)); await SetBankMeta(C, client.Money); } _ = SetBankDvars(S); } break; } }
override protected async Task Ban(string reason, EFClient targetClient, EFClient originClient, bool isEvade = false) { // ensure player gets banned if command not performed on them in game if (targetClient.ClientNumber < 0) { EFClient ingameClient = null; ingameClient = Manager.GetServers() .Select(s => s.GetClientsAsList()) .FirstOrDefault(l => l.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) != null) ?.First(c => c.ClientId == targetClient.ClientId); if (ingameClient != null) { await Ban(reason, ingameClient, originClient, isEvade); return; } } else { #if !DEBUG string formattedString = String.Format(RconParser.Configuration.CommandPrefixes.Kick, targetClient.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{reason} ^7{loc["SERVER_BAN_APPEAL"].FormatExt(Website)}^7"); await targetClient.CurrentServer.ExecuteCommandAsync(formattedString); #else await targetClient.CurrentServer.OnClientDisconnected(targetClient); #endif } Penalty newPenalty = new Penalty() { Type = Penalty.PenaltyType.Ban, Expires = null, Offender = targetClient, Offense = reason, Punisher = originClient, Link = targetClient.AliasLink, AutomatedOffense = originClient.AdministeredPenalties?.FirstOrDefault()?.AutomatedOffense, IsEvadedOffense = isEvade }; targetClient.SetLevel(Permission.Banned, originClient); await Manager.GetPenaltyService().Create(newPenalty); }
public async Task RemoveActivePenalties(int aliasLinkId, EFClient origin) { using (var context = new DatabaseContext()) { var now = DateTime.UtcNow; var penalties = context.Penalties .Include(p => p.Link.Children) .Where(p => p.LinkId == aliasLinkId) .Where(p => p.Expires > now || p.Expires == null); await penalties.ForEachAsync(p => { p.Active = false; }); await context.SaveChangesAsync(); } }
/// <summary> /// Send a message to all players /// </summary> /// <param name="message">Message to be sent to all players</param> public GameEvent Broadcast(string message, EFClient sender = null) { var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "", $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping)}"); ServerLogger.LogDebug("All-> {Message}", message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping).StripColors()); var e = new GameEvent { Type = GameEvent.EventType.Broadcast, Data = formattedMessage, Owner = this, Origin = sender, }; Manager.AddEvent(e); return(e); }
/// <summary> /// Send a message to all players /// </summary> /// <param name="message">Message to be sent to all players</param> public GameEvent Broadcast(string message, EFClient sender = null) { string formattedMessage = String.Format(RconParser.Configuration.CommandPrefixes.Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}"); #if DEBUG == true Logger.WriteVerbose(message.StripColors()); #endif var e = new GameEvent() { Type = GameEvent.EventType.Broadcast, Data = formattedMessage, Owner = this, Origin = sender, }; Manager.GetEventHandler().AddEvent(e); return(e); }
override public async Task Unban(string reason, EFClient Target, EFClient Origin) { var unbanPenalty = new Penalty() { Type = Penalty.PenaltyType.Unban, Expires = null, Offender = Target, Offense = reason, Punisher = Origin, When = DateTime.UtcNow, Active = true, Link = Target.AliasLink }; await Manager.GetPenaltyService().RemoveActivePenalties(Target.AliasLink.AliasLinkId, Origin); await Manager.GetPenaltyService().Create(unbanPenalty); Target.SetLevel(Permission.User, Origin); }
protected override async Task Warn(String Reason, EFClient Target, EFClient Origin) { // ensure player gets warned if command not performed on them in game if (Target.ClientNumber < 0) { var ingameClient = Manager.GetActiveClients() .FirstOrDefault(c => c.ClientId == Target.ClientId); if (ingameClient != null) { await Warn(Reason, ingameClient, Origin); return; } } else { if (Target.Warnings >= 4) { Target.Kick(loc["SERVER_WARNLIMT_REACHED"], Utilities.IW4MAdminClient(this)); return; } string message = $"^1{loc["SERVER_WARNING"]} ^7[^3{Target.Warnings}^7]: ^3{Target.Name}^7, {Reason}"; Target.CurrentServer.Broadcast(message); } Penalty newPenalty = new Penalty() { Type = Penalty.PenaltyType.Warning, Expires = DateTime.UtcNow, Offender = Target, Punisher = Origin, Offense = Reason, Link = Target.AliasLink }; await Manager.GetPenaltyService().Create(newPenalty); }