void Cbuf_Execute(void) { int i; char *text; char line[1024]; int quotes; alias_count = 0; /* don't allow infinite alias loops */ while (cmd_text.cursize) { /* find a \n or ; line break */ text = (char *)cmd_text.data; quotes = 0; for (i = 0; i < cmd_text.cursize; i++) { if (text[i] == '"') { quotes++; } if (!(quotes & 1) && (text[i] == ';')) { break; /* don't break if inside a quoted string */ } if (text[i] == '\n') { break; } } if (i > sizeof(line) - 1) { memcpy(line, text, sizeof(line) - 1); line[sizeof(line) - 1] = 0; } else { memcpy(line, text, i); line[i] = 0; } /* delete the text from the command buffer and move remaining commands down this is necessary because commands (exec, alias) can insert data at the beginning of the text buffer */ if (i == cmd_text.cursize) { cmd_text.cursize = 0; } else { i++; cmd_text.cursize -= i; memmove(text, text + i, cmd_text.cursize); } /* execute the command line */ Cmd_ExecuteString(line); if (cmd_wait) { /* skip out while text still remains in buffer, leaving it for next frame */ cmd_wait = false; break; } } }
void Cmd_ExecuteSingleCommand(int arg1, int arg2, const char* text) { Cmd_ExecuteString(text); }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute (void) { int i; char *text; char line[MAX_CMD_LINE]; int quotes; // This will keep // style comments all on one line by not breaking on // a semicolon. It will keep /* ... */ style comments all on one line by not // breaking it for semicolon or newline. qboolean in_star_comment = qfalse; qboolean in_slash_comment = qfalse; while (cmd_text.cursize) { if ( cmd_wait > 0 ) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; break; } // find a \n or ; line break or comment: // or /* */ text = (char *)cmd_text.data; quotes = 0; for (i=0 ; i< cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1)) { if (i < cmd_text.cursize - 1) { if (! in_star_comment && text[i] == '/' && text[i+1] == '/') in_slash_comment = qtrue; else if (! in_slash_comment && text[i] == '/' && text[i+1] == '*') in_star_comment = qtrue; else if (in_star_comment && text[i] == '*' && text[i+1] == '/') { in_star_comment = qfalse; // If we are in a star comment, then the part after it is valid // Note: This will cause it to NUL out the terminating '/' // but ExecuteString doesn't require it anyway. i++; break; } } if (! in_slash_comment && ! in_star_comment && text[i] == ';') break; } if (! in_star_comment && (text[i] == '\n' || text[i] == '\r')) { in_slash_comment = qfalse; break; } } if( i >= (MAX_CMD_LINE - 1)) { i = MAX_CMD_LINE - 1; } Com_Memcpy (line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) cmd_text.cursize = 0; else { i++; cmd_text.cursize -= i; memmove (text, text+i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line); } }
/* ** GLimp_Init ** ** This is the platform specific OpenGL initialization function. It ** is responsible for loading OpenGL, initializing it, setting ** extensions, creating a window of the appropriate size, doing ** fullscreen manipulations, etc. Its overall responsibility is ** to make sure that a functional OpenGL subsystem is operating ** when it returns to the ref. */ void GLimp_Init( void ) { char buf[1024]; cvar_t *lastValidRenderer = Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); cvar_t *cv; VID_Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" ); //glConfig.deviceSupportsGamma = qfalse; InitSig(); //r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); // load appropriate DLL and initialize subsystem GLW_StartOpenGL(); // get our config strings glConfig.vendor_string = (const char *) qglGetString (GL_VENDOR); glConfig.renderer_string = (const char *) qglGetString (GL_RENDERER); glConfig.version_string = (const char *) qglGetString (GL_VERSION); glConfig.extensions_string = (const char *) qglGetString (GL_EXTENSIONS); if (!glConfig.vendor_string || !glConfig.renderer_string || !glConfig.version_string || !glConfig.extensions_string) { Com_Error( ERR_FATAL, "GLimp_Init() - Invalid GL Driver\n" ); } // OpenGL driver constants qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize ); // stubbed or broken drivers may have reported 0... if ( glConfig.maxTextureSize <= 0 ) { glConfig.maxTextureSize = 1024; } // // chipset specific configuration // strcpy( buf, glConfig.renderer_string ); strlwr( buf ); // // NOTE: if changing cvars, do it within this block. This allows them // to be overridden when testing driver fixes, etc. but only sets // them to their default state when the hardware is first installed/run. // if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { //reset to defaults Cvar_Set( "r_picmip", "1" ); if ( strstr( buf, "matrox" )) { Cvar_Set( "r_allowExtensions", "0"); } Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); if ( strstr( buf, "intel" ) ) { // disable dynamic glow as default Cvar_Set( "r_DynamicGlow","0" ); } if ( strstr( buf, "kyro" ) ) { Cvar_Set( "r_ext_texture_filter_anisotropic", "0"); //KYROs have it avail, but suck at it! Cvar_Set( "r_ext_preferred_tc_method", "1"); //(Use DXT1 instead of DXT5 - same quality but much better performance on KYRO) } GLW_InitExtensions(); //this must be a really sucky card! if ( (glConfig.textureCompression == TC_NONE) || (glConfig.maxActiveTextures < 2) || (glConfig.maxTextureSize <= 512) ) { Cvar_Set( "r_picmip", "2"); Cvar_Set( "r_colorbits", "16"); Cvar_Set( "r_texturebits", "16"); Cvar_Set( "r_mode", "3"); //force 640 Cmd_ExecuteString ("exec low.cfg\n"); //get the rest which can be pulled in after init } } Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); LOGI("Force PICMIP"); Cvar_Set( "r_picmip", "2"); //Force to 2 GLW_InitExtensions(); //InitSig(); }
/* ================= VM_LoadQVM Load a .qvm file ================= */ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { int dataLength; int i; char filename[MAX_QPATH]; union { vmHeader_t *h; void *v; } header; // load the image Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name ); Com_Printf( "Loading vm file %s...\n", filename ); FS_ReadFile( filename, &header.v ); if ( !header.h ) { Com_Printf( "Failed.\n" ); VM_Free( vm ); return NULL; } // show where the qvm was loaded from Cmd_ExecuteString( va( "which %s\n", filename ) ); if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) { Com_DPrintf( "...which has vmMagic VM_MAGIC_VER2\n" ); // byte swap the header for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) { ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] ); } // validate if ( header.h->jtrgLength < 0 || header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 || header.h->codeLength <= 0 ) { VM_Free( vm ); Com_Error( ERR_FATAL, "%s has bad header", filename ); } } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) { // byte swap the header // sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) { ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] ); } // validate if ( header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 || header.h->codeLength <= 0 ) { VM_Free( vm ); Com_Error( ERR_FATAL, "%s has bad header", filename ); } } else { VM_Free( vm ); Com_Error( ERR_FATAL, "%s does not have a recognisable " "magic number in its header", filename ); } // round up to next power of 2 so all data operations can // be mask protected dataLength = header.h->dataLength + header.h->litLength + header.h->bssLength; for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) { } dataLength = 1 << i; if( alloc ) { // allocate zero filled space for initialized and uninitialized data vm->dataBase = Hunk_Alloc( dataLength, h_high ); vm->dataMask = dataLength - 1; } else { // clear the data Com_Memset( vm->dataBase, 0, dataLength ); } // copy the intialized data Com_Memcpy( vm->dataBase, (byte *)header.h + header.h->dataOffset, header.h->dataLength + header.h->litLength ); // byte swap the longs for ( i = 0 ; i < header.h->dataLength ; i += 4 ) { *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) ); } if( header.h->vmMagic == VM_MAGIC_VER2 ) { vm->numJumpTableTargets = header.h->jtrgLength >> 2; Com_DPrintf( "Loading %d jump table targets\n", vm->numJumpTableTargets ); if( alloc ) { vm->jumpTableTargets = Hunk_Alloc( header.h->jtrgLength, h_high ); } else { Com_Memset( vm->jumpTableTargets, 0, header.h->jtrgLength ); } Com_Memcpy( vm->jumpTableTargets, (byte *)header.h + header.h->dataOffset + header.h->dataLength + header.h->litLength, header.h->jtrgLength ); // byte swap the longs for ( i = 0 ; i < header.h->jtrgLength ; i += 4 ) { *(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) ); } }
/* ==================== CL_Record_f record <demoname> <map> [cd track] ==================== */ void CL_Record_f (void) { int c; char name[MAX_OSPATH]; int track; if (cmd_source != src_command) return; c = Cmd_Argc(); if (c != 2 && c != 3 && c != 4) { Con_Printf ("record <demoname> [<map> [cd track]]\n"); return; } if (strstr(Cmd_Argv(1), "..")) { Con_Printf ("Relative pathnames are not allowed.\n"); return; } if (c == 2 && cls.state == ca_connected) { Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); return; } // write the forced cd track number, or -1 if (c == 4) { track = atoi(Cmd_Argv(3)); Con_Printf ("Forcing CD track to %i\n", cls.forcetrack); } else track = -1; sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); // // start the map up // if (c > 2) Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command); // // open the demo file // COM_DefaultExtension (name, ".dem"); Con_Printf ("recording to %s.\n", name); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Con_Printf ("ERROR: couldn't open.\n"); return; } cls.forcetrack = track; fprintf (cls.demofile, "%i\n", cls.forcetrack); cls.demorecording = true; }
/* ================= Host_Main ================= */ int EXPORT Host_Main( int argc, const char **argv, const char *progname, int bChangeGame, pfnChangeGame func ) { static double oldtime, newtime; #ifdef XASH_SDL SDL_Event event; #endif pChangeGame = func; // may be NULL Host_InitCommon( argc, argv, progname, bChangeGame ); // init commands and vars if( host.developer >= 3 ) { Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures"); Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures"); Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons"); Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place"); } host_cheats = Cvar_Get( "sv_cheats", "0", CVAR_LATCH, "allow usage of cheat commands and variables" ); host_maxfps = Cvar_Get( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" ); host_sleeptime = Cvar_Get( "sleeptime", "1", CVAR_ARCHIVE, "higher value means lower accuracy" ); host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" ); host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_INIT, "displays current server state" ); host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "indicates a loaded game library" ); host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "indicates a loaded client library" ); host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" ); con_gamemaps = Cvar_Get( "con_mapfilter", "1", CVAR_ARCHIVE, "when enabled, show only maps in game folder (no maps from base folder when running mod)" ); download_types = Cvar_Get( "download_types", "msec", CVAR_ARCHIVE, "list of types to download: Model, Sounds, Events, Custom" ); build = Cvar_Get( "build", va( "%i", Q_buildnum()), CVAR_INIT, "returns a current build number" ); ver = Cvar_Get( "ver", va( "%i/%s.%i", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ) ), CVAR_INIT, "shows an engine version" ); host_mapdesign_fatal = Cvar_Get( "host_mapdesign_fatal", "1", CVAR_ARCHIVE, "make map design errors fatal" ); host_xashds_hacks = Cvar_Get( "xashds_hacks", "0", 0, "hacks for xashds in singleplayer" ); // content control Cvar_Get( "violence_hgibs", "1", CVAR_ARCHIVE, "show human gib entities" ); Cvar_Get( "violence_agibs", "1", CVAR_ARCHIVE, "show alien gib entities" ); Cvar_Get( "violence_hblood", "1", CVAR_ARCHIVE, "draw human blood" ); Cvar_Get( "violence_ablood", "1", CVAR_ARCHIVE, "draw alien blood" ); if( host.type != HOST_DEDICATED ) { // when we're in developer-mode, automatically turn cheats on if( host.developer > 1 ) Cvar_SetFloat( "sv_cheats", 1.0f ); Cbuf_AddText( "exec video.cfg\n" ); } Mod_Init(); NET_Init(); Netchan_Init(); // allow to change game from the console if( pChangeGame != NULL ) { Cmd_AddCommand( "game", Host_ChangeGame_f, "change active game/mod" ); Cvar_Get( "host_allow_changegame", "1", CVAR_READ_ONLY, "whether changing game/mod is allowed" ); } else { Cvar_Get( "host_allow_changegame", "0", CVAR_READ_ONLY, "allows to change games" ); } SV_Init(); CL_Init(); HTTP_Init(); // post initializations switch( host.type ) { case HOST_NORMAL: Con_ShowConsole( false ); // hide console // execute startup config and cmdline Cbuf_AddText( va( "exec %s.rc\n", SI.ModuleName )); // intentional fallthrough case HOST_DEDICATED: // if stuffcmds wasn't run, then init.rc is probably missing, use default if( !host.stuffcmdsrun ) Cbuf_AddText( "stuffcmds\n" ); Cbuf_Execute(); break; case HOST_UNKNOWN: break; } if( host.type == HOST_DEDICATED ) { char *defaultmap; Con_InitConsoleCommands (); Cmd_AddCommand( "quit", Sys_Quit, "quit the game" ); Cmd_AddCommand( "exit", Sys_Quit, "quit the game" ); SV_InitGameProgs(); Cbuf_AddText( "exec config.cfg\n" ); // dedicated servers are using settings from server.cfg file Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" ))); Cbuf_Execute(); defaultmap = Cvar_VariableString( "defaultmap" ); if( !defaultmap[0] ) Msg( "Please add \"defaultmap\" cvar with default map name to your server.cfg!\n" ); else Cbuf_AddText( va( "map %s\n", defaultmap )); Cvar_FullSet( "xashds_hacks", "0", CVAR_READ_ONLY ); NET_Config( true ); } else { Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to taskbar" ); Cbuf_AddText( "exec config.cfg\n" ); // listenserver/multiplayer config. // need load it to update menu options. Cbuf_AddText( "exec game.cfg\n" ); } host.errorframe = 0; Cbuf_Execute(); host.change_game = false; // done Cmd_RemoveCommand( "setr" ); // remove potential backdoor for changing renderer settings Cmd_RemoveCommand( "setgl" ); // we need to execute it again here if( host.type != HOST_DEDICATED ) Cmd_ExecuteString( "exec config.cfg\n", src_command ); // exec all files from userconfig.d Host_Userconfigd_f(); oldtime = Sys_DoubleTime(); IN_TouchInitConfig(); SCR_CheckStartupVids(); // must be last #ifdef XASH_SDL SDL_StopTextInput(); // disable text input event. Enable this in chat/console? #endif if( host.state == HOST_INIT ) host.state = HOST_FRAME; // initialization is finished // main window message loop while( !host.crashed && !host.shutdown_issued ) { #ifdef XASH_SDL while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) ) SDLash_EventFilter( &event ); #endif newtime = Sys_DoubleTime (); Host_Frame( newtime - oldtime ); oldtime = newtime; } // never reached return 0; }
void SystemWrapper::ExecuteFile(char *filename) { char cmd[1024]; Q_snprintf(cmd, sizeof(cmd), "exec %s\n", filename); Cmd_ExecuteString(cmd, src_command); }
bool Server::read_client_message(Client *client) { NetBuffer *msg = client->m_netconnection->m_receiveMessage; char *s; int ret; do { if (msg->pos() == 0 || msg->read_pos() == msg->pos()) { break; } int r = msg->read_byte(); if (r == -1) { return false; } int len = msg->read_short(); /*int skip = */msg->read_byte(); int end = msg->read_pos() + len; do { if (len == 0 || !client->is_active()) { return false; } int cmd = msg->read_byte(); //check end of message if (cmd == -1) { break; } switch (cmd) { case -1: //goto nextmsg; // end of message default: printf("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: printf("clc_nop\n"); break; case clc_stringcmd: s = msg->read_string(); ret = 0; if (strncasecmp(s, "status", 6) == 0) ret = 1; else if (strncasecmp(s, "god", 3) == 0) ret = 1; else if (strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (strncasecmp(s, "fly", 3) == 0) ret = 1; else if (strncasecmp(s, "name", 4) == 0) ret = 1; else if (strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (strncasecmp(s, "create", 6) == 0) ret = 1; else if (strncasecmp(s, "say", 3) == 0) ret = 1; else if (strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (strncasecmp(s, "tell", 4) == 0) ret = 1; else if (strncasecmp(s, "color", 5) == 0) ret = 1; else if (strncasecmp(s, "kill", 4) == 0) ret = 1; else if (strncasecmp(s, "pause", 5) == 0) ret = 1; else if (strncasecmp(s, "spawn", 5) == 0) { ret = 1; } else if (strncasecmp(s, "begin", 5) == 0) { ret = 1; client->m_spawned = true; break; } else if (strncasecmp(s, "prespawn", 8) == 0) { ret = 1; } else if (strncasecmp(s, "kick", 4) == 0) ret = 1; else if (strncasecmp(s, "ping", 4) == 0) ret = 1; else if (strncasecmp(s, "give", 4) == 0) ret = 1; if (ret == 2) Cbuf_InsertText(s); else if (ret == 1) { m_cmds.call(s, client); Cmd_ExecuteString(s, src_client); } else printf("%s tried to %s\n", client->m_name, s); break; case clc_disconnect: printf("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: read_client_move(client); break; } } while (msg->read_pos() < end); //read alignment bytes while (msg->read_pos() & 0x3) { msg->read_byte(); } //break; } while (1); client->m_netconnection->clear(); return true; }
/* ==================== CL_Record_f record <demoname> <map> [cd track] ==================== */ void CL_Record_f (void) { int c, track; char name[MAX_OSPATH]; char vabuf[1024]; c = Cmd_Argc(); if (c != 2 && c != 3 && c != 4) { Con_Print("record <demoname> [<map> [cd track]]\n"); return; } if (strstr(Cmd_Argv(1), "..")) { Con_Print("Relative pathnames are not allowed.\n"); return; } if (c == 2 && cls.state == ca_connected) { Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); return; } if (cls.state == ca_connected) CL_Disconnect(); // write the forced cd track number, or -1 if (c == 4) { track = atoi(Cmd_Argv(3)); Con_Printf("Forcing CD track to %i\n", cls.forcetrack); } else track = -1; // get the demo name strlcpy (name, Cmd_Argv(1), sizeof (name)); FS_DefaultExtension (name, ".dem", sizeof (name)); // start the map up if (c > 2) Cmd_ExecuteString ( va(vabuf, sizeof(vabuf), "map %s", Cmd_Argv(2)), src_command, false); // open the demo file Con_Printf("recording to %s.\n", name); cls.demofile = FS_OpenRealFile(name, "wb", false); if (!cls.demofile) { Con_Print("ERROR: couldn't open.\n"); return; } strlcpy(cls.demoname, name, sizeof(cls.demoname)); cls.forcetrack = track; FS_Printf(cls.demofile, "%i\n", cls.forcetrack); cls.demorecording = true; cls.demo_lastcsprogssize = -1; cls.demo_lastcsprogscrc = -1; }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand(netadr_t from, msg_t * msg) { bool valid; unsigned int time; char remaining[1024]; // show_bug.cgi?id=376 // if we send an OOB print message this size, 1.31 clients die in a Com_Printf buffer overflow // the buffer overflow will be fixed in > 1.31 clients // but we want a server side fix // we must NEVER send an OOB message that will be > 1.31 MAXPRINTMSG (4096) #define SV_OUTPUTBUF_LENGTH ( 256 - 16 ) char sv_outputbuf[SV_OUTPUTBUF_LENGTH], *cmd_aux; static unsigned int lasttime = 0; // TTimo - show_bug.cgi?id=534 time = Com_Milliseconds(); // Do we have a whitelist for rcon? if(sv_WhiteListRcon->string && *sv_WhiteListRcon->string) { // Prevent use of rcon from addresses that have not been whitelisted if(!SV_IsRconWhitelisted(&from)) { Com_Printf( "SVC_RemoteCommand: attempt from %s who is not whitelisted\n", NET_AdrToString( from ) ); NET_OutOfBandPrint(NS_SERVER, from, "print\nClient not found whitelist data.\n"); SV_DropClientsByAddress(&from, "Client tried to access to RCON password."); return; } } if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { // MaJ - If the rconpassword is bad and one just happned recently, don't spam the log file, just die. if ( (unsigned)( time - lasttime ) < 500u ) { return; } valid = false; Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } else { // MaJ - If the rconpassword is good, allow it much sooner than a bad one. if ( (unsigned)( time - lasttime ) < 200u ) { return; } valid = true; Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } lasttime = time; // start redirecting all print outputs to the packet svs.redirectAddress = from; // FIXME TTimo our rcon redirection could be improved // big rcon commands such as status lead to sending // out of band packets on every single call to Com_Printf // which leads to client overflows // see show_bug.cgi?id=51 // (also a Q3 issue) Com_BeginRedirect(sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if(!strlen(sv_rconPassword->string)) { Com_Printf("No rconpassword set on the server.\n"); } else if(!valid) { Com_Printf("Bad rconpassword.\n"); } else { remaining[0] = 0; // ATVI Wolfenstein Misc #284 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux += 4; while(cmd_aux[0] == ' ') { cmd_aux++; } while(cmd_aux[0] && cmd_aux[0] != ' ') { // password cmd_aux++; } while(cmd_aux[0] == ' ') { cmd_aux++; } Q_strcat(remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString(remaining); } Com_EndRedirect(); }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 // I believe that this code (and the dead link above) are to address a brute // force attack that guesses the rcon password. time = Com_Milliseconds(); if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { if ( (unsigned)( time - lasttime ) < 500u ) { return; } valid = qfalse; if (sv_logRconArgs->integer > 0) { Com_Printf("Bad rcon from %s\n", NET_AdrToString(from)); } else { Com_Printf("Bad rcon from %s:\n%s\n", NET_AdrToString(from), Cmd_Argv(2)); } } else { if (!Sys_IsLANAddress(from) && (unsigned) (time - lasttime) < 100u) { return; } valid = qtrue; remaining[0] = 0; // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux+=4; while(cmd_aux[0]==' ') cmd_aux++; while(cmd_aux[0] && cmd_aux[0]!=' ') // password cmd_aux++; while(cmd_aux[0]==' ') cmd_aux++; Q_strcat( remaining, sizeof(remaining), cmd_aux); if (sv_logRconArgs->integer > 0) { Com_Printf("Rcon from %s: %s\n", NET_AdrToString(from), remaining); } else { Com_Printf("Rcon from %s:\n%s\n", NET_AdrToString(from), Cmd_Argv(2)); } } lasttime = time; // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf ("No rconpassword set on the server.\n"); } else if ( !valid ) { Com_Printf ("Bad rconpassword.\n"); } else { Cmd_ExecuteString (remaining); } Com_EndRedirect (); }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute(void) { int i; char *text; char line[MAX_CMD_LINE]; int quotes; while(cmd_text.cursize) { if(cmd_wait) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; break; } // find a \n or ; line break text = (char *)cmd_text.data; quotes = 0; for(i = 0; i < cmd_text.cursize; i++) { if(text[i] == '\\' && text[i+1] == '"') { i++; continue; } if(text[i] == '"') { quotes++; } if(!(quotes & 1) && text[i] == ';') { break; // don't break if inside a quoted string } if(text[i] == '\n' || text[i] == '\r') { break; } } if(i >= (MAX_CMD_LINE - 1)) { i = MAX_CMD_LINE - 1; } memcpy(line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if(i == cmd_text.cursize) { cmd_text.cursize = 0; } else { i++; cmd_text.cursize -= i; memmove(text, text + i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString(line); } }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (net_message); while (1) { if (!host_client->active) return false; // a command caused an error if (net_message->badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (net_message); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("SV_ReadClientMessage: clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (net_message); ret = 0; if (nehahra) { if (strncasecmp(s, "max", 3) == 0) ret = 1; else if (strncasecmp(s, "monster", 7) == 0) ret = 1; else if (strncasecmp(s, "scrag", 5) == 0) ret = 1; else if (strncasecmp(s, "wraith", 6) == 0) ret = 1; else if (strncasecmp(s, "gimme", 5) == 0) ret = 1; } else { if (strncasecmp(s, "god", 3) == 0) ret = 1; else if (strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (strncasecmp(s, "fly", 3) == 0) ret = 1; else if (strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (strncasecmp(s, "give", 4) == 0) ret = 1; } if (strncasecmp(s, "status", 6) == 0) ret = 1; else if (strncasecmp(s, "freezeall", 9) == 0) ret = 1; else if (strncasecmp(s, "name", 4) == 0) ret = 1; else if (strncasecmp(s, "say", 3) == 0) ret = 1; else if (strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (strncasecmp(s, "tell", 4) == 0) ret = 1; else if (strncasecmp(s, "color", 5) == 0) ret = 1; else if (strncasecmp(s, "kill", 4) == 0) ret = 1; else if (strncasecmp(s, "pause", 5) == 0) ret = 1; else if (strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (strncasecmp(s, "begin", 5) == 0) ret = 1; else if (strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (strncasecmp(s, "kick", 4) == 0) ret = 1; else if (strncasecmp(s, "ping", 4) == 0) ret = 1; else if (strncasecmp(s, "ban", 3) == 0) ret = 1; else if (strncasecmp(s, "qcexec", 6) == 0) ret = 1; // qcexec command for qc testing if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute (void) { int i; char *text; char line[MAX_CMD_LINE]; int quotes; #ifdef _XBOX if(ClientManager::splitScreenMode == qtrue) { CM_START_LOOP(); while (ClientManager::ActiveClient().cmd_text.cursize) { if ( ClientManager::ActiveClient().cmd_wait ) { // skip out while text still remains in buffer, leaving it // for next frame ClientManager::ActiveClient().cmd_wait--; break; } // find a \n or ; line break text = (char *)ClientManager::ActiveClient().cmd_text.data; quotes = 0; for (i=0 ; i< ClientManager::ActiveClient().cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n' || text[i] == '\r' ) break; } memcpy (line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == ClientManager::ActiveClient().cmd_text.cursize) ClientManager::ActiveClient().cmd_text.cursize = 0; else { i++; ClientManager::ActiveClient().cmd_text.cursize -= i; memmove (text, text+i, ClientManager::ActiveClient().cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line); } CM_END_LOOP(); } else { #endif while (cmd_text.cursize) { if ( cmd_wait ) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; break; } // find a \n or ; line break text = (char *)cmd_text.data; quotes = 0; for (i=0 ; i< cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n' || text[i] == '\r' ) break; } if( i >= (MAX_CMD_LINE - 1)) { i = MAX_CMD_LINE - 1; } Com_Memcpy (line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) cmd_text.cursize = 0; else { i++; cmd_text.cursize -= i; memmove (text, text+i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line); } #ifdef _XBOX } #endif }
// enables renderer support for the Rift void R_VR_Enable() { qboolean success = false; screen.width = 0; screen.height = 0; leftStale = 1; rightStale = 1; hudStale = 1; if (glConfig.ext_framebuffer_object && glConfig.ext_packed_depth_stencil) { Com_Printf("VR: Initializing renderer:"); // TODO: conditional this shit up if (hud.valid) R_DelFBO(&hud); hmd = &available_hmds[(int32_t) vr_enabled->value]; success = R_GenFBO(640,480,1,GL_RGBA8,&hud); success = success && hmd->enable && hmd->enable(); // shader init R_VR_InitDistortionShader(&vr_distort_shaders[0], &vr_shader_distort_norm); R_VR_InitDistortionShader(&vr_distort_shaders[1], &vr_shader_distort_chrm); if (!success) { Com_Printf(" failed!\n"); Cmd_ExecuteString("vr_disable"); } else { char string[6]; Com_Printf(" ok!\n"); hmd->getState(&vrState); //strncpy(string, va("%.2f", vrState.ipd * 1000), sizeof(string)); vr_ipd = Cvar_Get("vr_ipd", string, CVAR_ARCHIVE); if (vr_ipd->value < 0) Cvar_SetToDefault("vr_ipd"); } R_CreateIVBO(&hudVBO, GL_STATIC_DRAW); R_VR_GenerateHud(); } else { Com_Printf("VR: Cannot initialize renderer due to missing OpenGL extensions\n"); if (vr_enabled->value) { Cmd_ExecuteString("vr_disable"); } } R_VR_StartFrame(); }
void SV_Status_f (void) { int i, j, l; client_t *cl; float cpu, avg, pak; char *s; #ifndef SERVERONLY // some mods use a "status" alias for their own needs, sigh if (!sv_redirected && !strcasecmp(Cmd_Argv(0), "status") && CL_ClientState() && Cmd_FindAlias("status")) { Cmd_ExecuteString (Cmd_AliasString("status")); return; } #endif 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; if (svs.socketip != INVALID_SOCKET && net_local_sv_ipadr.type != NA_LOOPBACK) Com_Printf ("ip address : %s\n",NET_AdrToString (net_local_sv_ipadr)); // TCPCONNECT --> if (svs.sockettcp != INVALID_SOCKET && net_local_sv_tcpipadr.type != NA_LOOPBACK) Com_Printf ("tcp address : %s\n",NET_AdrToString (net_local_sv_tcpipadr)); // <-- TCPCONNECT Com_Printf ("cpu utilization : %3i%%\n",(int)cpu); Com_Printf ("avg response time: %i ms\n",(int)avg); Com_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 Com_Printf ("name userid frags\n"); Com_Printf (" address rate ping drop\n"); Com_Printf (" ---------------- ---- ---- -----\n"); for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (!cl->state) continue; Com_Printf ("%-16.16s ", cl->name); Com_Printf ("%6i %5i", cl->userid, (int)cl->edict->v.frags); if (cl->spectator) Com_Printf (" (s)\n"); else Com_Printf ("\n"); s = NET_BaseAdrToString ( cl->netchan.remote_address); Com_Printf (" %-16.16s", s); if (cl->state == cs_connected) { Com_Printf ("CONNECTING\n"); continue; } if (cl->state == cs_zombie) { Com_Printf ("ZOMBIE\n"); continue; } Com_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 { Com_Printf ("frags userid address name rate ping drop qport\n"); Com_Printf ("----- ------ --------------- --------------- ---- ---- ----- -----\n"); for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (!cl->state) continue; Com_Printf ("%5i %6i ", (int)cl->edict->v.frags, cl->userid); s = NET_BaseAdrToString ( cl->netchan.remote_address); Com_Printf ("%s", s); l = 16 - strlen(s); for (j = 0; j < l; j++) Com_Printf (" "); Com_Printf ("%s", cl->name); l = 16 - strlen(cl->name); for (j = 0; j < l; j++) Com_Printf (" "); if (cl->state == cs_connected) { Com_Printf ("CONNECTING\n"); continue; } if (cl->state == cs_zombie) { Com_Printf ("ZOMBIE\n"); continue; } Com_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) Com_Printf (" (s)\n"); else Com_Printf ("\n"); } } Com_Printf ("\n"); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ qboolean SV_SpawnServer( const char *mapname, const char *startspot ) { int i, current_skill; qboolean loadgame, paused; qboolean background, changelevel; // save state loadgame = sv.loadgame; background = sv.background; changelevel = sv.changelevel; paused = sv.paused; if( sv.state == ss_dead ) SV_InitGame(); // the game is just starting else if( !sv_maxclients->modified ) Cmd_ExecuteString( "latch\n", src_command ); else MsgDev( D_ERROR, "SV_SpawnServer: while 'maxplayers' was modified.\n" ); sv_maxclients->modified = false; deathmatch->modified = false; teamplay->modified = false; coop->modified = false; if( !svs.initialized ) return false; svgame.globals->changelevel = false; // will be restored later if needed svs.timestart = Sys_DoubleTime(); svs.spawncount++; // any partially connected client will be restarted if( startspot ) { MsgDev( D_INFO, "Spawn Server: %s [%s]\n", mapname, startspot ); } else { MsgDev( D_INFO, "Spawn Server: %s\n", mapname ); } sv.state = ss_dead; Host_SetServerState( sv.state ); Q_memset( &sv, 0, sizeof( sv )); // wipe the entire per-level structure // restore state sv.paused = paused; sv.loadgame = loadgame; sv.background = background; sv.changelevel = changelevel; sv.time = 1.0f; // server spawn time it's always 1.0 second svgame.globals->time = sv.time; // initialize buffers BF_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf )); BF_Init( &sv.reliable_datagram, "Datagram R", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf )); BF_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf )); BF_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf )); BF_Init( &sv.spectator_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf )); // leave slots at start for clients only for( i = 0; i < sv_maxclients->integer; i++ ) { // needs to reconnect if( svs.clients[i].state > cs_connected ) svs.clients[i].state = cs_connected; } // make cvars consistant if( Cvar_VariableInteger( "coop" )) Cvar_SetFloat( "deathmatch", 0 ); current_skill = (int)(Cvar_VariableValue( "skill" ) + 0.5f); current_skill = bound( 0, current_skill, 3 ); Cvar_SetFloat( "skill", (float)current_skill ); if( sv.background ) { // tell the game parts about background state Cvar_FullSet( "sv_background", "1", CVAR_READ_ONLY ); Cvar_FullSet( "cl_background", "1", CVAR_READ_ONLY ); } else { Cvar_FullSet( "sv_background", "0", CVAR_READ_ONLY ); Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); } // make sure what server name doesn't contain path and extension FS_FileBase( mapname, sv.name ); if( startspot ) Q_strncpy( sv.startspot, startspot, sizeof( sv.startspot )); else sv.startspot[0] = '\0'; Q_snprintf( sv.model_precache[1], sizeof( sv.model_precache[0] ), "maps/%s.bsp", sv.name ); Mod_LoadWorld( sv.model_precache[1], &sv.checksum, false ); sv.worldmodel = Mod_Handle( 1 ); // get world pointer for( i = 1; i < sv.worldmodel->numsubmodels; i++ ) { Q_sprintf( sv.model_precache[i+1], "*%i", i ); Mod_RegisterModel( sv.model_precache[i+1], i+1 ); } // precache and static commands can be issued during map initialization sv.state = ss_loading; Host_SetServerState( sv.state ); // clear physics interaction links SV_ClearWorld(); // tell dlls about new level started svgame.dllFuncs.pfnParmsNewLevel(); return true; }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // show_bug.cgi?id=376 // if we send an OOB print message this size, 1.31 clients die in a Com_Printf buffer overflow // the buffer overflow will be fixed in > 1.31 clients // but we want a server side fix // we must NEVER send an OOB message that will be > 1.31 MAXPRINTMSG (4096) #define SV_OUTPUTBUF_LENGTH ( 256 - 16 ) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - show_bug.cgi?id=534 time = Com_Milliseconds(); if ( time < ( lasttime + 500 ) ) { return; } lasttime = time; if ( !strlen( sv_rconPassword->string ) || strcmp( Cmd_Argv( 1 ), sv_rconPassword->string ) ) { valid = qfalse; Com_Printf( "Bad rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } else { valid = qtrue; Com_Printf( "Rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } // start redirecting all print outputs to the packet svs.redirectAddress = from; // FIXME TTimo our rcon redirection could be improved // big rcon commands such as status lead to sending // out of band packets on every single call to Com_Printf // which leads to client overflows // see show_bug.cgi?id=51 // (also a Q3 issue) Com_BeginRedirect( sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect ); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf( "No rconpassword set on the server.\n" ); } else if ( !valid ) { Com_Printf( "Bad rconpassword.\n" ); } else { remaining[0] = 0; // ATVI Wolfenstein Misc #284 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux += 4; while ( cmd_aux[0] == ' ' ) cmd_aux++; while ( cmd_aux[0] && cmd_aux[0] != ' ' ) // password cmd_aux++; while ( cmd_aux[0] == ' ' ) cmd_aux++; Q_strcat( remaining, sizeof( remaining ), cmd_aux ); Cmd_ExecuteString( remaining ); } Com_EndRedirect(); }
/* ============== SV_InitGame A brand new game has been started ============== */ void SV_InitGame( void ) { edict_t *ent; int i; if( svs.initialized ) { // cause any connected clients to reconnect Q_strncpy( host.finalmsg, "Server restarted", MAX_STRING ); SV_Shutdown( true ); } else { // init game after host error if( !svgame.hInstance ) { if( !SV_LoadProgs( GI->game_dll )) { MsgDev( D_ERROR, "SV_InitGame: can't initialize %s\n", GI->game_dll ); return; // can't load } MsgDev( D_INFO, "Server loaded\n" ); } // make sure the client is down CL_Drop(); } // now apply latched commands Cmd_ExecuteString( "latch\n", src_command ); if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" )) { MsgDev( D_WARN, "Deathmatch, Teamplay and Coop set, defaulting to Deathmatch\n"); Cvar_FullSet( "coop", "0", CVAR_LATCH ); Cvar_FullSet( "teamplay", "0", CVAR_LATCH ); } // dedicated servers are can't be single player and are usually DM // so unless they explicity set coop, force it to deathmatch if( host.type == HOST_DEDICATED ) { if( !Cvar_VariableValue( "coop" ) && !Cvar_VariableValue( "teamplay" )) Cvar_FullSet( "deathmatch", "1", CVAR_LATCH ); } // init clients if( Cvar_VariableValue( "deathmatch" ) || Cvar_VariableValue( "teamplay" )) { if( sv_maxclients->integer <= 1 ) Cvar_FullSet( "maxplayers", "8", CVAR_LATCH ); else if( sv_maxclients->integer > MAX_CLIENTS ) Cvar_FullSet( "maxplayers", "32", CVAR_LATCH ); } else if( Cvar_VariableValue( "coop" )) { if( sv_maxclients->integer <= 1 || sv_maxclients->integer > 4 ) Cvar_FullSet( "maxplayers", "4", CVAR_LATCH ); } else { // non-deathmatch, non-coop is one player Cvar_FullSet( "maxplayers", "1", CVAR_LATCH ); } svgame.globals->maxClients = sv_maxclients->integer; SV_UPDATE_BACKUP = ( svgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP; svs.clients = Z_Malloc( sizeof( sv_client_t ) * sv_maxclients->integer ); svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * 64; svs.packet_entities = Z_Malloc( sizeof( entity_state_t ) * svs.num_client_entities ); svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts ); // client frames will be allocated in SV_DirectConnect // init network stuff NET_Config(( sv_maxclients->integer > 1 )); // copy gamemode into svgame.globals svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" ); svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" ); svgame.globals->coop = Cvar_VariableInteger( "coop" ); // heartbeats will always be sent to the id master svs.last_heartbeat = MAX_HEARTBEAT; // send immediately // set client fields on player ents for( i = 0; i < svgame.globals->maxClients; i++ ) { // setup all the clients ent = EDICT_NUM( i + 1 ); SV_InitEdict( ent ); svs.clients[i].edict = ent; } // get actual movevars SV_UpdateMovevars( true ); svgame.numEntities = svgame.globals->maxClients + 1; // clients + world svs.initialized = true; }
/** * @brief Buys aircraft or craftitem. * @sa BS_SellAircraft_f */ static void BS_BuyAircraft_f (void) { int num; const aircraft_t *aircraftTemplate; base_t *base = B_GetCurrentSelectedBase(); if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <num>\n", Cmd_Argv(0)); return; } if (!base) return; num = atoi(Cmd_Argv(1)); if (num < 0 || num >= buyList.length) return; if (buyCat == FILTER_AIRCRAFT) { int freeSpace; if (!B_GetBuildingStatus(base, B_COMMAND)) { CP_Popup(_("Note"), _("No command centre in this base.\nHangars are not functional.\n")); return; } /* We cannot buy aircraft if there is no power in our base. */ if (!B_GetBuildingStatus(base, B_POWER)) { CP_Popup(_("Note"), _("No power supplies in this base.\nHangars are not functional.")); return; } /* We cannot buy aircraft without any hangar. */ if (!AIR_AircraftAllowed(base)) { CP_Popup(_("Note"), _("Build a hangar first.")); return; } aircraftTemplate = buyList.l[num].aircraft; freeSpace = AIR_CalculateHangarStorage(aircraftTemplate, base, 0); /* Check free space in hangars. */ if (freeSpace < 0) { Com_Printf("BS_BuyAircraft_f: something bad happened, AIR_CalculateHangarStorage returned -1!\n"); return; } if (freeSpace == 0) { CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough space in hangars.\n")); return; } else { const int price = BS_GetAircraftBuyingPrice(aircraftTemplate); if (ccs.credits < price) { CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough credits.\n")); return; } else { /* Hangar capacities are being updated in AIR_NewAircraft().*/ BS_RemoveAircraftFromMarket(aircraftTemplate, 1); CP_UpdateCredits(ccs.credits - price); AIR_NewAircraft(base, aircraftTemplate); Cmd_ExecuteString(va("buy_type %s", INV_GetFilterType(FILTER_AIRCRAFT))); } } } }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 time = Com_Milliseconds(); if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { // MaJ - If the rconpassword is bad and one just happned recently, don't spam the log file, just die. if ( (unsigned)( time - lasttime ) < 50u ) return; valid = qfalse; Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } else { // MaJ - If the rconpassword is good, allow it much sooner than a bad one. if ( (unsigned)( time - lasttime ) < 25u ) return; valid = qtrue; Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } lasttime = time; // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf ("No rconpassword set on the server.\n"); } else if ( !valid ) { Com_Printf ("Bad rconpassword.\n"); } else { remaining[0] = 0; // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux+=4; while(cmd_aux[0]==' ') cmd_aux++; while(cmd_aux[0] && cmd_aux[0]!=' ') // password cmd_aux++; while(cmd_aux[0]==' ') cmd_aux++; Q_strcat( remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString (remaining); } Com_EndRedirect (); }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (); while (1) { if (!host_client->active) return false; // a command caused an error if (msg_badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (); if (host_client->privileged) ret = 2; else ret = 0; if (Q_strncasecmp(s, "status", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "god", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "fly", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "name", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "say", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "tell", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "color", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "kill", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "pause", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "begin", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "kick", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ping", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "give", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ban", 3) == 0) ret = 1; if (ret == 2) Cbuf_InsertText (s); else if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
/** * @brief Handle input events like keys presses and joystick movement as well * as window events * @sa CL_Frame * @sa IN_Parse * @sa IN_JoystickMove */ void IN_Frame (void) { int mouse_buttonstate; unsigned short unicode; unsigned int key; SDL_Event event; IN_Parse(); IN_JoystickMove(); if (vid_grabmouse->modified) { vid_grabmouse->modified = qfalse; if (!vid_grabmouse->integer) { /* ungrab the pointer */ Com_Printf("Switch grab input off\n"); SDL_WM_GrabInput(SDL_GRAB_OFF); /* don't allow grabbing the input in fullscreen mode */ } else if (!vid_fullscreen->integer) { /* grab the pointer */ Com_Printf("Switch grab input on\n"); SDL_WM_GrabInput(SDL_GRAB_ON); } else { Com_Printf("No input grabbing in fullscreen mode\n"); Cvar_SetValue("vid_grabmouse", 0); } } oldMousePosX = mousePosX; oldMousePosY = mousePosY; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: switch (event.button.button) { case SDL_BUTTON_LEFT: mouse_buttonstate = K_MOUSE1; break; case SDL_BUTTON_MIDDLE: mouse_buttonstate = K_MOUSE3; break; case SDL_BUTTON_RIGHT: mouse_buttonstate = K_MOUSE2; break; case SDL_BUTTON_WHEELUP: mouse_buttonstate = K_MWHEELUP; break; case SDL_BUTTON_WHEELDOWN: mouse_buttonstate = K_MWHEELDOWN; break; case 6: mouse_buttonstate = K_MOUSE4; break; case 7: mouse_buttonstate = K_MOUSE5; break; default: mouse_buttonstate = K_AUX1 + (event.button.button - 8) % 16; break; } IN_EventEnqueue(mouse_buttonstate, 0, (event.type == SDL_MOUSEBUTTONDOWN)); break; case SDL_MOUSEMOTION: SDL_GetMouseState(&mousePosX, &mousePosY); mousePosX /= viddef.rx; mousePosY /= viddef.ry; break; case SDL_KEYDOWN: IN_PrintKey(&event, 1); #ifndef _WIN32 if ((event.key.keysym.mod & KMOD_ALT) && event.key.keysym.sym == SDLK_RETURN) { SDL_Surface *surface = SDL_GetVideoSurface(); if (!SDL_WM_ToggleFullScreen(surface)) { int flags = surface->flags ^= SDL_FULLSCREEN; SDL_SetVideoMode(surface->w, surface->h, 0, flags); } if (surface->flags & SDL_FULLSCREEN) { Cvar_SetValue("vid_fullscreen", 1); /* make sure, that input grab is deactivated in fullscreen mode */ Cvar_SetValue("vid_grabmouse", 0); } else { Cvar_SetValue("vid_fullscreen", 0); } vid_fullscreen->modified = qfalse; /* we just changed it with SDL. */ break; /* ignore this key */ } #endif if ((event.key.keysym.mod & KMOD_CTRL) && event.key.keysym.sym == SDLK_g) { SDL_GrabMode gm = SDL_WM_GrabInput(SDL_GRAB_QUERY); Cvar_SetValue("vid_grabmouse", (gm == SDL_GRAB_ON) ? 0 : 1); break; /* ignore this key */ } /* console key is hardcoded, so the user can never unbind it */ if ((event.key.keysym.mod & KMOD_SHIFT) && event.key.keysym.sym == SDLK_ESCAPE) { Con_ToggleConsole_f(); break; } IN_TranslateKey(&event.key.keysym, &key, &unicode); IN_EventEnqueue(key, unicode, qtrue); break; case SDL_VIDEOEXPOSE: break; case SDL_KEYUP: IN_PrintKey(&event, 0); IN_TranslateKey(&event.key.keysym, &key, &unicode); IN_EventEnqueue(key, unicode, qfalse); break; case SDL_ACTIVEEVENT: /* make sure menu no more capture input when the game window lose the focus */ if (event.active.state == SDL_APPINPUTFOCUS && event.active.gain == 0) UI_ReleaseInput(); break; case SDL_QUIT: Cmd_ExecuteString("quit"); break; case SDL_VIDEORESIZE: /* make sure that SDL_SetVideoMode is called again after we changed the size * otherwise the mouse will make problems */ vid_mode->modified = qtrue; break; } } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; const char *str; //johnfitz int total, j, lastcmd; //johnfitz // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); lastcmd = 0; while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & U_SIGNAL) //johnfitz -- was 128, changed for clarity { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("Illegible server message, previous was %s\n", svc_strings[lastcmd]); //johnfitz -- added svc_strings[lastcmd] break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: CL_ParseClientdata (); //johnfitz -- removed bits parameter, we will read this inside CL_ParseClientdata() break; case svc_version: i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); cl.protocol = i; //johnfitz break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_stufftext: cls.stufftext_frame = host_framecount; // allow full frame update // in demo playback -- Pa3PyX Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); //johnfitz -- save extra info if (cl_lightstyle[i].length) { total = 0; cl_lightstyle[i].peak = 'a'; for (j=0; j<cl_lightstyle[i].length; j++) { total += cl_lightstyle[i].map[j] - 'a'; cl_lightstyle[i].peak = q_max(cl_lightstyle[i].peak, cl_lightstyle[i].map[j]); } cl_lightstyle[i].average = total / cl_lightstyle[i].length + 'a'; } else cl_lightstyle[i].average = cl_lightstyle[i].peak = 'm'; //johnfitz break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 1); // johnfitz -- added second parameter break; case svc_spawnstatic: CL_ParseStatic (1); //johnfitz -- added parameter break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); BGM_Pause (); } else { CDAudio_Resume (); BGM_Resume (); } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; //johnfitz -- if signonnum==2, signon packet has been fully parsed, so check for excessive static ents and efrags if (i == 2) { if (cl.num_statics > 128) Con_Warning ("%i static entities exceeds standard limit of 128.\n", cl.num_statics); R_CheckEfrags (); } //johnfitz CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (1); //johnfitz -- added parameter break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) BGM_PlayCDtrack ((byte)cls.forcetrack, true); else BGM_PlayCDtrack ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; //johnfitz -- new svc types case svc_skybox: Sky_LoadSkyBox (MSG_ReadString()); break; case svc_bf: Cmd_ExecuteString ("bf", src_command); break; case svc_fog: Fog_ParseServerMessage (); break; case svc_spawnbaseline2: //PROTOCOL_FITZQUAKE i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 2); break; case svc_spawnstatic2: //PROTOCOL_FITZQUAKE CL_ParseStatic (2); break; case svc_spawnstaticsound2: //PROTOCOL_FITZQUAKE CL_ParseStaticSound (2); break; //johnfitz } lastcmd = cmd; //johnfitz } }
/** * @brief Call before entering a new level, or after vid_restart */ void CL_ViewLoadMedia (void) { le_t* le; int i, max; float loadingPercent; CL_ViewUpdateRenderData(); if (CL_GetConfigString(CS_TILES)[0] == '\0') return; /* no map loaded */ GAME_InitMissionBriefing(_(CL_GetConfigString(CS_MAPTITLE))); loadingPercent = 0; /* register models, pics, and skins */ SCR_DrawLoading(loadingPercent); R_ModBeginLoading(CL_GetConfigString(CS_TILES), CL_GetConfigStringInteger(CS_LIGHTMAP), CL_GetConfigString(CS_POSITIONS), CL_GetConfigString(CS_NAME), CL_GetConfigString(CS_MAPZONE)); CL_SpawnParseEntitystring(); loadingPercent += 10.0f; SCR_DrawLoading(loadingPercent); LM_Register(); CL_ParticleRegisterArt(); for (i = 1, max = 0; i < MAX_MODELS && CL_GetConfigString(CS_MODELS + i)[0] != '\0'; i++) max++; max += csi.numODs; for (i = 1; i < MAX_MODELS; i++) { const char* name = CL_GetConfigString(CS_MODELS + i); if (name[0] == '\0') break; SCR_DrawLoading(loadingPercent); cl.model_draw[i] = R_FindModel(name); if (!cl.model_draw[i]) { Cmd_ExecuteString("fs_info"); Com_Error(ERR_DROP, "Could not load model '%s'\n", name); } /* initialize clipping for bmodels */ if (name[0] == '*') cl.model_clip[i] = CM_InlineModel(cl.mapTiles, name); else cl.model_clip[i] = nullptr; loadingPercent += 100.0f / (float)max; } /* update le model references */ le = nullptr; while ((le = LE_GetNextInUse(le))) { if (le->modelnum1 > 0) le->model1 = LE_GetDrawModel(le->modelnum1); if (le->modelnum2 > 0) le->model2 = LE_GetDrawModel(le->modelnum2); } refdef.ready = true; /* waiting for EV_START */ SCR_EndLoadingPlaque(); }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("CL_ParseServerMessage: Illegible server message\n"); break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: i = MSG_ReadShort (); CL_ParseClientdata (i); break; case svc_version: i = MSG_ReadLong (); if (i != PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); strcpy (cl.scores[i].name, MSG_ReadString ()); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i)); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: { cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); } else { CDAudio_Resume (); } } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; } } }
/* ================= Host_Main ================= */ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func ) { static double oldtime, newtime; pChangeGame = func; // may be NULL if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS )) { MsgDev(D_ERROR, "SDL_Init: %s", SDL_GetError()); return 0; } #ifndef _WIN32 #ifndef __ANDROID__ // Start of IO functions FILE *fd = fopen("/proc/self/cmdline", "r"); char moduleName[64], cmdLine[512] = "", *arg; size_t size = 0; int i = 0; for(i = 0; getdelim(&arg, &size, 0, fd) != -1; i++) { if(!i) { strcpy(moduleName, strrchr(arg, '/')); //strrchr adds a / at begin of string =( memmove(&moduleName[0], &moduleName[1], sizeof(moduleName) - 1); } else { strcat(cmdLine, arg); strcat(cmdLine, " "); } } free(arg); fclose(fd); #endif #else // TODO #endif #ifndef __ANDROID__ Host_InitCommon( moduleName, cmdLine, progname, bChangeGame ); #else Host_InitCommon( NULL, "-dev 3 -log", progname, bChangeGame ); #endif // init commands and vars if( host.developer >= 3 ) { Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures"); Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures"); Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons"); Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place"); } host_cheats = Cvar_Get( "sv_cheats", "0", CVAR_LATCH, "allow cheat variables to enable" ); host_maxfps = Cvar_Get( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" ); host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" ); host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_INIT, "displays current server state" ); host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "inidcates a loaded game.dll" ); host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "inidcates a loaded client.dll" ); host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" ); con_gamemaps = Cvar_Get( "con_mapfilter", "1", CVAR_ARCHIVE, "when true show only maps in game folder" ); build = Cvar_Get( "build", va( "%i", Q_buildnum()), CVAR_INIT, "returns a current build number" ); ver = Cvar_Get( "ver", va( "%i/%g (hw build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( )), CVAR_INIT, "shows an engine version" ); // content control Cvar_Get( "violence_hgibs", "1", CVAR_ARCHIVE, "show human gib entities" ); Cvar_Get( "violence_agibs", "1", CVAR_ARCHIVE, "show alien gib entities" ); Cvar_Get( "violence_hblood", "1", CVAR_ARCHIVE, "draw human blood" ); Cvar_Get( "violence_ablood", "1", CVAR_ARCHIVE, "draw alien blood" ); if( host.type != HOST_DEDICATED ) { // when we in developer-mode automatically turn cheats on if( host.developer > 1 ) Cvar_SetFloat( "sv_cheats", 1.0f ); Cbuf_AddText( "exec video.cfg\n" ); } Mod_Init(); NET_Init(); Netchan_Init(); // allow to change game from the console if( pChangeGame != NULL ) { Cmd_AddCommand( "game", Host_ChangeGame_f, "change game" ); Cvar_Get( "host_allow_changegame", "1", CVAR_READ_ONLY, "allows to change games" ); } else { Cvar_Get( "host_allow_changegame", "0", CVAR_READ_ONLY, "allows to change games" ); } SV_Init(); CL_Init(); if( host.type == HOST_DEDICATED ) { Con_InitConsoleCommands (); Cmd_AddCommand( "quit", Sys_Quit, "quit the game" ); Cmd_AddCommand( "exit", Sys_Quit, "quit the game" ); // dedicated servers using settings from server.cfg file Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" ))); Cbuf_Execute(); Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "defaultmap" ))); } else { Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" ); Cbuf_AddText( "exec config.cfg\n" ); } host.errorframe = 0; Cbuf_Execute(); // post initializations switch( host.type ) { case HOST_NORMAL: Con_ShowConsole( false ); // hide console // execute startup config and cmdline Cbuf_AddText( va( "exec %s.rc\n", SI.ModuleName )); // intentional fallthrough case HOST_DEDICATED: // if stuffcmds wasn't run, then init.rc is probably missing, use default if( !host.stuffcmdsrun ) Cbuf_AddText( "stuffcmds\n" ); Cbuf_Execute(); break; } host.change_game = false; // done Cmd_RemoveCommand( "setr" ); // remove potentially backdoor for change render settings Cmd_RemoveCommand( "setgl" ); // we need to execute it again here Cmd_ExecuteString( "exec config.cfg\n", src_command ); oldtime = Sys_DoubleTime(); SCR_CheckStartupVids(); // must be last SDL_StopTextInput(); // disable text input event. Enable this in chat/console? SDL_Event event; // main window message loop while( !host.crashed ) { while( SDL_PollEvent( &event ) ) SDLash_EventFilter( &event ); newtime = Sys_DoubleTime (); Host_Frame( newtime - oldtime ); oldtime = newtime; } // never reached return 0; }
/* =============== CL_ChangeGame This is experiment. Use with precaution =============== */ qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset ) { if( host.type == HOST_DEDICATED ) return false; if( Q_stricmp( host.gamefolder, gamefolder )) { kbutton_t *mlook, *jlook; qboolean mlook_active = false, jlook_active = false; string mapname, maptitle; int maxEntities; mlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_mlook" ); jlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_jlook" ); if( mlook && ( mlook->state & 1 )) mlook_active = true; if( jlook && ( jlook->state & 1 )) jlook_active = true; // so reload all images (remote connect) Mod_ClearAll( true ); R_ShutdownImages(); FS_LoadGameInfo( (bReset) ? host.gamefolder : gamefolder ); R_InitImages(); // save parms maxEntities = clgame.maxEntities; Q_strncpy( mapname, clgame.mapname, MAX_STRING ); Q_strncpy( maptitle, clgame.maptitle, MAX_STRING ); #ifdef PANDORA if( !CL_LoadProgs( va( "%s/" CLIENTDLL, "." ))) #else if( !CL_LoadProgs( va( "%s/%s", GI->dll_path, GI->client_lib))) #endif Host_Error( "can't initialize client library\n" ); // restore parms clgame.maxEntities = maxEntities; Q_strncpy( clgame.mapname, mapname, MAX_STRING ); Q_strncpy( clgame.maptitle, maptitle, MAX_STRING ); // invalidate fonts so we can reloading them again Q_memset( &cls.creditsFont, 0, sizeof( cls.creditsFont )); SCR_InstallParticlePalette(); SCR_LoadCreditsFont(); Con_InvalidateFonts(); SCR_RegisterTextures (); CL_FreeEdicts (); SCR_VidInit (); if( cls.key_dest == key_game ) // restore mouse state clgame.dllFuncs.IN_ActivateMouse(); // restore mlook state if( mlook_active ) Cmd_ExecuteString( "+mlook\n", src_command ); if( jlook_active ) Cmd_ExecuteString( "+jlook\n", src_command ); return true; } return false; }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute (void) { //qboolean escape = false; int i; char *text; char line[1024]; int quotes; alias_count = 0; // don't allow infinite alias loops while (cmd_text.cursize) { // find a \n or ; line break text = (char *)cmd_text_buf; quotes = 0; for (i=0 ; i< cmd_text.cursize ; i++) { //r1: allow for escaped ""s for eg rcon set hostname \"House of Pain\" /*if (text[i] == '\\' && !escape) { escape = true; //ignore the escape character memcpy ((text+i), (text+i+1), cmd_text.cursize-1); continue; }*/ if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string //don't allow escapes of \n if (text[i] == '\n') break; } //Com_DPrintf ("Cbuf_Execute: found %d bytes\n", i); if (i >= sizeof(line)-1) { Com_Printf ("Cbuf_Execute: overflow of %d truncated\n", LOG_GENERAL, i); memcpy (line, text, sizeof(line)-1); line[sizeof(line)-1] = 0; } else { memcpy (line, text, i); line[i] = 0; } // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec, alias) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) cmd_text.cursize = 0; else { i++; cmd_text.cursize -= i; if (cmd_text.cursize) memmove (text, text+i, cmd_text.cursize); } // execute the command line //Com_DPrintf ("Cbuf_Execute: executing '%s'\n", line); //Com_Printf ("exec: %s\n", line); Cmd_ExecuteString (line); if (cmd_wait) { // skip out while text still remains in buffer, leaving it // for next frame //Com_Printf ("wait: breaking\n"); #ifndef DEDICATED_ONLY send_packet_now = true; #endif cmd_wait = false; break; } } }