diff options
Diffstat (limited to 'QW/server/sv_ccmds.c')
| -rw-r--r-- | QW/server/sv_ccmds.c | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/QW/server/sv_ccmds.c b/QW/server/sv_ccmds.c new file mode 100644 index 0000000..14cec5d --- /dev/null +++ b/QW/server/sv_ccmds.c @@ -0,0 +1,900 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +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 +of the License, 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. + +*/ + +#include "qwsvdef.h" + +qboolean sv_allow_cheats; + +int fp_messages=4, fp_persecond=4, fp_secondsdead=10; +char fp_msg[255] = { 0 }; +extern cvar_t cl_warncmd; + extern redirect_t sv_redirected; + + +/* +=============================================================================== + +OPERATOR CONSOLE ONLY COMMANDS + +These commands can only be entered from stdin or by a remote operator datagram +=============================================================================== +*/ + +/* +==================== +SV_SetMaster_f + +Make a master server current +==================== +*/ +void SV_SetMaster_f (void) +{ + char data[2]; + int i; + + memset (&master_adr, 0, sizeof(master_adr)); + + for (i=1 ; i<Cmd_Argc() ; i++) + { + if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1])) + { + Con_Printf ("Setting nomaster mode.\n"); + return; + } + if (master_adr[i-1].port == 0) + master_adr[i-1].port = BigShort (27000); + + Con_Printf ("Master server at %s\n", NET_AdrToString (master_adr[i-1])); + + Con_Printf ("Sending a ping.\n"); + + data[0] = A2A_PING; + data[1] = 0; + NET_SendPacket (2, data, master_adr[i-1]); + } + + svs.last_heartbeat = -99999; +} + + +/* +================== +SV_Quit_f +================== +*/ +void SV_Quit_f (void) +{ + SV_FinalMessage ("server shutdown\n"); + Con_Printf ("Shutting down.\n"); + SV_Shutdown (); + Sys_Quit (); +} + +/* +============ +SV_Logfile_f +============ +*/ +void SV_Logfile_f (void) +{ + char name[MAX_OSPATH]; + + if (sv_logfile) + { + Con_Printf ("File logging off.\n"); + fclose (sv_logfile); + sv_logfile = NULL; + return; + } + + sprintf (name, "%s/qconsole.log", com_gamedir); + Con_Printf ("Logging text to %s.\n", name); + sv_logfile = fopen (name, "w"); + if (!sv_logfile) + Con_Printf ("failed.\n"); +} + + +/* +============ +SV_Fraglogfile_f +============ +*/ +void SV_Fraglogfile_f (void) +{ + char name[MAX_OSPATH]; + int i; + + if (sv_fraglogfile) + { + Con_Printf ("Frag file logging off.\n"); + fclose (sv_fraglogfile); + sv_fraglogfile = NULL; + return; + } + + // find an unused name + for (i=0 ; i<1000 ; i++) + { + sprintf (name, "%s/frag_%i.log", com_gamedir, i); + sv_fraglogfile = fopen (name, "r"); + if (!sv_fraglogfile) + { // can't read it, so create this one + sv_fraglogfile = fopen (name, "w"); + if (!sv_fraglogfile) + i=1000; // give error + break; + } + fclose (sv_fraglogfile); + } + if (i==1000) + { + Con_Printf ("Can't open any logfiles.\n"); + sv_fraglogfile = NULL; + return; + } + + Con_Printf ("Logging frags to %s.\n", name); +} + + +/* +================== +SV_SetPlayer + +Sets host_client and sv_player to the player with idnum Cmd_Argv(1) +================== +*/ +qboolean SV_SetPlayer (void) +{ + client_t *cl; + int i; + int idnum; + + idnum = atoi(Cmd_Argv(1)); + + for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) + { + if (!cl->state) + continue; + if (cl->userid == idnum) + { + host_client = cl; + sv_player = host_client->edict; + return true; + } + } + Con_Printf ("Userid %i is not on the server\n", idnum); + return false; +} + + +/* +================== +SV_God_f + +Sets client to godmode +================== +*/ +void SV_God_f (void) +{ + if (!sv_allow_cheats) + { + Con_Printf ("You must run the server with -cheats to enable this command.\n"); + return; + } + + if (!SV_SetPlayer ()) + return; + + sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE; + if (!((int)sv_player->v.flags & FL_GODMODE) ) + SV_ClientPrintf (host_client, PRINT_HIGH, "godmode OFF\n"); + else + SV_ClientPrintf (host_client, PRINT_HIGH, "godmode ON\n"); +} + + +void SV_Noclip_f (void) +{ + if (!sv_allow_cheats) + { + Con_Printf ("You must run the server with -cheats to enable this command.\n"); + return; + } + + if (!SV_SetPlayer ()) + return; + + if (sv_player->v.movetype != MOVETYPE_NOCLIP) + { + sv_player->v.movetype = MOVETYPE_NOCLIP; + SV_ClientPrintf (host_client, PRINT_HIGH, "noclip ON\n"); + } + else + { + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf (host_client, PRINT_HIGH, "noclip OFF\n"); + } +} + + +/* +================== +SV_Give_f +================== +*/ +void SV_Give_f (void) +{ + char *t; + int v; + + if (!sv_allow_cheats) + { + Con_Printf ("You must run the server with -cheats to enable this command.\n"); + return; + } + + if (!SV_SetPlayer ()) + return; + + t = Cmd_Argv(2); + v = atoi (Cmd_Argv(3)); + + switch (t[0]) + { + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + sv_player->v.items = (int)sv_player->v.items | IT_SHOTGUN<< (t[0] - '2'); + break; + + case 's': + sv_player->v.ammo_shells = v; + break; + case 'n': + sv_player->v.ammo_nails = v; + break; + case 'r': + sv_player->v.ammo_rockets = v; + break; + case 'h': + sv_player->v.health = v; + break; + case 'c': + sv_player->v.ammo_cells = v; + break; + } +} + + +/* +====================== +SV_Map_f + +handle a +map <mapname> +command from the console or progs. +====================== +*/ +void SV_Map_f (void) +{ + char level[MAX_QPATH]; + char expanded[MAX_QPATH]; + FILE *f; + + if (Cmd_Argc() != 2) + { + Con_Printf ("map <levelname> : continue game on a new level\n"); + return; + } + strcpy (level, Cmd_Argv(1)); + +#if 0 + if (!strcmp (level, "e1m8")) + { // QuakeWorld can't go to e1m8 + SV_BroadcastPrintf (PRINT_HIGH, "can't go to low grav level in QuakeWorld...\n"); + strcpy (level, "e1m5"); + } +#endif + + // check to make sure the level exists + sprintf (expanded, "maps/%s.bsp", level); + COM_FOpenFile (expanded, &f); + if (!f) + { + Con_Printf ("Can't find %s\n", expanded); + return; + } + fclose (f); + + SV_BroadcastCommand ("changing\n"); + SV_SendMessagesToAll (); + + SV_SpawnServer (level); + + SV_BroadcastCommand ("reconnect\n"); +} + + +/* +================== +SV_Kick_f + +Kick a user off of the server +================== +*/ +void SV_Kick_f (void) +{ + int i; + client_t *cl; + int uid; + + uid = atoi(Cmd_Argv(1)); + + for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) + { + if (!cl->state) + continue; + if (cl->userid == uid) + { + SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", cl->name); + // print directly, because the dropped client won't get the + // SV_BroadcastPrintf message + SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game\n"); + SV_DropClient (cl); + return; + } + } + + Con_Printf ("Couldn't find user number %i\n", uid); +} + + +/* +================ +SV_Status_f +================ +*/ +void SV_Status_f (void) +{ + int i, j, l; + client_t *cl; + float cpu, avg, pak; + char *s; + + + cpu = (svs.stats.latched_active+svs.stats.latched_idle); + if (cpu) + cpu = 100*svs.stats.latched_active/cpu; + avg = 1000*svs.stats.latched_active / STATFRAMES; + pak = (float)svs.stats.latched_packets/ STATFRAMES; + + Con_Printf ("net address : %s\n",NET_AdrToString (net_local_adr)); + Con_Printf ("cpu utilization : %3i%%\n",(int)cpu); + Con_Printf ("avg response time: %i ms\n",(int)avg); + Con_Printf ("packets/frame : %5.2f (%d)\n", pak, num_prstr); + +// min fps lat drp + if (sv_redirected != RD_NONE) { + // most remote clients are 40 columns + // 0123456789012345678901234567890123456789 + Con_Printf ("name userid frags\n"); + Con_Printf (" address rate ping drop\n"); + Con_Printf (" ---------------- ---- ---- -----\n"); + for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) + { + if (!cl->state) + continue; + + Con_Printf ("%-16.16s ", cl->name); + + Con_Printf ("%6i %5i", cl->userid, (int)cl->edict->v.frags); + if (cl->spectator) + Con_Printf(" (s)\n"); + else + Con_Printf("\n"); + + s = NET_BaseAdrToString ( cl->netchan.remote_address); + Con_Printf (" %-16.16s", s); + if (cl->state == cs_connected) + { + Con_Printf ("CONNECTING\n"); + continue; + } + if (cl->state == cs_zombie) + { + Con_Printf ("ZOMBIE\n"); + continue; + } + Con_Printf ("%4i %4i %5.2f\n" + , (int)(1000*cl->netchan.frame_rate) + , (int)SV_CalcPing (cl) + , 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence); + } + } else { + Con_Printf ("frags userid address name rate ping drop qport\n"); + Con_Printf ("----- ------ --------------- --------------- ---- ---- ----- -----\n"); + for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) + { + if (!cl->state) + continue; + Con_Printf ("%5i %6i ", (int)cl->edict->v.frags, cl->userid); + + s = NET_BaseAdrToString ( cl->netchan.remote_address); + Con_Printf ("%s", s); + l = 16 - strlen(s); + for (j=0 ; j<l ; j++) + Con_Printf (" "); + + Con_Printf ("%s", cl->name); + l = 16 - strlen(cl->name); + for (j=0 ; j<l ; j++) + Con_Printf (" "); + if (cl->state == cs_connected) + { + Con_Printf ("CONNECTING\n"); + continue; + } + if (cl->state == cs_zombie) + { + Con_Printf ("ZOMBIE\n"); + continue; + } + Con_Printf ("%4i %4i %3.1f %4i" + , (int)(1000*cl->netchan.frame_rate) + , (int)SV_CalcPing (cl) + , 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence + , cl->netchan.qport); + if (cl->spectator) + Con_Printf(" (s)\n"); + else + Con_Printf("\n"); + + + } + } + Con_Printf ("\n"); +} + +/* +================== +SV_ConSay_f +================== +*/ +void SV_ConSay_f(void) +{ + client_t *client; + int j; + char *p; + char text[1024]; + + if (Cmd_Argc () < 2) + return; + + Q_strcpy (text, "console: "); + p = Cmd_Args(); + + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + + Q_strcat(text, p); + + for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) + { + if (client->state != cs_spawned) + continue; + SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text); + } +} + + +/* +================== +SV_Heartbeat_f +================== +*/ +void SV_Heartbeat_f (void) +{ + svs.last_heartbeat = -9999; +} + +void SV_SendServerInfoChange(char *key, char *value) +{ + if (!sv.state) + return; + + MSG_WriteByte (&sv.reliable_datagram, svc_serverinfo); + MSG_WriteString (&sv.reliable_datagram, key); + MSG_WriteString (&sv.reliable_datagram, value); +} + +/* +=========== +SV_Serverinfo_f + + Examine or change the serverinfo string +=========== +*/ +char *CopyString(char *s); +void SV_Serverinfo_f (void) +{ + cvar_t *var; + + if (Cmd_Argc() == 1) + { + Con_Printf ("Server info settings:\n"); + Info_Print (svs.info); + return; + } + + if (Cmd_Argc() != 3) + { + Con_Printf ("usage: serverinfo [ <key> <value> ]\n"); + return; + } + + if (Cmd_Argv(1)[0] == '*') + { + Con_Printf ("Star variables cannot be changed.\n"); + return; + } + Info_SetValueForKey (svs.info, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING); + + // if this is a cvar, change it too + var = Cvar_FindVar (Cmd_Argv(1)); + if (var) + { + Z_Free (var->string); // free the old value string + var->string = CopyString (Cmd_Argv(2)); + var->value = Q_atof (var->string); + } + + SV_SendServerInfoChange(Cmd_Argv(1), Cmd_Argv(2)); +} + + +/* +=========== +SV_Serverinfo_f + + Examine or change the serverinfo string +=========== +*/ +char *CopyString(char *s); +void SV_Localinfo_f (void) +{ + if (Cmd_Argc() == 1) + { + Con_Printf ("Local info settings:\n"); + Info_Print (localinfo); + return; + } + + if (Cmd_Argc() != 3) + { + Con_Printf ("usage: localinfo [ <key> <value> ]\n"); + return; + } + + if (Cmd_Argv(1)[0] == '*') + { + Con_Printf ("Star variables cannot be changed.\n"); + return; + } + Info_SetValueForKey (localinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_LOCALINFO_STRING); +} + + +/* +=========== +SV_User_f + +Examine a users info strings +=========== +*/ +void SV_User_f (void) +{ + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: info <userid>\n"); + return; + } + + if (!SV_SetPlayer ()) + return; + + Info_Print (host_client->userinfo); +} + +/* +================ +SV_Gamedir + +Sets the fake *gamedir to a different directory. +================ +*/ +void SV_Gamedir (void) +{ + char *dir; + + if (Cmd_Argc() == 1) + { + Con_Printf ("Current *gamedir: %s\n", Info_ValueForKey (svs.info, "*gamedir")); + return; + } + + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: sv_gamedir <newgamedir>\n"); + return; + } + + dir = Cmd_Argv(1); + + if (strstr(dir, "..") || strstr(dir, "/") + || strstr(dir, "\\") || strstr(dir, ":") ) + { + Con_Printf ("*Gamedir should be a single filename, not a path\n"); + return; + } + + Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); +} + +/* +================ +SV_Floodport_f + +Sets the gamedir and path to a different directory. +================ +*/ + +void SV_Floodprot_f (void) +{ + int arg1, arg2, arg3; + + if (Cmd_Argc() == 1) + { + if (fp_messages) { + Con_Printf ("Current floodprot settings: \nAfter %d msgs per %d seconds, silence for %d seconds\n", + fp_messages, fp_persecond, fp_secondsdead); + return; + } else + Con_Printf ("No floodprots enabled.\n"); + } + + if (Cmd_Argc() != 4) + { + Con_Printf ("Usage: floodprot <# of messages> <per # of seconds> <seconds to silence>\n"); + Con_Printf ("Use floodprotmsg to set a custom message to say to the flooder.\n"); + return; + } + + arg1 = atoi(Cmd_Argv(1)); + arg2 = atoi(Cmd_Argv(2)); + arg3 = atoi(Cmd_Argv(3)); + + if (arg1<=0 || arg2 <= 0 || arg3<=0) { + Con_Printf ("All values must be positive numbers\n"); + return; + } + + if (arg1 > 10) { + Con_Printf ("Can only track up to 10 messages.\n"); + return; + } + + fp_messages = arg1; + fp_persecond = arg2; + fp_secondsdead = arg3; +} + +void SV_Floodprotmsg_f (void) +{ + if (Cmd_Argc() == 1) { + Con_Printf("Current msg: %s\n", fp_msg); + return; + } else if (Cmd_Argc() != 2) { + Con_Printf("Usage: floodprotmsg \"<message>\"\n"); + return; + } + sprintf(fp_msg, "%s", Cmd_Argv(1)); +} + +/* +================ +SV_Gamedir_f + +Sets the gamedir and path to a different directory. +================ +*/ +char gamedirfile[MAX_OSPATH]; +void SV_Gamedir_f (void) +{ + char *dir; + + if (Cmd_Argc() == 1) + { + Con_Printf ("Current gamedir: %s\n", com_gamedir); + return; + } + + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: gamedir <newdir>\n"); + return; + } + + dir = Cmd_Argv(1); + + if (strstr(dir, "..") || strstr(dir, "/") + || strstr(dir, "\\") || strstr(dir, ":") ) + { + Con_Printf ("Gamedir should be a single filename, not a path\n"); + return; + } + + COM_Gamedir (dir); + Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); +} + +/* +================ +SV_Snap +================ +*/ +void SV_Snap (int uid) +{ + client_t *cl; + char pcxname[80]; + char checkname[MAX_OSPATH]; + int i; + + for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) + { + if (!cl->state) + continue; + if (cl->userid == uid) + break; + } + if (i >= MAX_CLIENTS) { + Con_Printf ("userid not found\n"); + return; + } + + sprintf(pcxname, "%d-00.pcx", uid); + + sprintf(checkname, "%s/snap", gamedirfile); + Sys_mkdir(gamedirfile); + Sys_mkdir(checkname); + + for (i=0 ; i<=99 ; i++) + { + pcxname[strlen(pcxname) - 6] = i/10 + '0'; + pcxname[strlen(pcxname) - 5] = i%10 + '0'; + sprintf (checkname, "%s/snap/%s", gamedirfile, pcxname); + if (Sys_FileTime(checkname) == -1) + break; // file doesn't exist + } + if (i==100) + { + Con_Printf ("Snap: Couldn't create a file, clean some out.\n"); + return; + } + strcpy(cl->uploadfn, checkname); + + memcpy(&cl->snap_from, &net_from, sizeof(net_from)); + if (sv_redirected != RD_NONE) + cl->remote_snap = true; + else + cl->remote_snap = false; + + ClientReliableWrite_Begin (cl, svc_stufftext, 24); + ClientReliableWrite_String (cl, "cmd snap"); + Con_Printf ("Requesting snap from user %d...\n", uid); +} + +/* +================ +SV_Snap_f +================ +*/ +void SV_Snap_f (void) +{ + int uid; + + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: snap <userid>\n"); + return; + } + + uid = atoi(Cmd_Argv(1)); + + SV_Snap(uid); +} + +/* +================ +SV_Snap +================ +*/ +void SV_SnapAll_f (void) +{ + client_t *cl; + int i; + + for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) + { + if (cl->state < cs_connected || cl->spectator) + continue; + SV_Snap(cl->userid); + } +} + +/* +================== +SV_InitOperatorCommands +================== +*/ +void SV_InitOperatorCommands (void) +{ + if (COM_CheckParm ("-cheats")) + { + sv_allow_cheats = true; + Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); + } + + Cmd_AddCommand ("logfile", SV_Logfile_f); + Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f); + + Cmd_AddCommand ("snap", SV_Snap_f); + Cmd_AddCommand ("snapall", SV_SnapAll_f); + Cmd_AddCommand ("kick", SV_Kick_f); + Cmd_AddCommand ("status", SV_Status_f); + + Cmd_AddCommand ("map", SV_Map_f); + Cmd_AddCommand ("setmaster", SV_SetMaster_f); + + Cmd_AddCommand ("say", SV_ConSay_f); + Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); + Cmd_AddCommand ("quit", SV_Quit_f); + Cmd_AddCommand ("god", SV_God_f); + Cmd_AddCommand ("give", SV_Give_f); + Cmd_AddCommand ("noclip", SV_Noclip_f); + Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); + Cmd_AddCommand ("localinfo", SV_Localinfo_f); + Cmd_AddCommand ("user", SV_User_f); + Cmd_AddCommand ("gamedir", SV_Gamedir_f); + Cmd_AddCommand ("sv_gamedir", SV_Gamedir); + Cmd_AddCommand ("floodprot", SV_Floodprot_f); + Cmd_AddCommand ("floodprotmsg", SV_Floodprotmsg_f); + + cl_warncmd.value = 1; +} |
