mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-25 21:51:30 +00:00
539 lines
10 KiB
C
539 lines
10 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id$
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Log$
|
|
// Revision 1.15 2003/04/19 17:41:26 jbravo
|
|
// Applied changes that where in 1.29h -> 1.32b gamecode.
|
|
//
|
|
// Revision 1.14 2002/08/02 22:44:37 slicer
|
|
// Added resetMatch command for MM
|
|
//
|
|
// Revision 1.13 2002/06/19 18:13:57 jbravo
|
|
// New TNG spawning system :)
|
|
//
|
|
// Revision 1.12 2002/06/18 03:57:38 jbravo
|
|
// Committing for aasimon. Callvote nextmap removed and replaced with cyclemap for .ini
|
|
//
|
|
// Revision 1.11 2002/06/16 20:06:14 jbravo
|
|
// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap"
|
|
//
|
|
// Revision 1.10 2002/06/10 17:40:52 slicer
|
|
// Added MM's ClearScores command as console cmd also
|
|
//
|
|
// Revision 1.9 2002/05/20 04:59:33 jbravo
|
|
// Lots of small fixes.
|
|
//
|
|
// Revision 1.8 2002/05/04 16:19:02 jbravo
|
|
// Fixing the stuff cmd to work on dedicated servers.
|
|
//
|
|
// Revision 1.7 2002/04/03 15:51:01 jbravo
|
|
// Small warning fixes
|
|
//
|
|
// Revision 1.6 2002/02/26 03:58:19 jbravo
|
|
// Added a newline to the say messages from the server
|
|
//
|
|
// Revision 1.5 2002/01/11 19:48:30 jbravo
|
|
// Formatted the source in non DOS format.
|
|
//
|
|
// Revision 1.4 2001/12/31 16:28:42 jbravo
|
|
// I made a Booboo with the Log tag.
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1999-2000 Id Software, Inc.
|
|
//
|
|
|
|
// 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 you can use '*' to 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.
|
|
|
|
TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
|
|
The size of the cvar string buffer is limiting the banning to around 20 masks
|
|
this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
|
|
still, you should rely on PB for banning instead
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
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') {
|
|
if (*s == '*') { // 'match any'
|
|
// b[i] and m[i] to 0
|
|
s++;
|
|
if (!*s)
|
|
break;
|
|
s++;
|
|
continue;
|
|
}
|
|
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);
|
|
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], m[4];
|
|
int i, j;
|
|
char iplist_final[MAX_CVAR_VALUE_STRING];
|
|
char ip[64];
|
|
|
|
*iplist_final = 0;
|
|
for (i = 0; i < numIPFilters; i++) {
|
|
if (ipFilters[i].compare == 0xffffffff)
|
|
continue;
|
|
|
|
*(unsigned *) b = ipFilters[i].compare;
|
|
*(unsigned *) m = ipFilters[i].mask;
|
|
*ip = 0;
|
|
for (j = 0; j < 4; j++) {
|
|
if (m[j] != 255)
|
|
Q_strcat(ip, sizeof(ip), "*");
|
|
else
|
|
Q_strcat(ip, sizeof(ip), va("%i", b[j]));
|
|
Q_strcat(ip, sizeof(ip), (j < 3) ? "." : " ");
|
|
}
|
|
if (strlen(iplist_final) + strlen(ip) < MAX_CVAR_VALUE_STRING) {
|
|
Q_strcat(iplist_final, sizeof(iplist_final), ip);
|
|
} else {
|
|
Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
trap_Cvar_Set("g_banIPs", iplist_final);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
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
|
|
=================
|
|
*/
|
|
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_CVAR_VALUE_STRING];
|
|
|
|
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: 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_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];
|
|
|
|
if ( trap_Argc() < 3 ) {
|
|
G_Printf("Usage: forceteam <player> <team>\n");
|
|
return;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
// JBravo: adding a stuff cmd.
|
|
if (Q_stricmp(cmd, "stuff") == 0) {
|
|
RQ3_Cmd_Stuff();
|
|
return qtrue;
|
|
}
|
|
//sLiCeR: adding a clearScores
|
|
if (Q_stricmp(cmd, "clearscores") == 0 && g_RQ3_matchmode.integer) {
|
|
MM_ClearScores(qfalse);
|
|
return qtrue;
|
|
}
|
|
if (Q_stricmp(cmd, "resetmatch") == 0 && g_RQ3_matchmode.integer) {
|
|
MM_ResetMatch();
|
|
return qtrue;
|
|
}
|
|
|
|
if (Q_stricmp(cmd, "listip") == 0) {
|
|
trap_SendConsoleCommand(EXEC_NOW, "g_banIPs\n");
|
|
return qtrue;
|
|
}
|
|
|
|
if (Q_stricmp(cmd, "cyclemap") == 0 ) {
|
|
BeginIntermission();
|
|
return qtrue;
|
|
}
|
|
|
|
if (g_dedicated.integer) {
|
|
if (Q_stricmp(cmd, "say") == 0) {
|
|
trap_SendServerCommand(-1, va("print \"^1server: %s\n\"", ConcatArgs(1)));
|
|
return qtrue;
|
|
}
|
|
// everything else will also be printed as a say command
|
|
trap_SendServerCommand(-1, va("print \"^1server: %s\n\"", ConcatArgs(0)));
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|