using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using SharedLibrary.Network; using SharedLibrary.Commands; using System.Threading.Tasks; namespace SharedLibrary { [Guid("61d3829e-fcbe-44d3-bb7c-51db8c2d7ac5")] public abstract class Server { public enum Game { UKN, IW3, IW4, IW5, T4, T5, } public Server(Interfaces.IManager mgr, ServerConfiguration config) { Password = config.Password; IP = config.IP; Port = config.Port; Manager = mgr; Logger = Manager.GetLogger(); Config = config; Players = new List(new Player[18]); Reports = new List(); PlayerHistory = new Queue(); ChatHistory = new List(); NextMessage = 0; InitializeTokens(); InitializeAutoMessages(); InitializeMaps(); InitializeRules(); } //Returns current server IP set by `net_ip` -- *STRING* public String GetIP() { return IP; } //Returns current server port set by `net_port` -- *INT* public int GetPort() { return Port; } //Returns list of all current players public List GetPlayersAsList() { return Players.FindAll(x => x != null); } /// /// Add a player to the server's player list /// /// Player pulled from memory reading /// True if player added sucessfully, false otherwise abstract public Task AddPlayer(Player P); /// /// Remove player by client number /// /// Client ID of player to be removed /// true if removal succeded, false otherwise abstract public Task RemovePlayer(int cNum); /// /// Get the player from the server's list by line from game long /// /// Game log line containing event /// Position in the line where the cliet ID is written /// Matching player if found abstract public Player ParseClientFromString(String[] L, int cIDPos); /// /// Get a player by name /// /// Player name to search for /// Matching player if found public Player GetClientByName(String pName) { string[] QuoteSplit = pName.Split('"'); if (QuoteSplit.Length > 1) pName = QuoteSplit[1]; return Players.FirstOrDefault(p => p != null && p.Name.ToLower().Contains(pName.ToLower())); } /// /// Check ban list for every banned player and return ban if match is found /// /// Player to check if banned /// Matching ban if found abstract public Penalty IsBanned(Player C); /// /// Process requested command correlating to an event /// /// Event parameter /// Command requested from the event /// abstract public Task ValidateCommand(Event E); virtual public Task ProcessUpdatesAsync(CancellationToken cts) { return null; } /// /// Legacy method for the alias command /// /// /// public IList GetAliases(Player P) { return Manager.GetAliases(P); } /// /// Process any server event /// /// Event /// True on sucess abstract protected Task ProcessEvent(Event E); abstract public Task ExecuteEvent(Event E); /// /// Reloads all the server configurations /// /// True on sucess abstract public bool Reload(); /// /// Send a message to all players /// /// Message to be sent to all players public async Task Broadcast(String Message) { #if DEBUG //return; #endif string sayCommand = (GameName == Game.IW4) ? "sayraw" : "say"; await this.ExecuteCommandAsync($"{sayCommand} {Message}"); } /// /// Send a message to a particular players /// /// Message to send /// Player to send message to public async Task Tell(String Message, Player Target) { #if DEBUG //if (!Target.lastEvent.Remote) // return; #endif string tellCommand = (GameName == Game.IW4) ? "tellraw" : "tell"; if (Target.ClientID > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console && !Target.lastEvent.Remote) await this.ExecuteCommandAsync($"{tellCommand} {Target.ClientID} {Message}^7"); if (Target.Level == Player.Permission.Console) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(Utilities.StripColors(Message)); Console.ForegroundColor = ConsoleColor.Gray; } if (Target.lastEvent.Remote) commandResult.Enqueue(Utilities.StripColors(Message)); } /// /// Send a message to all admins on the server /// /// Message to send out public async Task ToAdmins(String message) { foreach (Player P in Players) { if (P == null) continue; if (P.Level > Player.Permission.Flagged) await P.Tell(message); } } /// /// Kick a player from the server /// /// Reason for kicking /// Player to kick abstract public Task Kick(String Reason, Player Target, Player Origin); /// /// Temporarily ban a player ( default 1 hour ) from the server /// /// Reason for banning the player /// The player to ban abstract public Task TempBan(String Reason, TimeSpan length, Player Target, Player Origin); /// /// Perm ban a player from the server /// /// The reason for the ban /// The person to ban /// The person who banned the target abstract public Task Ban(String Reason, Player Target, Player Origin); abstract public Task Warn(String Reason, Player Target, Player Origin); /// /// Unban a player by npID / GUID /// /// npID of the player /// I don't remember what this is for /// abstract public Task Unban(Player Target); /// /// Change the current searver map /// /// Non-localized map name public async Task LoadMap(string mapName) { await this.ExecuteCommandAsync($"map {mapName}"); } public async Task LoadMap(Map newMap) { await this.ExecuteCommandAsync($"map {newMap.Name}"); } /// /// Initalize the macro variables /// abstract public void InitializeTokens(); /// /// Read the map configuration /// protected void InitializeMaps() { Maps = new List(); IFile mapfile = new IFile("config/maps.cfg"); String[] _maps = mapfile.ReadAllLines(); mapfile.Close(); if (_maps.Length > 2) // readAll returns minimum one empty string { foreach (String m in _maps) { String[] m2 = m.Split(':'); if (m2.Length > 1) { Map map = new Map(m2[0].Trim(), m2[1].Trim()); Maps.Add(map); } } } else Logger.WriteInfo("Maps configuration appears to be empty - skipping..."); } /// /// Initialize the messages to be broadcasted /// todo: this needs to be a serialized file /// protected void InitializeAutoMessages() { BroadcastMessages = new List(); IFile messageCFG = new IFile("config/messages.cfg"); String[] lines = messageCFG.ReadAllLines(); messageCFG.Close(); if (lines.Length < 2) //readAll returns minimum one empty string { Logger.WriteInfo("Messages configuration appears empty - skipping..."); return; } int mTime = -1; int.TryParse(lines[0], out mTime); if (MessageTime == -1) MessageTime = 60; else MessageTime = mTime; foreach (String l in lines) { if (lines[0] != l && l.Length > 1) BroadcastMessages.Add(l); } messageCFG.Close(); //if (Program.Version != Program.latestVersion && Program.latestVersion != 0) // messages.Add("^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + Program.latestVersion); } /// /// Initialize the rules configuration /// todo: this needs to be a serialized file /// protected void InitializeRules() { Rules = new List(); IFile ruleFile = new IFile("config/rules.cfg"); String[] _rules = ruleFile.ReadAllLines(); ruleFile.Close(); if (_rules.Length > 2) // readAll returns minimum one empty string { foreach (String r in _rules) { if (r.Length > 1) Rules.Add(r); } } else Logger.WriteInfo("Rules configuration appears empty - skipping..."); ruleFile.Close(); } public override string ToString() { return $"{IP}_{Port}"; } // Objects public Interfaces.IManager Manager { get; protected set; } public Interfaces.ILogger Logger { get; private set; } public ServerConfiguration Config { get; private set; } public List Maps { get; protected set; } public List Rules { get; protected set; } public List Reports { get; set; } public List ChatHistory { get; protected set; } public Queue PlayerHistory { get; private set; } public Game GameName { get; protected set; } // Info public string Hostname { get; protected set; } public string Website { get; protected set; } public string Gametype { get; protected set; } public Map CurrentMap { get; protected set; } public int ClientNum { get { return Players.Where(p => p != null).Count(); } } public int MaxClients { get; protected set; } public List Players { get; protected set; } public string Password { get; private set; } public bool Throttled { get; protected set; } // Internal protected string IP; protected int Port; protected string FSGame; protected int MessageTime; protected int NextMessage; protected int ConnectionErrors; protected List BroadcastMessages; protected TimeSpan LastMessage; protected IFile LogFile; protected DateTime LastPoll; //Remote public Queue commandResult = new Queue(); } }