using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Threading.Tasks; namespace SharedLibraryCore.Objects { public class Player : Database.Models.EFClient { public enum ClientState { /// /// represents when the client has been detected as joining /// by the log file, but has not be authenticated by RCon /// Connecting, /// /// represents when the client has been parsed by RCon, /// but has not been validated against the database /// Authenticated, /// /// represents when the client has been authenticated by RCon /// and validated by the database /// Connected, /// /// represents when the client is leaving (either through RCon or log file) /// Disconnecting, } public enum Permission { /// /// client has been banned /// Banned = -1, /// /// default client state upon first connect /// User = 0, /// /// client has been flagged /// Flagged = 1, /// /// client is trusted /// Trusted = 2, /// /// client is a moderator /// Moderator = 3, /// /// client is an administrator /// Administrator = 4, /// /// client is a senior administrator /// SeniorAdmin = 5, /// /// client is a owner /// Owner = 6, /// /// not used /// Creator = 7, /// /// reserved for default account /// Console = 8 } public Player() { ConnectionTime = DateTime.UtcNow; ClientNumber = -1; DelayedEvents = new Queue(); _additionalProperties = new Dictionary { { "_reportCount", 0 } }; } public override string ToString() => $"{Name}::{NetworkId}"; /// /// send a message directly to the connected client /// /// message content to send to client public GameEvent Tell(String message) { var e = new GameEvent() { Message = message, Target = this, Owner = CurrentServer, Type = GameEvent.EventType.Tell, Data = message }; this.CurrentServer?.Manager.GetEventHandler().AddEvent(e); return e; } /// /// warn a client with given reason /// /// reason for warn /// client performing the warn public GameEvent Warn(String warnReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Warn, Message = warnReason, Data = warnReason, Origin = sender, Target = this, Owner = sender.CurrentServer }; // enforce level restrictions if (this.Level > sender.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } else { this.Warnings++; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// clear all warnings for a client /// /// client performing the warn clear /// public GameEvent WarnClear(Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.WarnClear, Origin = sender, Target = this, Owner = sender.CurrentServer }; // enforce level restrictions if (sender.Level <= this.Level) { e.FailReason = GameEvent.EventFailReason.Permission; return e; } this.Warnings = 0; sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// report a client for a given reason /// /// reason for the report /// client performing the report /// public GameEvent Report(string reportReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Report, Message = reportReason, Data = reportReason, Origin = sender, Target = this, Owner = sender.CurrentServer }; int reportCount = sender.GetAdditionalProperty("_reportCount"); if (this.Level > sender.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } else if (this.Equals(sender)) { e.FailReason = GameEvent.EventFailReason.Invalid; } else if (reportCount > 2) { e.FailReason = GameEvent.EventFailReason.Throttle; } else if (CurrentServer.Reports.Count(report => (report.Origin.NetworkId == sender.NetworkId && report.Target.NetworkId == this.NetworkId)) > 0) { e.FailReason = GameEvent.EventFailReason.Exception; } sender.SetAdditionalProperty("_reportCount", reportCount + 1); sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// flag a client for a given reason /// /// reason for flagging /// client performing the flag /// game event for the flag public GameEvent Flag(string flagReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Flag, Origin = sender, Data = flagReason, Message = flagReason, Target = this, Owner = sender.CurrentServer }; if (this.Level >= sender.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } else if (this.Level == Player.Permission.Flagged) { e.FailReason = GameEvent.EventFailReason.Invalid; } else { this.Level = Player.Permission.Flagged; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// unflag a client for a given reason /// /// reason to unflag a player for /// client performing the unflag /// game event for the un flug public GameEvent Unflag(string unflagReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Unflag, Origin = sender, Target = this, Data = unflagReason, Message = unflagReason, Owner = sender.CurrentServer }; if (sender.Level <= this.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } else if (this.Level != Player.Permission.Flagged) { e.FailReason = GameEvent.EventFailReason.Invalid; } else { this.Level = Permission.User; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// kick a client for the given reason /// /// reason to kick for /// client performing the kick public GameEvent Kick(String kickReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Kick, Message = kickReason, Target = this, Origin = sender, Data = kickReason, Owner = sender.CurrentServer }; // enforce level restrictions if (this.Level > sender.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// temporarily ban a client for the given time span /// /// reason for the temp ban /// how long the temp ban lasts /// client performing the tempban public GameEvent TempBan(String tempbanReason, TimeSpan banLength, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.TempBan, Message = tempbanReason, Data = tempbanReason, Origin = sender, Target = this, Extra = banLength, Owner = sender.CurrentServer }; // enforce level restrictions if (sender.Level <= this.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// permanently ban a client /// /// reason for the ban /// client performing the ban public GameEvent Ban(String banReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Ban, Message = banReason, Data = banReason, Origin = sender, Target = this, Owner = sender.CurrentServer }; // enforce level restrictions if (sender.Level <= this.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } /// /// unban a client /// /// reason for the unban /// client performing the unban /// public GameEvent Unban(String unbanReason, Player sender) { var e = new GameEvent() { Type = GameEvent.EventType.Unban, Message = unbanReason, Data = unbanReason, Origin = sender, Target = this, Owner = sender.CurrentServer }; // enforce level restrictions if (this.Level > sender.Level) { e.FailReason = GameEvent.EventFailReason.Permission; } sender.CurrentServer.Manager.GetEventHandler().AddEvent(e); return e; } [NotMapped] Dictionary _additionalProperties; public T GetAdditionalProperty(string name) => _additionalProperties.ContainsKey(name) ? (T)_additionalProperties[name] : default(T); public void SetAdditionalProperty(string name, object value) { if (_additionalProperties.ContainsKey(name)) { _additionalProperties[name] = value; } else { _additionalProperties.Add(name, value); } } [NotMapped] public int ClientNumber { get; set; } [NotMapped] public int Ping { get; set; } [NotMapped] public int Warnings { get; set; } [NotMapped] public DateTime ConnectionTime { get; set; } [NotMapped] public int ConnectionLength => (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds; [NotMapped] public Server CurrentServer { get; set; } [NotMapped] public int Score { get; set; } [NotMapped] public bool IsBot { get; set; } private int _ipaddress; public override int IPAddress { get { return _ipaddress; } set { _ipaddress = value; } } private string _name; public override string Name { get { return _name; } set { _name = value; } } [NotMapped] public ClientState State { get; set; } [NotMapped] public Queue DelayedEvents { get; set; } [NotMapped] // this is kinda dirty, but I need localizable level names public ClientPermission ClientPermission => new ClientPermission() { Level = Level, Name = Utilities.CurrentLocalization .LocalizationIndex[$"GLOBAL_PERMISSION_{Level.ToString().ToUpper()}"] }; public override bool Equals(object obj) { return ((Player)obj).NetworkId == this.NetworkId; } public override int GetHashCode() => (int)NetworkId; } }