using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SharedLibrary { public abstract class Server { public Server(string address, int port, string password, int H, int PID) { this.PID = PID; Handle = H; IP = address; Port = port; clientnum = 0; logFile = new IFile("admin_" + port + ".log", true); #if DEBUG Log = new Log(logFile, Log.Level.Debug, port); #else Log = new Log(logFile, Log.Level.Production, port); #endif clientDB = new ClientsDB("clients.rm"); aliasDB = new AliasesDB("aliases.rm"); Bans = new List(); players = new List(new Player[18]); events = new Queue(); Macros = new Dictionary(); Reports = new List(); statusPlayers = new Dictionary(); playerHistory = new Queue(); chatHistory = new List(); lastWebChat = DateTime.Now; nextMessage = 0; initCommands(); initMacros(); initMessages(); initMaps(); initRules(); } //Returns the current server name -- *STRING* public String getName() { return hostname; } public String getMap() { return mapname; } public String getGametype() { return Gametype; } //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 number of active clients on server -- *INT* public int getNumPlayers() { return clientnum; } //Returns the list of commands public List getCommands() { return commands; } //Returns list of all current players public List getPlayers() { return players; } public int getClientNum() { return clientnum; } public int getMaxClients() { return maxClients; } //Returns list of all active bans (loaded at runtime) public List getBans() { return Bans; } public int pID() { return this.PID; } /// /// Get any know aliases ( name or ip based ) from the database /// /// Player to scan for aliases abstract public List getAliases(Player Origin); public List getPlayerAliases(Player Origin) { List databaseIDs = new List(); foreach (Aliases A in getAliases(Origin)) databaseIDs.Add(A.Number); return clientDB.getPlayers(databaseIDs); } /// /// Add a player to the server's player list /// /// Player pulled from memory reading /// True if player added sucessfully, false otherwise abstract public bool addPlayer(Player P); /// /// Remove player by client number /// /// Client ID of player to be removed /// true if removal succeded, false otherwise abstract public bool 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 clientFromEventLine(String[] L, int cIDPos); /// /// Get a player by name /// /// Player name to search for /// Matching player if found public Player clientFromName(String pName) { lock (players) { foreach (var P in players) { if (P != null && P.Name.ToLower().Contains(pName.ToLower())) return P; } } return null; } /// /// 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 Command processCommand(Event E, Command C); /// /// Execute a command on the server /// /// Command to execute abstract public void executeCommand(String CMD); /// /// Retrieve a Dvar from the server /// /// Name of Dvar to retrieve /// Dvar if found abstract public dvar getDvar(String DvarName); /// /// Set a Dvar on the server /// /// Name of the /// abstract public void setDvar(String Dvar, String Value); /// /// Main loop for the monitoring processes of the server ( handles events and connects/disconnects ) /// abstract public void Monitor(); /// /// Set up the basic variables ( base path / hostname / etc ) that allow the monitor thread to work /// /// True if no issues initializing, false otherwise abstract public bool intializeBasics(); /// /// Process any server event /// /// Event /// True on sucess abstract public bool processEvent(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 void Broadcast(String Message) { executeCommand("sayraw " + Message); } /// /// Send a message to a particular players /// /// Message to send /// Player to send message to public void Tell(String Message, Player Target) { if (Target.clientID > -1 && Message.Length > 0) executeCommand("tellraw " + Target.clientID + " " + Message + "^7"); if (Target.Level == Player.Permission.Console) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(Utilities.stripColors(Message)); Console.ForegroundColor = ConsoleColor.Gray; } } /// /// Send a message to all admins on the server /// /// Message to send out public void ToAdmins(String message) { lock (players) // threading can modify list while we do this { foreach (Player P in players) { if (P == null) continue; if (P.Level > Player.Permission.Flagged) { P.Alert(); P.Tell(message); } } } } /// /// Alert a player via gsc implementation /// /// public void Alert(Player P) { executeCommand("admin_lastevent alert;" + P.npID + ";0;mp_killstreak_nuclearstrike"); } /// /// Kick a player from the server /// /// Reason for kicking /// Player to kick abstract public void 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 void tempBan(String Reason, 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 void Ban(String Reason, Player Target, Player Origin); abstract public void 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 bool Unban(String npID, Player Target); /// /// Fast restart the server with a specified delay /// /// public void fastRestart(int delay) { Utilities.Wait(delay); executeCommand("fast_restart"); } /// /// Rotate the server to the next map with specified delay /// /// public void mapRotate(int delay) { Utilities.Wait(delay); executeCommand("map_rotate"); } /// /// Map rotate without delay /// public void mapRotate() { mapRotate(0); } /// /// Change the current searver map /// /// Non-localized map name public void Map(String mapName) { executeCommand("map " + mapName); } public void webChat(Player P, String Message) { DateTime requestTime = DateTime.Now; if ((requestTime - lastWebChat).TotalSeconds > 1) { Broadcast("^1[WEBCHAT] ^5" + P.Name + "^7 - " + Message); while (chatHistory.Count > Math.Ceiling((double)clientnum / 2)) chatHistory.RemoveAt(0); if (Message.Length > 50) Message = Message.Substring(0, 50) + "..."; chatHistory.Add(new Chat(P, Utilities.stripColors(Message), DateTime.Now)); lastWebChat = DateTime.Now; } } /// /// Initalize the macro variables /// abstract public void initMacros(); /// /// Read the map configuration /// protected void initMaps() { maps = new List(); IFile mapfile = new IFile("config\\maps.cfg"); String[] _maps = mapfile.readAll(); 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 Log.Write("Maps configuration appears to be empty - skipping...", Log.Level.All); } /// /// Initialize the messages to be broadcasted /// protected void initMessages() { messages = new List(); IFile messageCFG = new IFile("config\\messages.cfg"); String[] lines = messageCFG.readAll(); messageCFG.Close(); if (lines.Length < 2) //readAll returns minimum one empty string { Log.Write("Messages configuration appears empty - skipping...", Log.Level.All); 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) messages.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 /// protected void initRules() { rules = new List(); IFile ruleFile = new IFile("config\\rules.cfg"); String[] _rules = ruleFile.readAll(); 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 Log.Write("Rules configuration appears empty - skipping...", Log.Level.All); ruleFile.Close(); } /// /// Load up the built in commands /// abstract public void initCommands(); //Objects public Log Log { get; private set; } public List Bans; public Player owner; public List maps; public List rules; public Queue events; public String Website; public String Gametype; public int totalKills = 0; public List Reports; public List chatHistory; public Queue playerHistory { get; private set; } //Info protected String IP; protected int Port; protected String hostname; protected String mapname; protected int clientnum; protected List players; protected List commands; protected List messages; protected int messageTime; protected TimeSpan lastMessage; protected DateTime lastPoll; protected int nextMessage; protected String IW_Ver; protected int maxClients; protected Dictionary Macros; protected DateTime lastWebChat; protected int Handle; protected int PID; protected IFile logFile; // Will probably move this later public Dictionary statusPlayers; public bool isRunning; // Log stuff protected String Basepath; protected String Mod; protected String logPath; // Databases public ClientsDB clientDB; public AliasesDB aliasDB; } }