57ddbebd8c
modified the deployment of outdated message inform user of invalid rcon password reworked layout of first time server setup fixed KDR not being properly truncated in some cases fixed duplicate game-end event more crash fixes
833 lines
29 KiB
C#
833 lines
29 KiB
C#
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading; //SLEEP
|
|
using System.IO;
|
|
|
|
|
|
namespace IW4MAdmin
|
|
{
|
|
class Server
|
|
{
|
|
const int FLOOD_TIMEOUT = 300;
|
|
|
|
public Server(string address, int port, string password)
|
|
{
|
|
IP = address;
|
|
Port = port;
|
|
rcon_pass = password;
|
|
clientnum = 0;
|
|
RCON = new RCON(this);
|
|
logFile = new file("admin_" + port + ".log", true);
|
|
Log = new Log(logFile, Log.Level.Production);
|
|
players = new List<Player>(new Player[18]);
|
|
DB = new Database("clients.rm", Database.Type.Clients);
|
|
stats = new Database("stats_" + port + ".rm", Database.Type.Stats);
|
|
Bans = DB.getBans();
|
|
owner = DB.getOwner();
|
|
maps = new List<Map>();
|
|
rules = new List<String>();
|
|
messages = new List<String>();
|
|
events = new Queue<Event>();
|
|
HB = new Heartbeat(this);
|
|
nextMessage = 0;
|
|
initCommands();
|
|
initMessages();
|
|
initMaps();
|
|
initRules();
|
|
}
|
|
|
|
//Returns the current server name -- *STRING*
|
|
public String getName()
|
|
{
|
|
return hostname;
|
|
}
|
|
|
|
public String getMap()
|
|
{
|
|
return mapname;
|
|
}
|
|
|
|
//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<Command> getCommands()
|
|
{
|
|
return commands;
|
|
}
|
|
|
|
//Returns list of all current players
|
|
public List<Player> getPlayers()
|
|
{
|
|
return players;
|
|
}
|
|
|
|
public int getClientNum()
|
|
{
|
|
return clientnum;
|
|
}
|
|
|
|
//Returns list of all active bans (loaded at runtime)
|
|
public List<Ban> getBans()
|
|
{
|
|
return Bans;
|
|
}
|
|
|
|
//Add player object p to `players` list
|
|
public bool addPlayer(Player P)
|
|
{
|
|
try
|
|
{
|
|
if (DB.getPlayer(P.getID(), P.getClientNum()) == null)
|
|
DB.addPlayer(P);
|
|
else
|
|
{
|
|
//messy way to prevent loss of last event
|
|
Player A;
|
|
A = DB.getPlayer(P.getID(), P.getClientNum());
|
|
A.lastEvent = P.lastEvent;
|
|
P = A;
|
|
}
|
|
|
|
P.stats = stats.getStats(P.getDBID());
|
|
if (P.stats == null)
|
|
{
|
|
stats.addPlayer(P);
|
|
P.stats = new Stats(0, 0, 0, 0);
|
|
}
|
|
players[P.getClientNum()] = null;
|
|
players[P.getClientNum()] = P;
|
|
|
|
clientnum++;
|
|
|
|
if (P.getLevel() == Player.Permission.Banned)
|
|
{
|
|
Log.Write("Banned client " + P.getName() + " trying to connect...", Log.Level.Debug);
|
|
String Message = "^1Player Kicked: ^7Previously Banned for ^5" + isBanned(P).getReason();
|
|
P.Kick(Message);
|
|
}
|
|
|
|
else
|
|
Log.Write("Client " + P.getName() + " connecting...", Log.Level.Debug);
|
|
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
Log.Write("Unable to add player " + P.getName() + " - " + E.Message, Log.Level.Debug);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//Remove player by CLIENT NUMBER
|
|
public bool removePlayer(int cNum)
|
|
{
|
|
Log.Write("Client at " + cNum + " disconnecting...", Log.Level.Debug);
|
|
players[cNum] = null;
|
|
clientnum--;
|
|
return true;
|
|
}
|
|
|
|
//Get a client from players list by by log line. If create = true, it will return a new player object
|
|
public Player clientFromLine(String[] line, int name_pos, bool create)
|
|
{
|
|
string Name = line[name_pos].ToString().Trim();
|
|
if (create)
|
|
{
|
|
Player C = new Player(Name, line[1].ToString(), Convert.ToInt16(line[2]), 0);
|
|
return C;
|
|
}
|
|
|
|
else
|
|
{
|
|
foreach (Player P in players)
|
|
{
|
|
if (P == null)
|
|
continue;
|
|
|
|
if (line[1].Trim() == P.getID())
|
|
return P;
|
|
}
|
|
|
|
Log.Write("Could not find player but player is in server. Lets try to manually add (looks like you didn't start me on an empty server)", Log.Level.All);
|
|
addPlayer(new Player(Name, line[1].ToString(), Convert.ToInt16(line[2]), 0));
|
|
return players[Convert.ToInt16(line[2])];
|
|
}
|
|
}
|
|
|
|
//Should be client from Name ( returns client in players list by name )
|
|
public Player clientFromLine(String Name)
|
|
{
|
|
foreach (Player P in players)
|
|
{
|
|
if (P == null)
|
|
continue;
|
|
if (P.getName().ToLower().Contains(Name.ToLower()))
|
|
return P;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public Ban isBanned(Player C)
|
|
{
|
|
if (C.getLevel() == Player.Permission.Banned)
|
|
{
|
|
foreach (Ban B in Bans)
|
|
{
|
|
if (B.getID() == C.getID())
|
|
return B;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public Command processCommand(Event E, Command C)
|
|
{
|
|
E.Data = Utilities.removeWords(E.Data, 1);
|
|
String[] Args = E.Data.Trim().Split(' ');
|
|
|
|
if (Args.Length < (C.getNumArgs()))
|
|
{
|
|
E.Origin.Tell("Not enough arguments supplied!");
|
|
return null;
|
|
}
|
|
|
|
if(E.Origin.getLevel() < C.getNeededPerm())
|
|
{
|
|
E.Origin.Tell("You do not have access to that command!");
|
|
return null;
|
|
}
|
|
|
|
if (C.needsTarget())
|
|
{
|
|
int cNum = -1;
|
|
int.TryParse(Args[0], out cNum);
|
|
|
|
if (Args[0] == String.Empty)
|
|
return C;
|
|
|
|
if (Args[0][0] == '@')
|
|
{
|
|
int dbID = -1;
|
|
int.TryParse(Args[0].Substring(1, Args[0].Length-1), out dbID);
|
|
Player found = E.Owner.DB.findPlayers(dbID);
|
|
if (found != null)
|
|
E.Target = found;
|
|
}
|
|
|
|
else if(Args[0].Length < 3 && cNum > -1 && cNum < 18)
|
|
{
|
|
if (players[cNum] != null)
|
|
E.Target = players[cNum];
|
|
}
|
|
|
|
else
|
|
E.Target = clientFromLine(Args[0]);
|
|
|
|
if (E.Target == null)
|
|
{
|
|
E.Origin.Tell("Unable to find specified player.");
|
|
return null;
|
|
}
|
|
}
|
|
return C;
|
|
}
|
|
|
|
private void addEvent(Event E)
|
|
{
|
|
events.Enqueue(E);
|
|
}
|
|
|
|
private void manageEventQueue()
|
|
{
|
|
while (true)
|
|
{
|
|
if (events.Count > 0)
|
|
{
|
|
processEvent(events.Peek());
|
|
events.Dequeue();
|
|
}
|
|
Utilities.Wait(0.1);
|
|
}
|
|
}
|
|
|
|
//Starts the monitoring process
|
|
public void Monitor()
|
|
{
|
|
if (!intializeBasics())
|
|
{
|
|
Log.Write("Stopping " + Port + " due to uncorrectable errors (check log)" + logPath, Log.Level.Production);
|
|
Utilities.Wait(10);
|
|
return;
|
|
}
|
|
|
|
//Handles new rcon requests in a fashionable manner
|
|
Thread RCONQueue = new Thread(new ThreadStart(RCON.ManageRCONQueue));
|
|
RCONQueue.Start();
|
|
|
|
//Handles new events in a fashionable manner
|
|
Thread eventQueue = new Thread(new ThreadStart(manageEventQueue));
|
|
eventQueue.Start();
|
|
|
|
long l_size = -1;
|
|
String[] lines = new String[8];
|
|
String[] oldLines = new String[8];
|
|
DateTime start = DateTime.Now;
|
|
|
|
//Utilities.Wait(1);
|
|
//Broadcast("IW4M Admin is now ^2ONLINE");
|
|
|
|
while (errors <=5)
|
|
{
|
|
try
|
|
{
|
|
lastMessage = DateTime.Now - start;
|
|
if(lastMessage.TotalSeconds > messageTime && messages.Count > 0)
|
|
{
|
|
Broadcast(messages[nextMessage]);
|
|
if (nextMessage == (messages.Count - 1))
|
|
nextMessage = 0;
|
|
else
|
|
nextMessage++;
|
|
start = DateTime.Now;
|
|
HB.Send();
|
|
}
|
|
|
|
if (l_size != logFile.getSize())
|
|
{
|
|
lines = logFile.Tail(8);
|
|
if (lines != oldLines)
|
|
{
|
|
l_size = logFile.getSize();
|
|
int end;
|
|
if (lines.Length == oldLines.Length)
|
|
end = lines.Length - 1;
|
|
else
|
|
end = Math.Abs((lines.Length - oldLines.Length)) - 1;
|
|
|
|
for (int count = 0; count < lines.Length; count++)
|
|
{
|
|
if (lines.Length < 1 && oldLines.Length < 1)
|
|
continue;
|
|
|
|
if (lines[count] == oldLines[oldLines.Length - 1])
|
|
continue;
|
|
|
|
if (lines[count].Length < 10) //Not a needed line
|
|
continue;
|
|
|
|
else
|
|
{
|
|
string[] game_event = lines[count].Split(';');
|
|
Event event_ = Event.requestEvent(game_event, this);
|
|
if (event_ != null)
|
|
{
|
|
if (event_.Origin == null)
|
|
event_.Origin = new Player("WORLD", "-1", -1, 0);
|
|
|
|
event_.Origin.lastEvent = event_;
|
|
event_.Origin.lastEvent.Owner = this;
|
|
|
|
addEvent(event_);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
oldLines = lines;
|
|
l_size = logFile.getSize();
|
|
Thread.Sleep(1);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
Log.Write("Something unexpected occured. Hopefully we can ignore it - " + E.Message + " @" + Utilities.GetLineNumber(E), Log.Level.All);
|
|
errors++;
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
RCONQueue.Abort();
|
|
eventQueue.Abort();
|
|
|
|
}
|
|
|
|
//Vital RCON commands to establish log file and server name. May need to cleanup in the future
|
|
private bool intializeBasics()
|
|
{
|
|
try
|
|
{
|
|
//get sv_hostname
|
|
String[] p = RCON.responseSendRCON("sv_hostname");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain server name!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
hostname = Utilities.stripColors(p[3].Substring(0, p[3].Length - 2).Trim());
|
|
p = null;
|
|
//END
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
|
|
//get mapname
|
|
p = RCON.responseSendRCON("mapname");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain map name!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
mapname = Utilities.stripColors(p[3].Substring(0, p[3].Length - 2).Trim());
|
|
p = null;
|
|
//END
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
|
|
//GET fs_basepath
|
|
p = RCON.responseSendRCON("fs_basepath");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain basepath!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
Basepath = p[3].Substring(0, p[3].Length - 2).Trim();
|
|
p = null;
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
//END
|
|
|
|
//get fs_game
|
|
p = RCON.responseSendRCON("fs_game");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain mod path!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
Mod = p[3].Substring(0, p[3].Length - 2).Trim().Replace('/', '\\');
|
|
p = null;
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
//END
|
|
|
|
//get g_log
|
|
p = RCON.responseSendRCON("g_log");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain log path!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
if (p.Length < 4)
|
|
{
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
Log.Write("Server does not appear to have map loaded. Please map_rotate", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
string log = p[3].Substring(0, p[3].Length - 2).Trim();
|
|
p = null;
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
//END
|
|
|
|
//get g_logsync
|
|
p = RCON.responseSendRCON("g_logsync");
|
|
|
|
if (p == null)
|
|
{
|
|
Log.Write("Could not obtain log sync status!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
|
|
p = p[1].Split('"');
|
|
int logsync = Convert.ToInt32(p[3].Substring(0, p[3].Length - 2).Trim());
|
|
p = null;
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
if (logsync != 1)
|
|
RCON.sendRCON("g_logsync 1");
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
//END
|
|
|
|
//get iw4m_onelog
|
|
p = RCON.responseSendRCON("iw4m_onelog");
|
|
|
|
if (p[0] == String.Empty || p[1].Length < 15)
|
|
{
|
|
Log.Write("Could not obtain iw4m_onelog value!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
p = p[1].Split('"');
|
|
string onelog = p[3].Substring(0, p[3].Length - 2).Trim();
|
|
p = null;
|
|
//END
|
|
|
|
Thread.Sleep(FLOOD_TIMEOUT);
|
|
|
|
if (Mod == String.Empty || onelog == "1")
|
|
logPath = Basepath + '\\' + "m2demo" + '\\' + log;
|
|
else
|
|
logPath = Basepath + '\\' + Mod + '\\' + log;
|
|
|
|
if (!File.Exists(logPath))
|
|
{
|
|
Log.Write("Gamelog does not exist!", Log.Level.All);
|
|
return false;
|
|
}
|
|
|
|
logFile = new file(logPath);
|
|
Log.Write("Log file is " + logPath, Log.Level.Debug);
|
|
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
Log.Write("Error during initialization - " + E.Message, Log.Level.All);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//Process any server event
|
|
public bool processEvent(Event E)
|
|
{
|
|
if (E.Type == Event.GType.Connect)
|
|
{
|
|
addPlayer(E.Origin);
|
|
return true;
|
|
}
|
|
|
|
if (E.Type == Event.GType.Disconnect)
|
|
{
|
|
if (getNumPlayers() > 0 && E.Origin != null)
|
|
{
|
|
DB.updatePlayer(E.Origin);
|
|
stats.updatePlayer(E.Origin);
|
|
removePlayer(E.Origin.getClientNum());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (E.Type == Event.GType.Kill)
|
|
{
|
|
if (E.Origin != null && E.Target != null && E.Origin.stats != null)
|
|
{
|
|
E.Origin.stats.Kills++;
|
|
E.Origin.stats.Update();
|
|
E.Target.stats.Deaths++;
|
|
E.Target.stats.Update();
|
|
}
|
|
}
|
|
|
|
if (E.Type == Event.GType.Say && E.Origin != null)
|
|
{
|
|
if (E.Data.Length < 2)
|
|
return false;
|
|
|
|
Log.Write("Message from " + E.Origin.getName() + ": " + E.Data, Log.Level.Debug);
|
|
|
|
if (E.Data.Substring(0, 1) != "!")
|
|
return true;
|
|
|
|
Command C = E.isValidCMD(commands);
|
|
if (C != null)
|
|
{
|
|
C = processCommand(E, C);
|
|
if (C != null)
|
|
{
|
|
C.Execute(E);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Log.Write("Error processing command by " + E.Origin.getName(), Log.Level.Debug);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
else
|
|
E.Origin.Tell("You entered an invalid command!");
|
|
|
|
return true;
|
|
}
|
|
|
|
if (E.Type == Event.GType.MapChange)
|
|
{
|
|
Log.Write("New map loaded", Log.Level.Debug);
|
|
String[] statusResponse = E.Data.Split('\\');
|
|
if (statusResponse.Length >= 15 && statusResponse[13] == "mapname")
|
|
mapname = maps.Find(m => m.Name.Equals(statusResponse[14])).Alias; //update map for heartbeat
|
|
}
|
|
|
|
if (E.Type == Event.GType.MapEnd)
|
|
{
|
|
Log.Write("Game ending...", Log.Level.Debug);
|
|
foreach (Player P in players)
|
|
{
|
|
if (P == null || P.stats == null)
|
|
continue;
|
|
stats.updatePlayer(P);
|
|
Log.Write("Updated stats for client " + P.getDBID(), Log.Level.Debug);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//THESE MAY NEED TO BE MOVED
|
|
public void Broadcast(String Message)
|
|
{
|
|
RCON.addRCON("sayraw " + Message, 0);
|
|
}
|
|
|
|
public void Tell(String Message, Player Target)
|
|
{
|
|
RCON.addRCON("tell " + Target.getClientNum() + " " + Message + "^7", 0);
|
|
}
|
|
|
|
public void Kick(String Message, Player Target)
|
|
{
|
|
RCON.addRCON("clientkick " + Target.getClientNum() + " \"" + Message + "^7\"", 0);
|
|
}
|
|
|
|
public void Ban(String Message, Player Target, Player Origin)
|
|
{
|
|
RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "^7\"", 0);
|
|
if (Origin != null)
|
|
{
|
|
Target.setLevel(Player.Permission.Banned);
|
|
Ban newBan = new Ban(Target.getLastO(), Target.getID(), Origin.getID());
|
|
Bans.Add(newBan);
|
|
DB.addBan(newBan);
|
|
DB.updatePlayer(Target);
|
|
}
|
|
}
|
|
|
|
public bool Unban(String GUID, Player Target)
|
|
{
|
|
foreach (Ban B in Bans)
|
|
{
|
|
if (B.getID() == Target.getID())
|
|
{
|
|
DB.removeBan(GUID);
|
|
Bans.Remove(B);
|
|
Player P = DB.getPlayer(Target.getID(), 0);
|
|
P.setLevel(Player.Permission.User);
|
|
DB.updatePlayer(P);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
public void fastRestart(int delay)
|
|
{
|
|
Utilities.Wait(delay);
|
|
RCON.addRCON("fast_restart", 0);
|
|
}
|
|
|
|
public void mapRotate(int delay)
|
|
{
|
|
Utilities.Wait(delay);
|
|
RCON.addRCON("map_rotate", 0);
|
|
}
|
|
|
|
public void tempBan(String Message, Player Target)
|
|
{
|
|
RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "\"", 0);
|
|
}
|
|
|
|
public void mapRotate()
|
|
{
|
|
RCON.addRCON("map_rotate", 0);
|
|
}
|
|
|
|
public void Map(String map)
|
|
{
|
|
RCON.addRCON("map " + map, 0);
|
|
}
|
|
//END
|
|
|
|
//THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/
|
|
public String getPassword()
|
|
{
|
|
return rcon_pass;
|
|
}
|
|
|
|
private void initMaps()
|
|
{
|
|
file mapfile = new file("config\\maps.cfg");
|
|
String[] _maps = mapfile.readAll();
|
|
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);
|
|
}
|
|
|
|
private void initMessages()
|
|
{
|
|
file messageCFG = new file("config\\messages.cfg");
|
|
String[] lines = messageCFG.readAll();
|
|
|
|
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);
|
|
}
|
|
if (Program.Version != Program.latestVersion && Program.latestVersion != 0)
|
|
messages.Add("^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + Program.latestVersion);
|
|
}
|
|
|
|
private void initRules()
|
|
{
|
|
file ruleFile = new file("config\\rules.cfg");
|
|
String[] _rules = ruleFile.readAll();
|
|
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);
|
|
}
|
|
|
|
private void initCommands()
|
|
{
|
|
// Something like *COMMAND* | NAME | HELP MSG | ALIAS | NEEDED PERMISSION | # OF REQUIRED ARGS | HAS TARGET |
|
|
|
|
commands = new List<Command>();
|
|
|
|
if(owner == null)
|
|
commands.Add(new Owner("owner", "claim ownership of the server", "owner", Player.Permission.User, 0, false));
|
|
|
|
commands.Add(new Kick("kick", "kick a player by name. syntax: !kick <player> <reason>.", "k", Player.Permission.Moderator, 2, true));
|
|
commands.Add(new Say("say", "broadcast message to all players. syntax: !say <message>.", "s", Player.Permission.Moderator, 1, false));
|
|
commands.Add(new TempBan("tempban", "temporarily ban a player for 1 hour. syntax: !tempban <player> <reason>.", "tb", Player.Permission.Moderator, 2, true));
|
|
commands.Add(new SBan("ban", "permanently ban a player from the server. syntax: !ban <player> <reason>", "b", Player.Permission.SeniorAdmin, 2, true));
|
|
commands.Add(new WhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false));
|
|
commands.Add(new List("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false));
|
|
commands.Add(new Help("help", "list all available commands. syntax: !help.", "h", Player.Permission.User, 0, false));
|
|
commands.Add(new FastRestart("fastrestart", "fast restart current map. syntax: !fastrestart.", "fr", Player.Permission.Moderator, 0, false));
|
|
commands.Add(new MapRotate("maprotate", "cycle to the next map in rotation. syntax: !maprotate.", "mr", Player.Permission.Administrator, 0, false));
|
|
commands.Add(new SetLevel("setlevel", "set player to specified administration level. syntax: !setlevel <player> <level>.", "sl", Player.Permission.Owner, 2, true));
|
|
commands.Add(new Usage("usage", "get current application memory usage. syntax: !usage.", "us", Player.Permission.Moderator, 0, false));
|
|
commands.Add(new Uptime("uptime", "get current application running time. syntax: !uptime.", "up", Player.Permission.Moderator, 0, false));
|
|
commands.Add(new Warn("warn", "warn player for infringing rules syntax: !warn <player> <reason>.", "w", Player.Permission.Moderator, 2, true));
|
|
commands.Add(new WarnClear("warnclear", "remove all warning for a player syntax: !warnclear <player>.", "wc", Player.Permission.Administrator, 1, true));
|
|
commands.Add(new Unban("unban", "unban player by guid. syntax: !unban <guid>.", "ub", Player.Permission.Administrator, 1, true));
|
|
commands.Add(new Admins("admins", "list currently connected admins. syntax: !admins.", "a", Player.Permission.User, 0, false));
|
|
commands.Add(new Wisdom("wisdom", "get a random wisdom quote. syntax: !wisdom", "w", Player.Permission.Administrator, 0, false));
|
|
commands.Add(new MapCMD("map", "change to specified map. syntax: !map", "m", Player.Permission.Administrator, 1, false));
|
|
commands.Add(new Find("find", "find player in database. syntax: !find <player>", "f", Player.Permission.Administrator, 1, false));
|
|
commands.Add(new Rules("rules", "list server rules. syntax: !rules", "r", Player.Permission.User, 0, false));
|
|
commands.Add(new PrivateMessage("privatemessage", "send message to other player. syntax: !pm <player> <message>", "pm", Player.Permission.User, 2, true));
|
|
commands.Add(new _Stats("stats", "view your stats or another player's. syntax: !stats", "xlrstats", Player.Permission.User, 0, true));
|
|
/*
|
|
commands.Add(new commands { command = "stats", desc = "view your server stats.", requiredPer = 0 });
|
|
commands.Add(new commands { command = "speed", desc = "change player speed. syntax: !speed <number>", requiredPer = 3 });
|
|
commands.Add(new commands { command = "gravity", desc = "change game gravity. syntax: !gravity <number>", requiredPer = 3 });
|
|
|
|
commands.Add(new commands { command = "version", desc = "view current app version.", requiredPer = 0 });*/
|
|
}
|
|
|
|
//Objects
|
|
public Log Log;
|
|
public RCON RCON;
|
|
public Database DB;
|
|
public List<Ban> Bans;
|
|
public Player owner;
|
|
public List<Map> maps;
|
|
public List<String> rules;
|
|
public Queue<Event> events;
|
|
public Database stats;
|
|
public Heartbeat HB;
|
|
|
|
//Info
|
|
private String IP;
|
|
private int Port;
|
|
private String hostname;
|
|
private String mapname;
|
|
private int clientnum;
|
|
private string rcon_pass;
|
|
private List<Player> players;
|
|
private List<Command> commands;
|
|
private List<String> messages;
|
|
private int messageTime;
|
|
private TimeSpan lastMessage;
|
|
private int nextMessage;
|
|
private int errors = 0;
|
|
private Connection Heartbeat;
|
|
|
|
//Log stuff
|
|
private String Basepath;
|
|
private String Mod;
|
|
private String logPath;
|
|
private file logFile;
|
|
}
|
|
}
|