summaryrefslogtreecommitdiff
path: root/src/game/g_svcmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_svcmds.c')
-rw-r--r--src/game/g_svcmds.c488
1 files changed, 488 insertions, 0 deletions
diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c
new file mode 100644
index 00000000..81af978f
--- /dev/null
+++ b/src/game/g_svcmds.c
@@ -0,0 +1,488 @@
+// Copyright (C) 1999-2000 Id Software, Inc.
+//
+
+/*
+ * Portions Copyright (C) 2000-2001 Tim Angus
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* To assertain which portions are licensed under the GPL and which are
+ * licensed by Id Software, Inc. please run a diff between the equivalent
+ * versions of the "Tremulous" modification and the unmodified "Quake3"
+ * game source code.
+ */
+
+// this file holds commands that can be executed by the server console, but not remote clients
+
+#include "g_local.h"
+
+
+/*
+==============================================================================
+
+PACKET FILTERING
+
+
+You can add or remove addresses from the filter list with:
+
+addip <ip>
+removeip <ip>
+
+The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
+
+Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
+
+listip
+Prints the current list of filters.
+
+g_filterban <0 or 1>
+
+If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
+
+If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
+
+
+==============================================================================
+*/
+
+// extern vmCvar_t g_banIPs;
+// extern vmCvar_t g_filterBan;
+
+
+typedef struct ipFilter_s
+{
+ unsigned mask;
+ unsigned compare;
+} ipFilter_t;
+
+#define MAX_IPFILTERS 1024
+
+static ipFilter_t ipFilters[MAX_IPFILTERS];
+static int numIPFilters;
+
+/*
+=================
+StringToFilter
+=================
+*/
+static qboolean StringToFilter (char *s, ipFilter_t *f)
+{
+ char num[128];
+ int i, j;
+ byte b[4];
+ byte m[4];
+
+ for (i=0 ; i<4 ; i++)
+ {
+ b[i] = 0;
+ m[i] = 0;
+ }
+
+ for (i=0 ; i<4 ; i++)
+ {
+ if (*s < '0' || *s > '9')
+ {
+ G_Printf( "Bad filter address: %s\n", s );
+ return qfalse;
+ }
+
+ j = 0;
+ while (*s >= '0' && *s <= '9')
+ {
+ num[j++] = *s++;
+ }
+ num[j] = 0;
+ b[i] = atoi(num);
+ if (b[i] != 0)
+ m[i] = 255;
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ f->mask = *(unsigned *)m;
+ f->compare = *(unsigned *)b;
+
+ return qtrue;
+}
+
+/*
+=================
+UpdateIPBans
+=================
+*/
+static void UpdateIPBans (void)
+{
+ byte b[4];
+ int i;
+ char iplist[MAX_INFO_STRING];
+
+ *iplist = 0;
+ for (i = 0 ; i < numIPFilters ; i++)
+ {
+ if (ipFilters[i].compare == 0xffffffff)
+ continue;
+
+ *(unsigned *)b = ipFilters[i].compare;
+ Com_sprintf( iplist + strlen(iplist), sizeof(iplist) - strlen(iplist),
+ "%i.%i.%i.%i ", b[0], b[1], b[2], b[3]);
+ }
+
+ trap_Cvar_Set( "g_banIPs", iplist );
+}
+
+/*
+=================
+G_FilterPacket
+=================
+*/
+qboolean G_FilterPacket (char *from)
+{
+ int i;
+ unsigned in;
+ byte m[4];
+ char *p;
+
+ i = 0;
+ p = from;
+ while (*p && i < 4) {
+ m[i] = 0;
+ while (*p >= '0' && *p <= '9') {
+ m[i] = m[i]*10 + (*p - '0');
+ p++;
+ }
+ if (!*p || *p == ':')
+ break;
+ i++, p++;
+ }
+
+ in = *(unsigned *)m;
+
+ for (i=0 ; i<numIPFilters ; i++)
+ if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
+ return g_filterBan.integer != 0;
+
+ return g_filterBan.integer == 0;
+}
+
+/*
+=================
+AddIP
+=================
+*/
+static void AddIP( char *str )
+{
+ int i;
+
+ for (i = 0 ; i < numIPFilters ; i++)
+ if (ipFilters[i].compare == 0xffffffff)
+ break; // free spot
+ if (i == numIPFilters)
+ {
+ if (numIPFilters == MAX_IPFILTERS)
+ {
+ G_Printf ("IP filter list is full\n");
+ return;
+ }
+ numIPFilters++;
+ }
+
+ if (!StringToFilter (str, &ipFilters[i]))
+ ipFilters[i].compare = 0xffffffffu;
+
+ UpdateIPBans();
+}
+
+/*
+=================
+G_ProcessIPBans
+=================
+*/
+void G_ProcessIPBans(void)
+{
+ char *s, *t;
+ char str[MAX_TOKEN_CHARS];
+
+ Q_strncpyz( str, g_banIPs.string, sizeof(str) );
+
+ for (t = s = g_banIPs.string; *t; /* */ ) {
+ s = strchr(s, ' ');
+ if (!s)
+ break;
+ while (*s == ' ')
+ *s++ = 0;
+ if (*t)
+ AddIP( t );
+ t = s;
+ }
+}
+
+
+/*
+=================
+Svcmd_AddIP_f
+=================
+*/
+void Svcmd_AddIP_f (void)
+{
+ char str[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc() < 2 ) {
+ G_Printf("Usage: addip <ip-mask>\n");
+ return;
+ }
+
+ trap_Argv( 1, str, sizeof( str ) );
+
+ AddIP( str );
+
+}
+
+/*
+=================
+Svcmd_RemoveIP_f
+=================
+*/
+void Svcmd_RemoveIP_f (void)
+{
+ ipFilter_t f;
+ int i;
+ char str[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc() < 2 ) {
+ G_Printf("Usage: sv removeip <ip-mask>\n");
+ return;
+ }
+
+ trap_Argv( 1, str, sizeof( str ) );
+
+ if (!StringToFilter (str, &f))
+ return;
+
+ for (i=0 ; i<numIPFilters ; i++) {
+ if (ipFilters[i].mask == f.mask &&
+ ipFilters[i].compare == f.compare) {
+ ipFilters[i].compare = 0xffffffffu;
+ G_Printf ("Removed.\n");
+
+ UpdateIPBans();
+ return;
+ }
+ }
+
+ G_Printf ( "Didn't find %s.\n", str );
+}
+
+/*
+===================
+Svcmd_EntityList_f
+===================
+*/
+void Svcmd_EntityList_f (void) {
+ int e;
+ gentity_t *check;
+
+ check = g_entities+1;
+ for (e = 1; e < level.num_entities ; e++, check++) {
+ if ( !check->inuse ) {
+ continue;
+ }
+ G_Printf("%3i:", e);
+ switch ( check->s.eType ) {
+ case ET_GENERAL:
+ G_Printf("ET_GENERAL ");
+ break;
+ case ET_PLAYER:
+ G_Printf("ET_PLAYER ");
+ break;
+ case ET_ITEM:
+ G_Printf("ET_ITEM ");
+ break;
+ case ET_BUILDABLE:
+ G_Printf("ET_BUILDABLE ");
+ break;
+ case ET_MISSILE:
+ G_Printf("ET_MISSILE ");
+ break;
+ case ET_MOVER:
+ G_Printf("ET_MOVER ");
+ break;
+ case ET_BEAM:
+ G_Printf("ET_BEAM ");
+ break;
+ case ET_PORTAL:
+ G_Printf("ET_PORTAL ");
+ break;
+ case ET_SPEAKER:
+ G_Printf("ET_SPEAKER ");
+ break;
+ case ET_PUSH_TRIGGER:
+ G_Printf("ET_PUSH_TRIGGER ");
+ break;
+ case ET_TELEPORT_TRIGGER:
+ G_Printf("ET_TELEPORT_TRIGGER ");
+ break;
+ case ET_INVISIBLE:
+ G_Printf("ET_INVISIBLE ");
+ break;
+ case ET_GRAPPLE:
+ G_Printf("ET_GRAPPLE ");
+ break;
+ default:
+ G_Printf("%3i ", check->s.eType);
+ break;
+ }
+
+ if ( check->classname ) {
+ G_Printf("%s", check->classname);
+ }
+ G_Printf("\n");
+ }
+}
+
+gclient_t *ClientForString( const char *s ) {
+ gclient_t *cl;
+ int i;
+ int idnum;
+
+ // numeric values are just slot numbers
+ if ( s[0] >= '0' && s[0] <= '9' ) {
+ idnum = atoi( s );
+ if ( idnum < 0 || idnum >= level.maxclients ) {
+ Com_Printf( "Bad client slot: %i\n", idnum );
+ return NULL;
+ }
+
+ cl = &level.clients[idnum];
+ if ( cl->pers.connected == CON_DISCONNECTED ) {
+ G_Printf( "Client %i is not connected\n", idnum );
+ return NULL;
+ }
+ return cl;
+ }
+
+ // check for a name match
+ for ( i=0 ; i < level.maxclients ; i++ ) {
+ cl = &level.clients[i];
+ if ( cl->pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( !Q_stricmp( cl->pers.netname, s ) ) {
+ return cl;
+ }
+ }
+
+ G_Printf( "User %s is not on the server\n", s );
+
+ return NULL;
+}
+
+/*
+===================
+Svcmd_ForceTeam_f
+
+forceteam <player> <team>
+===================
+*/
+void Svcmd_ForceTeam_f( void ) {
+ gclient_t *cl;
+ char str[MAX_TOKEN_CHARS];
+
+ // find the player
+ trap_Argv( 1, str, sizeof( str ) );
+ cl = ClientForString( str );
+ if ( !cl ) {
+ return;
+ }
+
+ // set the team
+ trap_Argv( 2, str, sizeof( str ) );
+ SetTeam( &g_entities[cl - level.clients], str );
+}
+
+char *ConcatArgs( int start );
+
+/*
+=================
+ConsoleCommand
+
+=================
+*/
+qboolean ConsoleCommand( void ) {
+ char cmd[MAX_TOKEN_CHARS];
+
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+
+ if ( Q_stricmp (cmd, "entitylist") == 0 ) {
+ Svcmd_EntityList_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "forceteam") == 0 ) {
+ Svcmd_ForceTeam_f();
+ return qtrue;
+ }
+
+ if (Q_stricmp (cmd, "game_memory") == 0) {
+ Svcmd_GameMem_f();
+ return qtrue;
+ }
+
+ //TA: rip bots
+ /*if (Q_stricmp (cmd, "addbot") == 0) {
+ Svcmd_AddBot_f();
+ return qtrue;
+ }
+
+ if (Q_stricmp (cmd, "botlist") == 0) {
+ Svcmd_BotList_f();
+ return qtrue;
+ }*/
+
+ if (Q_stricmp (cmd, "abort_podium") == 0) {
+ Svcmd_AbortPodium_f();
+ return qtrue;
+ }
+
+ if (Q_stricmp (cmd, "addip") == 0) {
+ Svcmd_AddIP_f();
+ return qtrue;
+ }
+
+ if (Q_stricmp (cmd, "removeip") == 0) {
+ Svcmd_RemoveIP_f();
+ return qtrue;
+ }
+
+ if (Q_stricmp (cmd, "listip") == 0) {
+ trap_SendConsoleCommand( EXEC_INSERT, "g_banIPs\n" );
+ return qtrue;
+ }
+
+ if (g_dedicated.integer) {
+ if (Q_stricmp (cmd, "say") == 0) {
+ trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(1) ) );
+ return qtrue;
+ }
+ // everything else will also be printed as a say command
+ trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(0) ) );
+ return qtrue;
+ }
+
+ return qfalse;
+}
+