2015-03-08 17:20:10 -04:00
using System ;
using System.Collections.Generic ;
2015-03-13 19:40:16 -04:00
using System.Collections ;
2015-03-08 17:20:10 -04:00
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 ) ;
2015-03-09 00:28:57 -04:00
logFile = new file ( "admin_" + port + ".log" , true ) ;
2015-03-13 19:40:16 -04:00
#if DEBUG
2015-03-23 23:01:05 -04:00
Log = new Log ( logFile , Log . Level . Debug , port ) ;
2015-03-13 19:40:16 -04:00
#else
2015-03-23 23:01:05 -04:00
Log = new Log ( logFile , Log . Level . Production , port ) ;
2015-03-13 19:40:16 -04:00
#endif
2015-03-08 17:20:10 -04:00
players = new List < Player > ( new Player [ 18 ] ) ;
2015-03-13 19:40:16 -04:00
clientDB = new ClientsDB ( "clients.rm" ) ;
statDB = new StatsDB ( "stats_" + port + ".rm" ) ;
aliasDB = new AliasesDB ( "aliases.rm" ) ;
Bans = clientDB . getBans ( ) ;
owner = clientDB . getOwner ( ) ;
2015-03-08 17:20:10 -04:00
events = new Queue < Event > ( ) ;
2015-03-10 16:45:20 -04:00
HB = new Heartbeat ( this ) ;
2015-03-13 19:40:16 -04:00
Macros = new Dictionary < String , Object > ( ) ;
2015-03-23 23:01:05 -04:00
Reports = new List < Report > ( ) ;
2015-04-10 00:02:12 -04:00
Skills = new Moserware . TrueSkill ( ) ;
statusPlayers = new Dictionary < string , Player > ( ) ;
2015-04-19 14:14:30 -04:00
chatHistory = new List < Chat > ( ) ;
lastWebChat = DateTime . Now ;
2015-03-08 17:20:10 -04:00
nextMessage = 0 ;
initCommands ( ) ;
2015-03-13 19:40:16 -04:00
initMacros ( ) ;
2015-03-08 17:20:10 -04:00
initMessages ( ) ;
initMaps ( ) ;
initRules ( ) ;
}
//Returns the current server name -- *STRING*
public String getName ( )
{
return hostname ;
}
2015-03-10 16:45:20 -04:00
public String getMap ( )
{
return mapname ;
}
2015-04-10 00:02:12 -04:00
public String getGametype ( )
{
return Gametype ;
}
2015-03-08 17:20:10 -04:00
//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 ;
}
2015-03-09 00:28:57 -04:00
//Returns list of all current players
2015-03-08 17:20:10 -04:00
public List < Player > getPlayers ( )
{
return players ;
}
2015-03-10 16:45:20 -04:00
public int getClientNum ( )
{
return clientnum ;
}
2015-03-11 21:25:14 -04:00
public int getMaxClients ( )
{
return maxClients ;
}
2015-03-09 00:28:57 -04:00
//Returns list of all active bans (loaded at runtime)
2015-03-08 17:20:10 -04:00
public List < Ban > getBans ( )
{
return Bans ;
}
2015-03-14 12:42:36 -04:00
2015-04-10 00:02:12 -04:00
public void getAliases ( List < Player > returnPlayers , Player Origin )
{
if ( Origin = = null )
return ;
List < Aliases > aliasAliases = new List < Aliases > ( ) ;
Aliases currentAliases = aliasDB . getPlayer ( Origin . getDBID ( ) ) ;
if ( currentAliases = = null )
2015-04-13 00:25:34 -04:00
{
2015-04-10 00:02:12 -04:00
Log . Write ( "No aliases found for " + Origin . getName ( ) , Log . Level . Debug ) ;
2015-04-13 00:25:34 -04:00
return ;
}
2015-04-10 00:02:12 -04:00
foreach ( String IP in currentAliases . getIPS ( ) )
{
List < Aliases > tmp = aliasDB . getPlayer ( IP ) ;
if ( tmp ! = null )
aliasAliases = tmp ;
foreach ( Aliases a in aliasAliases )
{
if ( a = = null )
continue ;
Player aliasPlayer = clientDB . getPlayer ( a . getNumber ( ) ) ;
if ( aliasPlayer ! = null )
{
aliasPlayer . Alias = a ;
if ( returnPlayers . Exists ( p = > p . getDBID ( ) = = aliasPlayer . getDBID ( ) ) = = false )
{
returnPlayers . Add ( aliasPlayer ) ;
getAliases ( returnPlayers , aliasPlayer ) ;
}
}
}
}
}
2015-04-19 14:14:30 -04:00
bool checkClientStatus ( Player P )
{
/ * RCON . addRCON ( "admin_lastevent status;" + P . getID ( ) + ";0;clean" ) ;
Utilities . Wait ( 0.5 ) ; // give it time to update
String [ ] Status = RCON . addRCON ( "whoisdirty" ) ;
if ( Status ! = null )
{
String GUID = Utilities . stripColors ( Status [ 1 ] . Split ( new char [ ] { '\"' } ) [ 3 ] ) ;
}
* /
return true ;
}
2015-04-10 00:02:12 -04:00
2015-03-08 17:20:10 -04:00
//Add player object p to `players` list
public bool addPlayer ( Player P )
{
2015-04-10 00:02:12 -04:00
if ( P . getClientNum ( ) < 0 | | P . getClientNum ( ) > ( players . Count - 1 ) ) // invalid index
return false ;
if ( players [ P . getClientNum ( ) ] ! = null & & players [ P . getClientNum ( ) ] . getID ( ) = = P . getID ( ) ) // if someone has left and a new person has taken their spot between polls
return true ;
Log . Write ( "Client slot #" + P . getClientNum ( ) + " now reserved" , Log . Level . Debug ) ;
2015-03-14 12:42:36 -04:00
#if DEBUG = = false
2015-03-08 17:20:10 -04:00
try
2015-03-14 12:42:36 -04:00
#endif
2015-03-08 17:20:10 -04:00
{
2015-04-10 00:02:12 -04:00
Player NewPlayer = clientDB . getPlayer ( P . getID ( ) , P . getClientNum ( ) ) ;
if ( NewPlayer = = null ) // first time connecting
2015-03-08 17:20:10 -04:00
{
2015-04-10 00:02:12 -04:00
Log . Write ( "Client slot #" + P . getClientNum ( ) + " first time connecting" , Log . Level . All ) ;
2015-03-13 19:40:16 -04:00
clientDB . addPlayer ( P ) ;
2015-04-10 00:02:12 -04:00
NewPlayer = clientDB . getPlayer ( P . getID ( ) , P . getClientNum ( ) ) ;
aliasDB . addPlayer ( new Aliases ( NewPlayer . getDBID ( ) , NewPlayer . getName ( ) , NewPlayer . getIP ( ) ) ) ;
statDB . addPlayer ( NewPlayer ) ;
2015-03-08 17:20:10 -04:00
}
2015-04-10 00:02:12 -04:00
NewPlayer . updateName ( P . getName ( ) . Trim ( ) ) ;
2015-03-13 19:40:16 -04:00
NewPlayer . stats = statDB . getStats ( NewPlayer . getDBID ( ) ) ;
2015-04-10 00:02:12 -04:00
NewPlayer . Alias = aliasDB . getPlayer ( NewPlayer . getDBID ( ) ) ;
2015-03-14 12:42:36 -04:00
2015-04-10 00:02:12 -04:00
if ( NewPlayer . Alias = = null )
2015-03-09 21:28:37 -04:00
{
2015-04-10 00:02:12 -04:00
aliasDB . addPlayer ( new Aliases ( NewPlayer . getDBID ( ) , NewPlayer . getName ( ) , NewPlayer . getIP ( ) ) ) ;
NewPlayer . Alias = aliasDB . getPlayer ( NewPlayer . getDBID ( ) ) ;
2015-03-09 21:28:37 -04:00
}
2015-04-10 00:02:12 -04:00
// try not to crash if no stats!
2015-03-10 17:56:01 -04:00
2015-04-10 00:02:12 -04:00
if ( P . lastEvent = = null | | P . lastEvent . Owner = = null )
2015-03-14 12:42:36 -04:00
NewPlayer . lastEvent = new Event ( Event . GType . Say , null , NewPlayer , null , this ) ; // this is messy but its throwing an error when they've started it too late
else
NewPlayer . lastEvent = P . lastEvent ;
2015-03-08 17:20:10 -04:00
2015-04-10 00:02:12 -04:00
// lets check aliases
if ( ( NewPlayer . Alias . getNames ( ) . Find ( m = > m . Equals ( P . getName ( ) ) ) ) = = null | | NewPlayer . getName ( ) = = null | | NewPlayer . getName ( ) = = String . Empty )
2015-03-08 17:20:10 -04:00
{
2015-04-10 00:02:12 -04:00
NewPlayer . updateName ( P . getName ( ) . Trim ( ) ) ;
NewPlayer . Alias . addName ( NewPlayer . getName ( ) ) ;
}
// and ips
if ( NewPlayer . Alias . getIPS ( ) . Find ( i = > i . Equals ( P . getIP ( ) ) ) = = null | | P . getIP ( ) = = null | | P . getIP ( ) = = String . Empty )
{
NewPlayer . Alias . addIP ( P . getIP ( ) ) ;
}
2015-03-16 16:40:30 -04:00
2015-04-19 14:14:30 -04:00
NewPlayer . updateIP ( P . getIP ( ) ) ;
2015-04-10 00:02:12 -04:00
aliasDB . updatePlayer ( NewPlayer . Alias ) ;
clientDB . updatePlayer ( NewPlayer ) ;
2015-03-16 16:40:30 -04:00
2015-04-11 13:31:04 -04:00
if ( NewPlayer . getLevel ( ) = = Player . Permission . Banned ) // their guid is already banned so no need to check aliases
2015-04-10 00:02:12 -04:00
{
2015-04-11 13:31:04 -04:00
String Message ;
2015-03-16 16:40:30 -04:00
2015-04-11 13:31:04 -04:00
Log . Write ( "Banned client " + P . getName ( ) + " trying to connect..." , Log . Level . Debug ) ;
2015-03-30 01:04:10 -04:00
2015-04-11 13:31:04 -04:00
if ( NewPlayer . getLastO ( ) ! = null )
Message = "^7Player Kicked: Previously banned for ^5" + NewPlayer . getLastO ( ) + " ^7(appeal at " + Website + ")" ;
else
Message = "Player Kicked: Previous Ban" ;
2015-03-16 16:40:30 -04:00
2015-04-11 13:31:04 -04:00
NewPlayer . Kick ( Message ) ;
if ( players [ NewPlayer . getClientNum ( ) ] ! = null )
2015-03-16 16:40:30 -04:00
{
2015-04-11 13:31:04 -04:00
lock ( players )
{
players [ NewPlayer . getClientNum ( ) ] = null ;
}
}
2015-03-23 23:01:05 -04:00
2015-04-11 13:31:04 -04:00
return true ;
}
2015-03-16 16:40:30 -04:00
2015-04-11 13:31:04 -04:00
List < Player > newPlayerAliases = new List < Player > ( ) ;
getAliases ( newPlayerAliases , NewPlayer ) ;
2015-03-23 23:01:05 -04:00
2015-04-11 13:31:04 -04:00
foreach ( Player aP in newPlayerAliases ) // lets check their aliases
{
if ( aP = = null )
continue ;
2015-04-10 00:02:12 -04:00
2015-04-11 13:31:04 -04:00
if ( aP . getLevel ( ) = = Player . Permission . Flagged )
NewPlayer . setLevel ( Player . Permission . Flagged ) ;
2015-04-10 00:02:12 -04:00
Ban B = isBanned ( aP ) ;
2015-04-11 13:31:04 -04:00
if ( B ! = null )
2015-04-10 00:02:12 -04:00
{
2015-04-11 13:31:04 -04:00
Log . Write ( String . Format ( "Banned client {0} is connecting with new alias {1}" , aP . getName ( ) , NewPlayer . getName ( ) ) , Log . Level . Debug ) ;
NewPlayer . LastOffense = String . Format ( "Evading ( {0} )" , aP . getName ( ) ) ;
2015-04-10 00:02:12 -04:00
if ( B . getReason ( ) ! = null )
NewPlayer . Ban ( "^7Previously Banned: ^5" + B . getReason ( ) + " ^7(appeal at " + Website + ")" , NewPlayer ) ;
else
NewPlayer . Ban ( "^7Previous Ban" , NewPlayer ) ;
2015-03-23 23:01:05 -04:00
2015-04-10 00:02:12 -04:00
lock ( players )
{
if ( players [ NewPlayer . getClientNum ( ) ] ! = null )
players [ NewPlayer . getClientNum ( ) ] = null ;
}
2015-03-23 23:01:05 -04:00
return true ;
2015-03-16 16:40:30 -04:00
}
2015-04-10 00:02:12 -04:00
}
2015-03-16 16:40:30 -04:00
2015-04-19 14:14:30 -04:00
//finally lets check their clean status :>
checkClientStatus ( NewPlayer ) ;
2015-04-10 00:02:12 -04:00
lock ( players )
{
players [ NewPlayer . getClientNum ( ) ] = null ; // just in case we have shit in the way
2015-03-16 16:40:30 -04:00
players [ NewPlayer . getClientNum ( ) ] = NewPlayer ;
2015-04-10 00:02:12 -04:00
}
2015-03-23 23:01:05 -04:00
#if DEBUG = = FALSE
2015-03-14 12:42:36 -04:00
NewPlayer . Tell ( "Welcome ^5" + NewPlayer . getName ( ) + " ^7this is your ^5" + Utilities . timesConnected ( NewPlayer . getConnections ( ) ) + " ^7time connecting!" ) ;
2015-03-23 23:01:05 -04:00
#endif
2015-04-11 13:31:04 -04:00
Log . Write ( "Client " + NewPlayer . getName ( ) + " connecting..." , Log . Level . Debug ) ; // they're clean
2015-03-23 23:01:05 -04:00
2015-04-19 14:14:30 -04:00
if ( chatHistory . Count > Math . Ceiling ( ( double ) clientnum / 2 ) )
chatHistory . RemoveAt ( 0 ) ;
chatHistory . Add ( new Chat ( NewPlayer , "<i>CONNECTED</i>" , DateTime . Now ) ) ;
2015-04-10 00:02:12 -04:00
if ( NewPlayer . getLevel ( ) = = Player . Permission . Flagged )
ToAdmins ( "^1NOTICE: ^7Flagged player ^5" + NewPlayer . getName ( ) + "^7 has joined!" ) ;
if ( NewPlayer . getLevel ( ) > Player . Permission . Moderator )
NewPlayer . Tell ( "There are ^5" + Reports . Count + " ^7recent reports!" ) ;
2015-03-08 17:20:10 -04:00
2015-03-30 01:04:10 -04:00
if ( NewPlayer . stats = = null ) // there seems to be an issue with stats with multiple servers. I think this should fix it
{
statDB . addPlayer ( NewPlayer ) ;
NewPlayer . stats = statDB . getStats ( NewPlayer . getDBID ( ) ) ;
}
2015-03-08 17:20:10 -04:00
return true ;
}
2015-03-14 12:42:36 -04:00
#if DEBUG = = false
2015-03-08 17:20:10 -04:00
catch ( Exception E )
{
2015-03-09 16:11:09 -04:00
Log . Write ( "Unable to add player " + P . getName ( ) + " - " + E . Message , Log . Level . Debug ) ;
2015-03-08 17:20:10 -04:00
return false ;
}
2015-03-14 12:42:36 -04:00
#endif
2015-03-08 17:20:10 -04:00
}
//Remove player by CLIENT NUMBER
public bool removePlayer ( int cNum )
{
2015-04-10 00:02:12 -04:00
if ( cNum > = 0 & & cNum < players . Count )
2015-03-16 16:40:30 -04:00
{
2015-04-13 00:25:34 -04:00
if ( players [ cNum ] = = null )
{
Log . Write ( "Error - Disconnecting client slot is already empty!" , Log . Level . Debug ) ;
return false ;
}
2015-04-10 00:02:12 -04:00
Player Leaving = players [ cNum ] ;
Leaving . Connections + + ;
clientDB . updatePlayer ( Leaving ) ;
statDB . updatePlayer ( Leaving ) ;
2015-03-16 16:40:30 -04:00
Log . Write ( "Client at " + cNum + " disconnecting..." , Log . Level . Debug ) ;
2015-04-10 00:02:12 -04:00
lock ( players )
{
players [ cNum ] = null ;
}
clientnum = statusPlayers . Count ;
2015-03-16 16:40:30 -04:00
return true ;
}
else
{
2015-04-13 00:25:34 -04:00
Log . Write ( "Error - Client disconnecting has an invalid client index!" , Log . Level . Debug ) ;
2015-04-10 00:02:12 -04:00
clientnum = statusPlayers . Count ;
2015-03-16 16:40:30 -04:00
return false ;
}
2015-03-08 17:20:10 -04:00
}
2015-03-16 16:40:30 -04:00
//Another version of client from line, written for the line created by a kill or death event
2015-04-10 00:02:12 -04:00
public Player clientFromEventLine ( String [ ] L , int cIDPos )
2015-03-16 16:40:30 -04:00
{
2015-04-10 00:02:12 -04:00
if ( L . Length < cIDPos )
2015-03-16 16:40:30 -04:00
{
Log . Write ( "Line sent for client creation is not long enough!" , Log . Level . Debug ) ;
return null ;
}
2015-03-30 01:04:10 -04:00
int pID = - 2 ; // apparently falling = -1 cID so i can't use it now
2015-04-10 00:02:12 -04:00
int . TryParse ( L [ cIDPos ] . Trim ( ) , out pID ) ;
2015-03-16 16:40:30 -04:00
2015-03-30 01:04:10 -04:00
if ( pID = = - 1 ) // special case similar to mod_suicide
int . TryParse ( L [ 2 ] , out pID ) ;
2015-04-10 00:02:12 -04:00
if ( pID < 0 | | pID > 17 )
{
Log . Write ( "Error event player index " + pID + " is out of bounds!" , Log . Level . Debug ) ;
2015-03-30 01:04:10 -04:00
Log . Write ( "Offending line -- " + String . Join ( ";" , L ) , Log . Level . Debug ) ;
2015-04-10 00:02:12 -04:00
return null ;
2015-03-16 16:40:30 -04:00
}
else
{
2015-04-10 00:02:12 -04:00
Player P = null ;
try
{
P = players [ pID ] ;
return P ;
}
catch ( Exception )
{
Log . Write ( "Client index is invalid - " + pID , Log . Level . Debug ) ;
Log . Write ( L . ToString ( ) , Log . Level . Debug ) ;
return null ;
}
}
}
public Player clientFromName ( String pName )
{
lock ( players )
{
foreach ( var P in players )
2015-03-16 16:40:30 -04:00
{
2015-04-10 00:02:12 -04:00
if ( P ! = null & & P . getName ( ) . ToLower ( ) . Contains ( pName . ToLower ( ) ) )
2015-03-16 16:40:30 -04:00
return P ;
}
}
2015-04-10 00:02:12 -04:00
return null ;
2015-03-16 16:40:30 -04:00
}
//Check ban list for every banned player and return ban if match is found
2015-03-08 17:20:10 -04:00
public Ban isBanned ( Player C )
{
2015-04-11 13:31:04 -04:00
if ( C . getLevel ( ) = = Player . Permission . Banned )
return Bans . Find ( p = > p . getID ( ) . Equals ( C . getID ( ) ) ) ;
2015-03-08 17:20:10 -04:00
foreach ( Ban B in Bans )
{
2015-03-23 23:01:05 -04:00
if ( B . getID ( ) . Length < 5 | | B . getIP ( ) . Length < 5 )
continue ;
if ( B . getID ( ) = = null | | C . getID ( ) = = null )
continue ;
2015-03-08 17:20:10 -04:00
if ( B . getID ( ) = = C . getID ( ) )
return B ;
2015-03-13 19:40:16 -04:00
2015-03-23 23:01:05 -04:00
if ( B . getIP ( ) = = null | | C . getIP ( ) = = null )
2015-03-13 19:40:16 -04:00
continue ;
if ( C . getIP ( ) = = B . getIP ( ) )
return B ;
2015-03-08 17:20:10 -04:00
}
return null ;
}
2015-03-16 16:40:30 -04:00
//Procses requested command correlating to an event
2015-03-08 17:20:10 -04:00
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 ) ;
2015-03-23 23:01:05 -04:00
if ( C . getName ( ) = = "stats" & & Args . Length = = 1 )
E . Target = E . Origin ;
2015-03-09 21:28:37 -04:00
if ( Args [ 0 ] = = String . Empty )
return C ;
2015-03-23 23:01:05 -04:00
2015-03-16 16:40:30 -04:00
if ( Args [ 0 ] [ 0 ] = = '@' ) // user specifying target by database ID
2015-03-08 17:20:10 -04:00
{
int dbID = - 1 ;
int . TryParse ( Args [ 0 ] . Substring ( 1 , Args [ 0 ] . Length - 1 ) , out dbID ) ;
2015-03-13 19:40:16 -04:00
Player found = E . Owner . clientDB . getPlayer ( dbID ) ;
2015-03-08 17:20:10 -04:00
if ( found ! = null )
2015-03-16 16:40:30 -04:00
{
2015-03-08 17:20:10 -04:00
E . Target = found ;
2015-03-16 16:40:30 -04:00
E . Target . lastEvent = E ;
E . Owner = this ;
}
2015-03-08 17:20:10 -04:00
}
2015-03-16 16:40:30 -04:00
else if ( Args [ 0 ] . Length < 3 & & cNum > - 1 & & cNum < 18 ) // user specifying target by client num
2015-03-08 17:20:10 -04:00
{
if ( players [ cNum ] ! = null )
E . Target = players [ cNum ] ;
}
else
2015-04-10 00:02:12 -04:00
E . Target = clientFromName ( Args [ 0 ] ) ;
2015-03-08 17:20:10 -04:00
if ( E . Target = = null )
{
E . Origin . Tell ( "Unable to find specified player." ) ;
return null ;
}
}
return C ;
}
2015-03-16 16:40:30 -04:00
//push a new event into the queue
2015-03-08 17:20:10 -04:00
private void addEvent ( Event E )
{
events . Enqueue ( E ) ;
}
2015-03-16 16:40:30 -04:00
2015-03-08 17:20:10 -04:00
2015-03-16 16:40:30 -04:00
//process new event every 100 milliseconds
2015-03-08 17:20:10 -04:00
private void manageEventQueue ( )
{
2015-03-14 12:42:36 -04:00
while ( isRunning )
2015-03-08 17:20:10 -04:00
{
if ( events . Count > 0 )
{
processEvent ( events . Peek ( ) ) ;
events . Dequeue ( ) ;
}
Utilities . Wait ( 0.1 ) ;
}
}
//Starts the monitoring process
public void Monitor ( )
{
2015-03-14 12:42:36 -04:00
isRunning = true ;
2015-03-13 19:40:16 -04:00
//Handles new rcon requests in a fashionable manner
Thread RCONQueue = new Thread ( new ThreadStart ( RCON . ManageRCONQueue ) ) ;
RCONQueue . Start ( ) ;
2015-03-08 17:20:10 -04:00
if ( ! intializeBasics ( ) )
{
2015-03-13 19:40:16 -04:00
Log . Write ( "Stopping " + Port + " due to uncorrectable errors (check log)" + logPath , Log . Level . Production ) ;
2015-03-14 12:42:36 -04:00
isRunning = false ;
Utilities . Wait ( 10 ) ;
2015-03-09 16:11:09 -04:00
return ;
2015-03-08 17:20:10 -04:00
}
2015-03-16 16:40:30 -04:00
//Thread to handle polling server for IP's
2015-03-14 12:42:36 -04:00
Thread statusUpdate = new Thread ( new ThreadStart ( pollServer ) ) ;
statusUpdate . Start ( ) ;
2015-03-08 17:20:10 -04:00
//Handles new events in a fashionable manner
Thread eventQueue = new Thread ( new ThreadStart ( manageEventQueue ) ) ;
eventQueue . Start ( ) ;
2015-03-13 19:40:16 -04:00
int timesFailed = 0 ;
2015-03-08 17:20:10 -04:00
long l_size = - 1 ;
2015-03-14 12:42:36 -04:00
bool checkedForOutdate = false ;
2015-03-08 17:20:10 -04:00
String [ ] lines = new String [ 8 ] ;
String [ ] oldLines = new String [ 8 ] ;
DateTime start = DateTime . Now ;
2015-03-10 17:56:01 -04:00
Utilities . Wait ( 1 ) ;
2015-03-14 12:42:36 -04:00
#if DEBUG = = false
2015-03-10 17:56:01 -04:00
Broadcast ( "IW4M Admin is now ^2ONLINE" ) ;
2015-03-14 12:42:36 -04:00
#endif
2015-03-08 17:20:10 -04:00
2015-03-23 23:01:05 -04:00
while ( isRunning )
2015-03-08 17:20:10 -04:00
{
2015-03-14 12:42:36 -04:00
#if DEBUG = = false
try
#endif
2015-03-08 17:20:10 -04:00
{
lastMessage = DateTime . Now - start ;
if ( lastMessage . TotalSeconds > messageTime & & messages . Count > 0 )
{
2015-03-14 12:42:36 -04:00
initMacros ( ) ; // somethings dynamically change so we have to re-init the dictionary
2015-03-13 19:40:16 -04:00
Broadcast ( Utilities . processMacro ( Macros , messages [ nextMessage ] ) ) ;
2015-03-08 17:20:10 -04:00
if ( nextMessage = = ( messages . Count - 1 ) )
nextMessage = 0 ;
else
nextMessage + + ;
start = DateTime . Now ;
2015-03-13 19:40:16 -04:00
if ( timesFailed < = 3 )
HB . Send ( ) ;
2015-03-14 12:42:36 -04:00
String checkVer = new Connection ( "http://raidmax.org/IW4M/Admin/version.php" ) . Read ( ) ;
double checkVerNum ;
double . TryParse ( checkVer , out checkVerNum ) ;
if ( checkVerNum ! = Program . Version & & checkVerNum ! = 0 & & ! checkedForOutdate )
{
messages . Add ( "^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + checkVerNum ) ;
checkedForOutdate = true ;
}
2015-03-08 17:20:10 -04:00
}
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 ;
2015-04-10 00:02:12 -04:00
if ( lines [ count ] . Length < 10 ) // its not a needed line
2015-03-08 17:20:10 -04:00
continue ;
else
{
string [ ] game_event = lines [ count ] . Split ( ';' ) ;
Event event_ = Event . requestEvent ( game_event , this ) ;
if ( event_ ! = null )
{
if ( event_ . Origin = = null )
2015-04-11 13:31:04 -04:00
continue ;
2015-03-08 17:20:10 -04:00
event_ . Origin . lastEvent = event_ ;
event_ . Origin . lastEvent . Owner = this ;
addEvent ( event_ ) ;
}
}
}
}
}
oldLines = lines ;
l_size = logFile . getSize ( ) ;
Thread . Sleep ( 1 ) ;
}
2015-03-14 12:42:36 -04:00
#if DEBUG = = false
2015-03-08 17:20:10 -04:00
catch ( Exception E )
{
Log . Write ( "Something unexpected occured. Hopefully we can ignore it - " + E . Message + " @" + Utilities . GetLineNumber ( E ) , Log . Level . All ) ;
continue ;
}
2015-03-14 12:42:36 -04:00
#endif
2015-03-08 17:20:10 -04:00
}
2015-03-14 12:42:36 -04:00
isRunning = false ;
2015-03-08 17:20:10 -04:00
RCONQueue . Abort ( ) ;
eventQueue . Abort ( ) ;
}
2015-03-14 12:42:36 -04:00
private void pollServer ( )
{
2015-03-16 16:40:30 -04:00
int timesFailed = 0 ;
2015-04-19 14:14:30 -04:00
Dictionary < String , Player > toCheck = new Dictionary < String , Player > ( ) ;
2015-03-14 12:42:36 -04:00
while ( isRunning )
{
2015-04-19 14:14:30 -04:00
String [ ] Response = RCON . addRCON ( "status" ) ;
if ( Response ! = null )
toCheck = Utilities . playersFromStatus ( Response ) ;
if ( toCheck ! = null )
2015-04-10 00:02:12 -04:00
{
lastPoll = DateTime . Now ;
timesFailed = 0 ;
2015-04-19 14:14:30 -04:00
if ( toCheck ! = statusPlayers )
2015-03-16 16:40:30 -04:00
{
2015-04-19 14:14:30 -04:00
List < Player > toRemove = new List < Player > ( ) ;
lock ( players )
2015-04-10 00:02:12 -04:00
{
2015-04-19 14:14:30 -04:00
foreach ( Player P in players )
2015-04-11 13:31:04 -04:00
{
2015-04-19 14:14:30 -04:00
if ( P = = null )
continue ;
2015-04-11 13:31:04 -04:00
2015-04-19 14:14:30 -04:00
Player Matching ;
toCheck . TryGetValue ( P . getID ( ) , out Matching ) ;
if ( Matching = = null ) // they are no longer with us
toRemove . Add ( P ) ;
2015-04-11 13:31:04 -04:00
}
2015-04-19 14:14:30 -04:00
foreach ( Player Removing in toRemove ) // cuz cant modify collections
removePlayer ( Removing . getClientNum ( ) ) ;
}
2015-04-10 00:02:12 -04:00
2015-04-19 14:14:30 -04:00
foreach ( var P in toCheck . Values )
{
if ( P = = null )
{
Log . Write ( "Null player found in toCheck" , Log . Level . Debug ) ;
continue ;
2015-04-10 00:02:12 -04:00
}
2015-04-19 14:14:30 -04:00
if ( ! addPlayer ( P ) )
Log . Write ( "Error adding " + P . getName ( ) + " at client slot #" + P . getClientNum ( ) , Log . Level . Debug ) ;
}
lock ( statusPlayers )
{
statusPlayers = toCheck ;
2015-04-10 00:02:12 -04:00
}
2015-03-16 16:40:30 -04:00
}
2015-04-10 00:02:12 -04:00
clientnum = statusPlayers . Count ;
2015-03-23 23:01:05 -04:00
}
2015-03-16 16:40:30 -04:00
2015-04-10 00:02:12 -04:00
else
2015-03-23 23:01:05 -04:00
{
2015-04-10 00:02:12 -04:00
timesFailed + + ;
Log . Write ( "Server appears to be offline - " + timesFailed , Log . Level . Debug ) ;
2015-03-16 16:40:30 -04:00
2015-04-10 00:02:12 -04:00
if ( timesFailed > = 4 )
2015-03-23 23:01:05 -04:00
{
2015-04-10 00:02:12 -04:00
Log . Write ( "Max offline attempts reached. Reinitializing RCON connection." , Log . Level . Debug ) ;
RCON . Reset ( ) ;
2015-03-23 23:01:05 -04:00
}
2015-03-14 12:42:36 -04:00
}
2015-04-10 00:02:12 -04:00
Utilities . Wait ( 15 ) ;
2015-03-14 12:42:36 -04:00
}
}
2015-03-09 00:28:57 -04:00
//Vital RCON commands to establish log file and server name. May need to cleanup in the future
2015-03-08 17:20:10 -04:00
private bool intializeBasics ( )
{
2015-03-13 19:40:16 -04:00
try
2015-03-08 17:20:10 -04:00
{
2015-03-13 19:40:16 -04:00
String [ ] infoResponse = RCON . addRCON ( "getstatus" ) ;
2015-03-11 21:25:14 -04:00
if ( infoResponse = = null | | infoResponse . Length < 2 )
2015-03-10 16:45:20 -04:00
{
2015-03-11 21:25:14 -04:00
Log . Write ( "Could not get server status!" , Log . Level . All ) ;
2015-04-11 13:31:04 -04:00
hostname = "Offline" ; // for the web front
2015-03-10 16:45:20 -04:00
return false ;
}
2015-03-11 21:25:14 -04:00
infoResponse = infoResponse [ 1 ] . Split ( '\\' ) ;
2015-03-13 19:40:16 -04:00
Dictionary < String , String > infoResponseDict = new Dictionary < string , string > ( ) ;
2015-03-10 16:45:20 -04:00
2015-03-13 19:40:16 -04:00
for ( int i = 0 ; i < infoResponse . Length ; i + + )
{
if ( i % 2 = = 0 | | infoResponse [ i ] = = String . Empty )
continue ;
infoResponseDict . Add ( infoResponse [ i ] , infoResponse [ i + 1 ] ) ;
}
2015-03-11 00:47:34 -04:00
2015-03-13 19:40:16 -04:00
mapname = infoResponseDict [ "mapname" ] ;
try
2015-03-11 00:47:34 -04:00
{
2015-03-13 19:40:16 -04:00
mapname = maps . Find ( m = > m . Name . Equals ( mapname ) ) . Alias ;
2015-03-11 00:47:34 -04:00
}
2015-03-13 19:40:16 -04:00
catch ( Exception )
{
Log . Write ( mapname + " doesn't appear to be in the maps.cfg" , Log . Level . Debug ) ;
}
2015-03-11 00:47:34 -04:00
2015-03-13 19:40:16 -04:00
hostname = Utilities . stripColors ( infoResponseDict [ "sv_hostname" ] ) ;
IW_Ver = infoResponseDict [ "shortversion" ] ;
maxClients = Convert . ToInt32 ( infoResponseDict [ "sv_maxclients" ] ) ;
Gametype = infoResponseDict [ "g_gametype" ] ;
2015-03-16 16:40:30 -04:00
2015-03-13 19:40:16 -04:00
try
{
2015-04-10 00:02:12 -04:00
Website = infoResponseDict [ "_website" ] ;
2015-03-13 19:40:16 -04:00
}
2015-03-30 01:04:10 -04:00
2015-04-11 13:31:04 -04:00
catch ( Exception )
2015-03-13 19:40:16 -04:00
{
2015-03-30 01:04:10 -04:00
Website = "this server's website" ;
2015-03-13 19:40:16 -04:00
Log . Write ( "Seems not to have website specified" , Log . Level . Debug ) ;
}
2015-03-11 00:47:34 -04:00
2015-03-30 01:04:10 -04:00
String [ ] p = RCON . addRCON ( "fs_basepath" ) ;
2015-03-08 17:20:10 -04:00
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 ;
//END
//get fs_game
2015-03-14 12:42:36 -04:00
p = RCON . addRCON ( "fs_game" ) ;
2015-03-08 17:20:10 -04:00
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 ;
//END
//get g_log
2015-03-13 19:40:16 -04:00
p = RCON . addRCON ( "g_log" ) ;
2015-03-08 17:20:10 -04:00
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 ;
//END
//get g_logsync
2015-03-14 12:42:36 -04:00
p = RCON . addRCON ( "g_logsync" ) ;
2015-03-08 17:20:10 -04:00
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 ;
if ( logsync ! = 1 )
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "g_logsync 1" ) ;
2015-03-08 17:20:10 -04:00
//END
//get iw4m_onelog
2015-04-11 13:31:04 -04:00
p = RCON . addRCON ( "iw4m_onelog" ) ;
2015-03-08 17:20:10 -04:00
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
if ( Mod = = String . Empty | | onelog = = "1" )
logPath = Basepath + '\\' + "m2demo" + '\\' + log ;
else
logPath = Basepath + '\\' + Mod + '\\' + log ;
2015-04-13 00:25:34 -04:00
#if DEBUG
// logPath = "C:\\Users\\Michael\\Desktop\\test.txt";
#endif
2015-03-08 17:20:10 -04:00
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 ) ;
2015-03-14 12:42:36 -04:00
//get players ip's
p = RCON . addRCON ( "status" ) ;
2015-03-13 19:40:16 -04:00
if ( p = = null )
{
Log . Write ( "Unable to get initial player list!" , Log . Level . Debug ) ;
return false ;
}
2015-03-14 12:42:36 -04:00
lastPoll = DateTime . Now ;
2015-03-13 19:40:16 -04:00
#if DEBUG
/ * System . Net . FtpWebRequest tmp = ( System . Net . FtpWebRequest ) System . Net . FtpWebRequest . Create ( "ftp://raidmax.org/logs/games_old.log" ) ;
tmp . Credentials = new System . Net . NetworkCredential ( "*" , "*" ) ;
System . IO . Stream ftpStream = tmp . GetResponse ( ) . GetResponseStream ( ) ;
String ftpLog = new StreamReader ( ftpStream ) . ReadToEnd ( ) ; * /
2015-03-16 16:40:30 -04:00
//logPath = "games_old.log";
2015-03-13 19:40:16 -04:00
#endif
2015-04-13 00:25:34 -04:00
Log . Write ( "Now monitoring " + this . getName ( ) , Log . Level . All ) ;
2015-03-08 17:20:10 -04:00
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 )
{
2015-04-11 13:31:04 -04:00
/ * if ( E . Type = = Event . GType . Connect ) // this is anow handled by rcon status :(
2015-03-08 17:20:10 -04:00
{
2015-03-16 16:40:30 -04:00
if ( E . Origin = = null )
Log . Write ( "Connect event triggered, but no client is detected!" , Log . Level . Debug ) ;
2015-03-10 16:45:20 -04:00
addPlayer ( E . Origin ) ;
2015-03-08 17:20:10 -04:00
return true ;
2015-04-10 00:02:12 -04:00
} * /
2015-03-08 17:20:10 -04:00
2015-04-11 13:31:04 -04:00
if ( E . Type = = Event . GType . Connect )
{
return true ;
}
2015-03-16 16:40:30 -04:00
if ( E . Type = = Event . GType . Disconnect )
2015-03-08 17:20:10 -04:00
{
2015-03-16 16:40:30 -04:00
if ( E . Origin = = null )
2015-03-09 21:28:37 -04:00
{
2015-03-16 16:40:30 -04:00
Log . Write ( "Disconnect event triggered, but no origin found." , Log . Level . Debug ) ;
return false ;
2015-03-09 21:28:37 -04:00
}
2015-03-16 16:40:30 -04:00
2015-04-19 14:14:30 -04:00
if ( chatHistory . Count > Math . Ceiling ( ( ( double ) clientnum - 1 ) / 2 ) )
chatHistory . RemoveAt ( 0 ) ;
chatHistory . Add ( new Chat ( E . Origin , "<i>DISCONNECTED</i>" , DateTime . Now ) ) ;
2015-04-10 00:02:12 -04:00
removePlayer ( E . Origin . getClientNum ( ) ) ;
2015-03-08 17:20:10 -04:00
return true ;
}
2015-03-09 21:28:37 -04:00
if ( E . Type = = Event . GType . Kill )
{
2015-03-16 16:40:30 -04:00
if ( E . Origin = = null )
{
Log . Write ( "Kill event triggered, but no origin found!" , Log . Level . Debug ) ;
return false ;
}
if ( E . Target = = null )
2015-03-09 21:28:37 -04:00
{
2015-03-16 16:40:30 -04:00
Log . Write ( "Kill event triggered, but no target found!" , Log . Level . Debug ) ;
return false ;
}
if ( E . Origin . stats = = null )
{
Log . Write ( "Kill event triggered, but no stats found for origin!" , Log . Level . Debug ) ;
2015-03-30 01:04:10 -04:00
return false ;
2015-03-16 16:40:30 -04:00
}
2015-03-11 21:25:14 -04:00
2015-03-16 16:40:30 -04:00
if ( E . Target . stats = = null )
{
Log . Write ( "Kill event triggered, but no stats found for target!" , Log . Level . Debug ) ;
2015-03-30 01:04:10 -04:00
return false ;
2015-03-09 21:28:37 -04:00
}
2015-03-16 16:40:30 -04:00
2015-03-23 23:01:05 -04:00
if ( E . Origin ! = E . Target )
{
2015-04-10 00:02:12 -04:00
E . Origin . stats . Kills + = 1 ;
2015-03-23 23:01:05 -04:00
E . Origin . stats . updateKDR ( ) ;
2015-04-10 00:02:12 -04:00
E . Target . stats . Deaths + = 1 ;
2015-03-23 23:01:05 -04:00
E . Target . stats . updateKDR ( ) ;
2015-03-16 16:40:30 -04:00
2015-04-10 00:02:12 -04:00
Skills . updateNewSkill ( E . Origin , E . Target ) ;
2015-03-30 01:04:10 -04:00
statDB . updatePlayer ( E . Origin ) ;
statDB . updatePlayer ( E . Target ) ;
2015-03-16 16:40:30 -04:00
2015-03-23 23:01:05 -04:00
totalKills + + ;
2015-04-10 00:02:12 -04:00
Log . Write ( E . Origin . getName ( ) + " killed " + E . Target . getName ( ) + " with a " + E . Data , Log . Level . Debug ) ;
2015-03-23 23:01:05 -04:00
}
2015-03-16 16:40:30 -04:00
2015-04-11 13:31:04 -04:00
else // suicide/falling
2015-03-23 23:01:05 -04:00
{
E . Origin . stats . Deaths + + ;
E . Origin . stats . updateKDR ( ) ;
2015-03-30 01:04:10 -04:00
statDB . updatePlayer ( E . Origin ) ;
2015-04-10 00:02:12 -04:00
Log . Write ( E . Origin . getName ( ) + " suicided..." , Log . Level . Debug ) ;
2015-03-23 23:01:05 -04:00
}
2015-03-09 21:28:37 -04:00
}
2015-03-16 16:40:30 -04:00
if ( E . Type = = Event . GType . Say )
2015-03-08 17:20:10 -04:00
{
2015-03-16 16:40:30 -04:00
if ( E . Data . Length < 2 ) // ITS A LIE!
return false ;
if ( E . Origin = = null )
{
Log . Write ( "Say event triggered, but no origin found! - " + E . Data , Log . Level . Debug ) ;
2015-03-09 21:28:37 -04:00
return false ;
2015-03-16 16:40:30 -04:00
}
2015-03-09 21:28:37 -04:00
2015-03-08 17:20:10 -04:00
Log . Write ( "Message from " + E . Origin . getName ( ) + ": " + E . Data , Log . Level . Debug ) ;
2015-03-16 16:40:30 -04:00
if ( E . Owner = = null )
{
Log . Write ( "Say event does not have an owner!" , Log . Level . Debug ) ;
return false ;
}
if ( E . Data . Substring ( 0 , 1 ) ! = "!" ) // Not a command so who gives an F?
2015-04-19 14:14:30 -04:00
{
E . Data = Utilities . stripColors ( Utilities . cleanChars ( E . Data ) ) ;
if ( E . Data . Length > 50 )
E . Data = E . Data . Substring ( 0 , 50 ) + "..." ;
if ( chatHistory . Count > Math . Ceiling ( ( double ) clientnum / 2 ) )
chatHistory . RemoveAt ( 0 ) ;
chatHistory . Add ( new Chat ( E . Origin , E . Data , DateTime . Now ) ) ;
2015-03-08 17:20:10 -04:00
return true ;
2015-04-19 14:14:30 -04:00
}
2015-03-08 17:20:10 -04:00
Command C = E . isValidCMD ( commands ) ;
2015-03-16 16:40:30 -04:00
2015-03-08 17:20:10 -04:00
if ( C ! = null )
{
C = processCommand ( E , C ) ;
if ( C ! = null )
{
2015-03-16 16:40:30 -04:00
if ( C . needsTarget ( ) & & E . Target = = null )
{
Log . Write ( "Requested event requiring target does not have a target!" , Log . Level . Debug ) ;
return false ;
}
2015-03-08 17:20:10 -04:00
C . Execute ( E ) ;
return true ;
}
2015-04-10 00:02:12 -04:00
2015-03-08 17:20:10 -04:00
else
{
2015-03-16 16:40:30 -04:00
Log . Write ( "Player didn't properly enter command - " + E . Origin . getName ( ) , Log . Level . Debug ) ;
2015-03-08 17:20:10 -04:00
return true ;
}
}
else
E . Origin . Tell ( "You entered an invalid command!" ) ;
return true ;
}
if ( E . Type = = Event . GType . MapChange )
{
2015-04-10 00:02:12 -04:00
Log . Write ( "New map loaded - " + clientnum + " active players" , Log . Level . Debug ) ;
2015-03-10 16:45:20 -04:00
String [ ] statusResponse = E . Data . Split ( '\\' ) ;
if ( statusResponse . Length > = 15 & & statusResponse [ 13 ] = = "mapname" )
2015-04-11 13:31:04 -04:00
mapname = maps . Find ( m = > m . Name . Equals ( statusResponse [ 14 ] ) ) . Alias ; //update map for heartbeat
return true ;
2015-03-08 17:20:10 -04:00
}
if ( E . Type = = Event . GType . MapEnd )
{
2015-03-10 16:45:20 -04:00
Log . Write ( "Game ending..." , Log . Level . Debug ) ;
2015-03-09 21:28:37 -04:00
foreach ( Player P in players )
{
2015-03-10 16:45:20 -04:00
if ( P = = null | | P . stats = = null )
2015-03-09 21:28:37 -04:00
continue ;
2015-03-13 19:40:16 -04:00
statDB . updatePlayer ( P ) ;
2015-03-09 21:28:37 -04:00
Log . Write ( "Updated stats for client " + P . getDBID ( ) , Log . Level . Debug ) ;
}
2015-03-08 17:20:10 -04:00
return true ;
}
return false ;
}
2015-03-13 19:40:16 -04:00
public bool Reload ( )
{
try
{
messages = null ;
maps = null ;
rules = null ;
initMaps ( ) ;
initMessages ( ) ;
initRules ( ) ;
return true ;
}
catch ( Exception E )
{
Log . Write ( "Unable to reload configs! - " + E . Message , Log . Level . Debug ) ;
messages = new List < String > ( ) ;
maps = new List < Map > ( ) ;
rules = new List < String > ( ) ;
return false ;
}
}
2015-03-08 17:20:10 -04:00
//THESE MAY NEED TO BE MOVED
public void Broadcast ( String Message )
{
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "sayraw " + Message ) ;
2015-03-08 17:20:10 -04:00
}
public void Tell ( String Message , Player Target )
{
2015-04-10 00:02:12 -04:00
if ( Target . getClientNum ( ) > - 1 )
RCON . addRCON ( "tell " + Target . getClientNum ( ) + " " + Message + "^7" ) ;
2015-03-08 17:20:10 -04:00
}
public void Kick ( String Message , Player Target )
{
2015-04-10 00:02:12 -04:00
if ( Target . getClientNum ( ) > - 1 )
RCON . addRCON ( "clientkick " + Target . getClientNum ( ) + " \"" + Message + "^7\"" ) ;
2015-03-08 17:20:10 -04:00
}
public void Ban ( String Message , Player Target , Player Origin )
{
2015-04-10 00:02:12 -04:00
if ( Target . getClientNum ( ) > - 1 )
RCON . addRCON ( "tempbanclient " + Target . getClientNum ( ) + " \"" + Message + "^7\"" ) ;
2015-03-08 17:20:10 -04:00
if ( Origin ! = null )
{
Target . setLevel ( Player . Permission . Banned ) ;
2015-03-13 19:40:16 -04:00
Ban newBan = new Ban ( Target . getLastO ( ) , Target . getID ( ) , Origin . getID ( ) , DateTime . Now , Target . getIP ( ) ) ;
2015-03-08 17:20:10 -04:00
Bans . Add ( newBan ) ;
2015-03-13 19:40:16 -04:00
clientDB . addBan ( newBan ) ;
clientDB . updatePlayer ( Target ) ;
2015-04-10 00:02:12 -04:00
lock ( Reports ) // threading seems to do something weird here
{
List < Report > toRemove = new List < Report > ( ) ;
foreach ( Report R in Reports )
{
if ( R . Target . getID ( ) = = Target . getID ( ) )
toRemove . Add ( R ) ;
}
foreach ( Report R in toRemove )
{
Reports . Remove ( R ) ;
Log . Write ( "Removing report for banned GUID -- " + R . Origin . getID ( ) , Log . Level . Debug ) ;
}
}
2015-03-08 17:20:10 -04:00
}
}
2015-03-09 00:28:57 -04:00
public bool Unban ( String GUID , Player Target )
2015-03-08 17:20:10 -04:00
{
foreach ( Ban B in Bans )
{
2015-03-09 21:28:37 -04:00
if ( B . getID ( ) = = Target . getID ( ) )
2015-03-08 17:20:10 -04:00
{
2015-04-13 00:25:34 -04:00
clientDB . removeBan ( Target . getID ( ) , Target . getIP ( ) ) ;
2015-04-19 14:14:30 -04:00
int position = Bans . IndexOf ( B ) ;
if ( position > - 1 & & position < Bans . Count - 1 )
{
Log . Write ( "Removing ban at index #" + position , Log . Level . Debug ) ;
Bans . RemoveAt ( position ) ;
Bans [ position ] = null ;
}
else
Log . Write ( position + " is an invalid ban index!" , Log . Level . Debug ) ;
2015-04-13 00:25:34 -04:00
Player P = clientDB . getPlayer ( Target . getID ( ) , - 1 ) ;
2015-03-08 17:20:10 -04:00
P . setLevel ( Player . Permission . User ) ;
2015-03-13 19:40:16 -04:00
clientDB . updatePlayer ( P ) ;
2015-03-08 17:20:10 -04:00
return true ;
}
}
return false ;
}
public void fastRestart ( int delay )
{
Utilities . Wait ( delay ) ;
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "fast_restart" ) ;
2015-03-08 17:20:10 -04:00
}
public void mapRotate ( int delay )
{
Utilities . Wait ( delay ) ;
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "map_rotate" ) ;
2015-03-08 17:20:10 -04:00
}
public void tempBan ( String Message , Player Target )
{
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "tempbanclient " + Target . getClientNum ( ) + " \"" + Message + "\"" ) ;
2015-03-08 17:20:10 -04:00
}
public void mapRotate ( )
{
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "map_rotate" ) ;
2015-03-08 17:20:10 -04:00
}
public void Map ( String map )
{
2015-03-13 19:40:16 -04:00
RCON . addRCON ( "map " + map ) ;
}
public String Wisdom ( )
{
String Quote = new Connection ( "http://www.iheartquotes.com/api/v1/random?max_lines=1&max_characters=200" ) . Read ( ) ;
return Utilities . removeNastyChars ( Quote ) ;
2015-03-08 17:20:10 -04:00
}
2015-03-13 19:40:16 -04:00
2015-03-23 23:01:05 -04:00
public void ToAdmins ( String message )
{
2015-04-10 00:02:12 -04:00
lock ( players ) // threading can modify list while we do this
2015-03-23 23:01:05 -04:00
{
2015-04-10 00:02:12 -04:00
foreach ( Player P in players )
2015-03-23 23:01:05 -04:00
{
2015-04-10 00:02:12 -04:00
if ( P = = null )
continue ;
2015-04-13 00:25:34 -04:00
if ( P . getLevel ( ) > Player . Permission . Flagged )
2015-04-10 00:02:12 -04:00
{
P . Alert ( ) ;
P . Tell ( message ) ;
}
2015-03-23 23:01:05 -04:00
}
}
}
2015-04-10 00:02:12 -04:00
public void Alert ( Player P )
{
RCON . addRCON ( "admin_lastevent alert;" + P . getID ( ) + ";0;mp_killstreak_nuclearstrike" ) ;
}
2015-04-19 14:14:30 -04:00
public void webChat ( Player P , String Message )
{
DateTime requestTime = DateTime . Now ;
if ( ( requestTime - lastWebChat ) . TotalSeconds > 1 )
{
Broadcast ( "^1[WEBCHAT] ^5" + P . getName ( ) + "^7 - " + Message ) ;
if ( 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 ;
}
}
2015-03-08 17:20:10 -04:00
//END
//THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/
public String getPassword ( )
{
return rcon_pass ;
}
2015-03-13 19:40:16 -04:00
private void initMacros ( )
{
Macros = new Dictionary < String , Object > ( ) ;
Macros . Add ( "WISDOM" , Wisdom ( ) ) ;
Macros . Add ( "TOTALPLAYERS" , clientDB . totalPlayers ( ) ) ;
2015-03-23 23:01:05 -04:00
Macros . Add ( "TOTALKILLS" , totalKills ) ;
2015-03-13 19:40:16 -04:00
}
2015-03-08 17:20:10 -04:00
private void initMaps ( )
{
2015-03-13 19:40:16 -04:00
maps = new List < Map > ( ) ;
2015-03-08 17:20:10 -04:00
file mapfile = new file ( "config\\maps.cfg" ) ;
String [ ] _maps = mapfile . readAll ( ) ;
2015-03-13 19:40:16 -04:00
mapfile . Close ( ) ;
2015-03-08 17:20:10 -04:00
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 ) ;
}
}
2015-03-11 21:25:14 -04:00
}
2015-03-08 17:20:10 -04:00
else
Log . Write ( "Maps configuration appears to be empty - skipping..." , Log . Level . All ) ;
}
private void initMessages ( )
{
2015-03-13 19:40:16 -04:00
messages = new List < String > ( ) ;
2015-03-08 17:20:10 -04:00
file messageCFG = new file ( "config\\messages.cfg" ) ;
String [ ] lines = messageCFG . readAll ( ) ;
2015-03-13 19:40:16 -04:00
messageCFG . Close ( ) ;
2015-03-08 17:20:10 -04:00
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 ) ;
}
2015-03-10 16:45:20 -04:00
if ( Program . Version ! = Program . latestVersion & & Program . latestVersion ! = 0 )
messages . Add ( "^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + Program . latestVersion ) ;
2015-03-08 17:20:10 -04:00
}
private void initRules ( )
{
2015-03-13 19:40:16 -04:00
rules = new List < String > ( ) ;
2015-03-08 17:20:10 -04:00
file ruleFile = new file ( "config\\rules.cfg" ) ;
String [ ] _rules = ruleFile . readAll ( ) ;
2015-03-13 19:40:16 -04:00
ruleFile . Close ( ) ;
2015-03-08 17:20:10 -04:00
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 ) ) ;
2015-03-10 16:45:20 -04:00
commands . Add ( new Help ( "help" , "list all available commands. syntax: !help." , "h" , Player . Permission . User , 0 , false ) ) ;
2015-03-08 17:20:10 -04:00
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 ) ) ;
2015-03-10 16:45:20 -04:00
commands . Add ( new Usage ( "usage" , "get current application memory usage. syntax: !usage." , "us" , Player . Permission . Moderator , 0 , false ) ) ;
2015-03-08 17:20:10 -04:00
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 ) ) ;
2015-04-13 00:25:34 -04:00
commands . Add ( new Unban ( "unban" , "unban player by database id. syntax: !unban @<id>." , "ub" , Player . Permission . SeniorAdmin , 1 , true ) ) ;
2015-03-08 17:20:10 -04:00
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 ) ) ;
2015-03-13 19:40:16 -04:00
commands . Add ( new Find ( "find" , "find player in database. syntax: !find <player>" , "f" , Player . Permission . SeniorAdmin , 1 , false ) ) ;
2015-03-08 17:20:10 -04:00
commands . Add ( new Rules ( "rules" , "list server rules. syntax: !rules" , "r" , Player . Permission . User , 0 , false ) ) ;
2015-03-09 16:11:09 -04:00
commands . Add ( new PrivateMessage ( "privatemessage" , "send message to other player. syntax: !pm <player> <message>" , "pm" , Player . Permission . User , 2 , true ) ) ;
2015-03-09 21:28:37 -04:00
commands . Add ( new _Stats ( "stats" , "view your stats or another player's. syntax: !stats" , "xlrstats" , Player . Permission . User , 0 , true ) ) ;
2015-03-13 19:40:16 -04:00
commands . Add ( new TopStats ( "topstats" , "view the top 4 players on this server. syntax: !topstats" , "xlrtopstats" , Player . Permission . User , 0 , false ) ) ;
commands . Add ( new Reload ( "reload" , "reload configurations. syntax: !reload" , "reload" , Player . Permission . Owner , 0 , false ) ) ;
2015-03-23 23:01:05 -04:00
commands . Add ( new Balance ( "balance" , "balance teams. syntax !balance" , "bal" , Player . Permission . Moderator , 0 , false ) ) ;
commands . Add ( new GoTo ( "goto" , "teleport to selected player. syntax !goto" , "go" , Player . Permission . SeniorAdmin , 1 , true ) ) ;
commands . Add ( new Flag ( "flag" , "flag a suspicious player and announce to admins on join . syntax !flag <player>:" , "flag" , Player . Permission . Moderator , 1 , true ) ) ;
commands . Add ( new _Report ( "report" , "report a player for suspicious behaivor. syntax !report <player> <reason>" , "rep" , Player . Permission . User , 2 , true ) ) ;
commands . Add ( new Reports ( "reports" , "get most recent reports. syntax !reports" , "reports" , Player . Permission . Moderator , 0 , false ) ) ;
2015-04-10 00:02:12 -04:00
commands . Add ( new _Tell ( "tell" , "send onscreen message to player. syntax !tell <player> <message>" , "t" , Player . Permission . Moderator , 2 , true ) ) ;
commands . Add ( new Mask ( "mask" , "hide your online presence from online admin list. syntax: !mask" , "mask" , Player . Permission . Administrator , 0 , false ) ) ;
commands . Add ( new BanInfo ( "baninfo" , "get information about a ban for a player. syntax: !baninfo <player>" , "bi" , Player . Permission . Moderator , 1 , true ) ) ;
commands . Add ( new Alias ( "alias" , "get past aliases and ips of a player. syntax: !alias <player>" , "known" , Player . Permission . Moderator , 1 , true ) ) ;
commands . Add ( new _RCON ( "rcon" , "send rcon command to server. syntax: !rcon <command>" , "rcon" , Player . Permission . Owner , 1 , false ) ) ;
2015-04-13 00:25:34 -04:00
commands . Add ( new FindAll ( "findall" , "find a player by their aliase(s). syntax: !findall <player>" , "fa" , Player . Permission . Moderator , 1 , false ) ) ;
2015-03-08 17:20:10 -04:00
}
//Objects
public Log Log ;
public RCON RCON ;
2015-03-13 19:40:16 -04:00
public ClientsDB clientDB ;
public AliasesDB aliasDB ;
public StatsDB statDB ;
2015-03-08 17:20:10 -04:00
public List < Ban > Bans ;
public Player owner ;
public List < Map > maps ;
public List < String > rules ;
public Queue < Event > events ;
2015-03-10 16:45:20 -04:00
public Heartbeat HB ;
2015-03-11 00:47:34 -04:00
public String Website ;
2015-03-11 21:25:14 -04:00
public String Gametype ;
2015-03-23 23:01:05 -04:00
public int totalKills = 0 ;
public List < Report > Reports ;
2015-04-19 14:14:30 -04:00
public List < Chat > chatHistory ;
2015-03-08 17:20:10 -04:00
//Info
private String IP ;
private int Port ;
private String hostname ;
2015-03-10 16:45:20 -04:00
private String mapname ;
2015-03-08 17:20:10 -04:00
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 ;
2015-03-11 21:25:14 -04:00
private String IW_Ver ;
private int maxClients ;
2015-03-13 19:40:16 -04:00
private Dictionary < String , Object > Macros ;
2015-04-10 00:02:12 -04:00
private Moserware . TrueSkill Skills ;
2015-04-19 14:14:30 -04:00
private DateTime lastWebChat ;
2015-03-13 19:40:16 -04:00
//Will probably move this later
2015-04-10 00:02:12 -04:00
public Dictionary < String , Player > statusPlayers ;
2015-03-14 12:42:36 -04:00
public bool isRunning ;
private DateTime lastPoll ;
2015-03-10 17:56:01 -04:00
2015-03-08 17:20:10 -04:00
//Log stuff
private String Basepath ;
private String Mod ;
private String logPath ;
private file logFile ;
}
}