/* ============== S_LoadSound The filename may be different than sfx->name in the case of a forced fallback of a player specific sound ============== */ qboolean S_LoadSound( sfx_t *sfx ) { byte *data; short *samples; snd_info_t info; // int size; // load it in data = S_CodecLoad(sfx->soundName, &info); if(!data) return qfalse; if ( info.width == 1 ) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName); } if ( info.rate != 22050 ) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName); } samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2); sfx->lastTimeUsed = Com_Milliseconds()+1; // each of these compression schemes works just fine // but the 16bit quality is much nicer and with a local // install assured we can rely upon the sound memory // manager to do the right thing for us and page // sound in as needed if( info.channels == 1 && sfx->soundCompressed == qtrue) { sfx->soundCompressionMethod = 1; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs ); S_AdpcmEncodeSound(sfx, samples); #if 0 } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) { sfx->soundCompressionMethod = 3; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeMuLaw( sfx, samples); } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) { sfx->soundCompressionMethod = 2; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeWavelet( sfx, samples); #endif } else { sfx->soundCompressionMethod = 0; sfx->soundData = NULL; sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse ); } sfx->soundChannels = info.channels; Hunk_FreeTempMemory(samples); Hunk_FreeTempMemory(data); return qtrue; }
static void R_LevelShot( void ) { #ifndef _XBOX char checkname[MAX_OSPATH]; byte *buffer; byte *source; byte *src, *dst; int x, y; int r, g, b; float xScale, yScale; int xx, yy; sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); source = (unsigned char *)Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); buffer = (unsigned char *)Hunk_AllocateTempMemory( LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = LEVELSHOTSIZE & 255; buffer[13] = LEVELSHOTSIZE >> 8; buffer[14] = LEVELSHOTSIZE & 255; buffer[15] = LEVELSHOTSIZE >> 8; buffer[16] = 24; // pixel size qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); // resample from source xScale = glConfig.vidWidth / (4.0*LEVELSHOTSIZE); yScale = glConfig.vidHeight / (3.0*LEVELSHOTSIZE); for ( y = 0 ; y < LEVELSHOTSIZE ; y++ ) { for ( x = 0 ; x < LEVELSHOTSIZE ; x++ ) { r = g = b = 0; for ( yy = 0 ; yy < 3 ; yy++ ) { for ( xx = 0 ; xx < 4 ; xx++ ) { src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); r += src[0]; g += src[1]; b += src[2]; } } dst = buffer + 18 + 3 * ( y * LEVELSHOTSIZE + x ); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } } // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, LEVELSHOTSIZE * LEVELSHOTSIZE * 3 ); } FS_WriteFile( checkname, buffer, LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18 ); Hunk_FreeTempMemory( buffer ); Hunk_FreeTempMemory( source ); Com_Printf ("Wrote %s\n", checkname ); #endif }
/* ================= SV_LoadGame_f ================= */ void SV_LoadGame_f( void ) { char filename[MAX_QPATH], mapname[MAX_QPATH]; byte *buffer; int size; Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) ); if ( !filename[0] ) { Com_Printf( "You must specify a savegame to load\n" ); return; } if ( Q_strncmp( filename, "save/", 5 ) && Q_strncmp( filename, "save\\", 5 ) ) { Q_strncpyz( filename, va( "save/%s", filename ), sizeof( filename ) ); } if ( !strstr( filename, ".svg" ) ) { Q_strcat( filename, sizeof( filename ), ".svg" ); } size = FS_ReadFile( filename, NULL ); if ( size < 0 ) { Com_Printf( "Can't find savegame %s\n", filename ); return; } buffer = Hunk_AllocateTempMemory( size ); FS_ReadFile( filename, (void **)&buffer ); // read the mapname, if it is the same as the current map, then do a fast load Com_sprintf( mapname, sizeof( mapname ), buffer + sizeof( int ) ); if ( com_sv_running->integer && ( com_frameTime != sv.serverId ) ) { // check mapname if ( !Q_stricmp( mapname, sv_mapname->string ) ) { // same if ( Q_stricmp( filename, "save/current.svg" ) != 0 ) { // copy it to the current savegame file FS_WriteFile( "save/current.svg", buffer, size ); } Hunk_FreeTempMemory( buffer ); Cvar_Set( "savegame_loading", "2" ); // 2 means it's a restart, so stop rendering until we are loaded SV_MapRestart_f(); // savegame will be loaded after restart return; } } Hunk_FreeTempMemory( buffer ); // otherwise, do a slow load if ( Cvar_VariableIntegerValue( "sv_cheats" ) ) { Cbuf_ExecuteText( EXEC_APPEND, va( "spdevmap %s", filename ) ); } else { // no cheats Cbuf_ExecuteText( EXEC_APPEND, va( "spmap %s", filename ) ); } }
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t, i = 0; int size; glIndex_t *indicies; size = (maxs[1] - mins[1]) * (maxs[0] - mins[0] + 1); indicies = ri.Hunk_AllocateTempMemory(sizeof(glIndex_t) * size); GL_Bind( image ); for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { indicies[i++] = t * (SKY_SUBDIVISIONS + 1) + s; indicies[i++] = (t + 1) * (SKY_SUBDIVISIONS + 1) + s; } } qglDisableClientState(GL_COLOR_ARRAY); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 0, s_skyTexCoords); qglVertexPointer(3, GL_FLOAT, 0, s_skyPoints); qglDrawElements(GL_TRIANGLE_STRIP, i, GL_INDEX_TYPE, indicies); Hunk_FreeTempMemory(indicies); }
/* ============== S_LoadSound The filename may be different than sfx->name in the case of a forced fallback of a player specific sound ============== */ bool S_LoadSound( sfx_t *sfx ) { byte *data; short *samples; wavinfo_t info; int size; // player specific sounds are never directly loaded if ( sfx->soundName[0] == '*') return false; // load it in size = FS_ReadFile( sfx->soundName, (void **)&data ); if ( !data ) return false; info = GetWavinfo( sfx->soundName, data, size ); if ( info.channels != 1 ) { Com_Printf ("%s is a stereo wav file\n", sfx->soundName); FS_FreeFile (data); return false; } if ( info.width == 1 ) Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName); if ( info.rate != 22050 ) Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName); samples = reinterpret_cast<short*>(Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2)); sfx->lastTimeUsed = Com_Milliseconds()+1; // each of these compression schemes works just fine // but the 16bit quality is much nicer and with a local // install assured we can rely upon the sound memory // manager to do the right thing for us and page // sound in as needed if( sfx->soundCompressed == true) { sfx->soundCompressionMethod = 1; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) ); S_AdpcmEncodeSound(sfx, samples); } else { sfx->soundCompressionMethod = 0; sfx->soundLength = info.samples; sfx->soundData = NULL; ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, false ); } Hunk_FreeTempMemory(samples); FS_FreeFile( data ); return true; }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { byte *buffer; int i, c, temp; buffer = (unsigned char *)Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; buffer[15] = height >> 8; buffer[16] = 24; // pixel size qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); // swap rgb to bgr c = 18 + width * height * 3; for (i=18 ; i<c ; i+=3) { temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp; } // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); } FS_WriteFile( fileName, buffer, c ); Hunk_FreeTempMemory( buffer ); }
/* ================== SV_ChangeMaxClients ================== */ void SV_ChangeMaxClients( void ) { int oldMaxClients; int i; client_t *oldClients; int count; // get the highest client number in use count = 0; for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { if (i > count) count = i; } } count++; oldMaxClients = sv_maxclients->integer; // never go below the highest client number in use SV_BoundMaxClients( count ); // if still the same if ( sv_maxclients->integer == oldMaxClients ) { return; } oldClients = Hunk_AllocateTempMemory( count * sizeof(client_t) ); // copy the clients to hunk memory for ( i = 0 ; i < count ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { oldClients[i] = svs.clients[i]; } else { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } } // free old clients arrays Z_Free( svs.clients ); // allocate new clients svs.clients = Z_Malloc ( sv_maxclients->integer * sizeof(client_t) ); Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) ); // copy the clients over for ( i = 0 ; i < count ; i++ ) { if ( oldClients[i].state >= CS_CONNECTED ) { svs.clients[i] = oldClients[i]; } } // free the old clients on the hunk Hunk_FreeTempMemory( oldClients ); // allocate new snapshot entities if ( com_dedicated->integer ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } }
/* ===================================================================== S_OggOpus_CodecLoad We handle S_OggOpus_CodecLoad as a special case of the streaming functions where we read the whole stream at once. ====================================================================== */ void *S_OggOpus_CodecLoad( const char *filename, snd_info_t *info ) { snd_stream_t *stream; byte *buffer; int bytesRead; // check if input is valid if ( !( filename && info ) ) { return NULL; } // open the file as a stream stream = S_OggOpus_CodecOpenStream( filename ); if ( !stream ) { return NULL; } // copy over the info info->rate = stream->info.rate; info->width = stream->info.width; info->channels = stream->info.channels; info->samples = stream->info.samples; info->size = stream->info.size; info->dataofs = stream->info.dataofs; // allocate a buffer // this buffer must be free-ed by the caller of this function buffer = Hunk_AllocateTempMemory( info->size ); if ( !buffer ) { S_OggOpus_CodecCloseStream( stream ); return NULL; } // fill the buffer bytesRead = S_OggOpus_CodecReadStream( stream, info->size, buffer ); // we don't even have read a single byte if ( bytesRead <= 0 ) { Hunk_FreeTempMemory( buffer ); S_OggOpus_CodecCloseStream( stream ); return NULL; } S_OggOpus_CodecCloseStream( stream ); return buffer; }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { byte *allbuf, *buffer; byte *srcptr, *destptr; byte *endline, *endmem; byte temp; int linelen, padlen; size_t offset = 18, memcount; allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); buffer = allbuf + offset - 18; Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; buffer[15] = height >> 8; buffer[16] = 24; // pixel size // swap rgb to bgr and remove padding from line endings linelen = width * 3; srcptr = destptr = allbuf + offset; endmem = srcptr + (linelen + padlen) * height; while(srcptr < endmem) { endline = srcptr + linelen; while(srcptr < endline) { temp = srcptr[0]; *destptr++ = srcptr[2]; *destptr++ = srcptr[1]; *destptr++ = temp; srcptr += 3; } // Skip the pad srcptr += padlen; } memcount = linelen * height; // gamma correct if(glConfig.deviceSupportsGamma) R_GammaCorrect(allbuf + offset, memcount); FS_WriteFile(fileName, buffer, memcount + 18); Hunk_FreeTempMemory(allbuf); }
void RE_SaveJPG(const char * filename, int quality, int image_width, int image_height, byte *image_buffer, int padding) { byte *out; size_t bufSize; bufSize = image_width * image_height * 3; out = (byte *)Hunk_AllocateTempMemory(bufSize); bufSize = RE_SaveJPGToBuffer(out, bufSize, quality, image_width, image_height, image_buffer, padding); ri->FS_WriteFile(filename, out, bufSize); Hunk_FreeTempMemory(out); }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; size_t offset = 0, memcount; int padlen; buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); memcount = (width * 3 + padlen) * height; // gamma correct if(glConfig.deviceSupportsGamma) R_GammaCorrect(buffer + offset, memcount); RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); Hunk_FreeTempMemory(buffer); }
/* ================ R_MipMap2 Operates in place, quartering the size of the texture Proper linear filter ================ */ static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) { int i, j, k; byte *outpix; int inWidthMask, inHeightMask; int total; int outWidth, outHeight; unsigned *temp; outWidth = inWidth >> 1; outHeight = inHeight >> 1; temp = (unsigned int *)Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); inWidthMask = inWidth - 1; inHeightMask = inHeight - 1; for ( i = 0 ; i < outHeight ; i++ ) { for ( j = 0 ; j < outWidth ; j++ ) { outpix = (byte *) ( temp + i * outWidth + j ); for ( k = 0 ; k < 4 ; k++ ) { total = 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k]; outpix[k] = total / 36; } } } memcpy( in, temp, outWidth * outHeight * 4 ); Hunk_FreeTempMemory( temp ); }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; buffer = (unsigned char *)Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } FS_WriteFile( fileName, buffer, 1 ); // create path SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer); Hunk_FreeTempMemory( buffer ); }
/* =============== Cmd_Exec_f =============== */ void Cmd_Exec_f(void) { union { char *c; void *v; } f; int len; char filename[MAX_QPATH]; fileHandle_t h; bool success = false; if (Cmd_Argc () < 2) { Com_Printf ("exec <filename> (args) : execute a script file\n"); return; } Com_Printf ("execing %s\n", Cmd_Argv(1)); Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) ); COM_DefaultExtension( filename, sizeof( filename ), ".cfg" ); len = FS_SV_FOpenFileRead(filename, &h); if (h) { success = true; f.v = Hunk_AllocateTempMemory(len + 1); FS_Read(f.v, len, h); f.c[len] = 0; FS_FCloseFile(h); Cmd_ExecFile(f.c); Hunk_FreeTempMemory(f.v); } FS_ReadFile( filename, &f.v); if (f.c) { success = true; Cmd_ExecFile(f.c); FS_FreeFile (f.v); } if (!success) Com_Printf ("couldn't exec %s\n",Cmd_Argv(1)); }
/* ============== S_LoadSound The filename may be different than sfx->name in the case of a forced fallback of a player specific sound ============== */ qboolean S_LoadSound(sfx_t * sfx) { byte *data; short *samples; snd_info_t info; // player specific sounds are never directly loaded if(sfx->soundName[0] == '*') { return qfalse; } // load it in data = S_CodecLoad(sfx->soundName, &info); if(!data) return qfalse; if(info.width == 1) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName); } if(info.rate != 22050) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName); } samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2); sfx->lastTimeUsed = Com_Milliseconds() + 1; sfx->soundLength = info.samples; sfx->soundData = NULL; ResampleSfx(sfx, info.rate, info.width, data + info.dataofs, qfalse); Hunk_FreeTempMemory(samples); Z_Free(data); return qtrue; }
void NV_WriteConfig(){ char* buffer; if( nvEntered == qtrue ){ return; } buffer = Hunk_AllocateTempMemory(MAX_NVCONFIG_SIZE); if(!buffer){ Com_Printf( "Error Updating NVConfig: Hunk_Alloc failed\n" ); return; } Com_Memset(buffer,0,MAX_NVCONFIG_SIZE); Q_strcat(buffer,MAX_NVCONFIG_SIZE,"//Autogenerated non volatile config settings\n"); Cmd_WritePowerConfig( buffer, MAX_NVCONFIG_SIZE ); Auth_WriteAdminConfig( buffer, MAX_NVCONFIG_SIZE ); FS_SV_WriteFile(NV_CONFIGFILE, buffer, strlen(buffer)); Hunk_FreeTempMemory( buffer ); Com_DPrintf("NV-Config Updated\n"); }
/* ================== SV_ChangeMaxClients ================== */ void SV_ChangeMaxClients( void ) { int oldMaxClients; int i, j; client_t *oldClients; player_t *oldPlayers; int count; // get the highest client or player number in use count = 0; for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED || svs.players[i].inUse ) { if (i > count) count = i; } } count++; oldMaxClients = sv_maxclients->integer; // never go below the highest client number in use SV_BoundMaxClients( count ); // if still the same if ( sv_maxclients->integer == oldMaxClients ) { return; } oldClients = Hunk_AllocateTempMemory( count * sizeof(client_t) ); oldPlayers = Hunk_AllocateTempMemory( count * sizeof(player_t) ); // copy the clients and players to hunk memory for ( i = 0 ; i < count ; i++ ) { if ( svs.players[i].inUse && svs.players[i].client->state >= CS_CONNECTED ) { oldPlayers[i] = svs.players[i]; oldPlayers[i].client = NULL; // client pointer gets restored using localPlayers pointers. } else { Com_Memset(&oldPlayers[i], 0, sizeof(player_t)); } if ( svs.clients[i].state >= CS_CONNECTED ) { oldClients[i] = svs.clients[i]; // save player indexes for ( j = 0; j < MAX_SPLITVIEW; j++ ) { if (svs.clients[i].localPlayers[j]) { oldClients[i].localPlayers[j] = (void*)((svs.clients[i].localPlayers[j] - svs.players) + 1); } } } else { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } } // free old clients and players arrays Z_Free( svs.clients ); Z_Free( svs.players ); // allocate new clients and players svs.clients = Z_Malloc ( sv_maxclients->integer * sizeof(client_t) ); Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) ); svs.players = Z_Malloc ( sv_maxclients->integer * sizeof(player_t) ); Com_Memset( svs.players, 0, sv_maxclients->integer * sizeof(player_t) ); // copy the clients and players over for ( i = 0 ; i < count ; i++ ) { if ( oldPlayers[i].inUse ) { svs.players[i] = oldPlayers[i]; } if ( oldClients[i].state >= CS_CONNECTED ) { svs.clients[i] = oldClients[i]; // restore pointers for ( j = 0; j < MAX_SPLITVIEW; j++ ) { if (oldClients[i].localPlayers[j]) { svs.clients[i].localPlayers[j] = &svs.players[ (intptr_t)oldClients[i].localPlayers[j] - 1 ]; svs.clients[i].localPlayers[j]->client = &svs.clients[i]; } } } } // free the old playes and clients on the hunk Hunk_FreeTempMemory( oldPlayers ); Hunk_FreeTempMemory( oldClients ); // allocate new snapshot entities if ( !Com_GameIsSinglePlayer() ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES; } }
/* ================== SV_DemoChangeMaxClients change sv_maxclients and move real clients slots when a demo is playing or stopped ================== */ void SV_DemoChangeMaxClients(void) { int oldMaxClients, oldDemoClients; int i, j, k; client_t *oldClients = NULL; int count; //qboolean firstTime = svs.clients == NULL; // == Checking the prerequisites // Note: we check here that we have enough slots to fit all clients, and that it doesn't overflow the MAX_CLIENTS the engine can support. Also, we save the oldMaxClients and oldDemoClients values. // -- Get the highest client number in use count = 0; for (i = 0 ; i < sv_maxclients->integer ; i++) { if (svs.clients[i].state >= CS_CONNECTED) { if (i > count) { count = i; } } } count++; // -- Save the previous oldMaxClients and oldDemoClients values, and update // Save the previous sv_maxclients value before updating it oldMaxClients = sv_maxclients->integer; // update the cvars Cvar_Get("sv_maxclients", "8", 0); Cvar_Get("sv_democlients", "0", 0); // unnecessary now that sv_democlients is not latched anymore? // Save the previous sv_democlients (since it's updated instantly, we cannot get it directly), we use a trick by computing the difference between the new and previous sv_maxclients (the difference should indeed be the exact value of sv_democlients) oldDemoClients = (oldMaxClients - sv_maxclients->integer); if (oldDemoClients < 0) // if the difference is negative, this means that before it was set to 0 (because the newer sv_maxclients is greater than the old) { oldDemoClients = 0; } // -- Check limits // never go below the highest client number in use (make sure we have enough room for all players) SV_BoundMaxClients(count); // -- Change check: if still the same, we just quit, there's nothing to do if (sv_maxclients->integer == oldMaxClients) { return; } // == Memorizing clients // Note: we save in a temporary variables the clients, because after we will wipe completely the svs.clients struct // copy the clients to hunk memory oldClients = Hunk_AllocateTempMemory((sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // we allocate just enough memory for the real clients (not counting in the democlients) // For all previous clients slots, we copy the entire client into a temporary var for (i = 0, j = 0, k = sv_privateClients->integer ; i < oldMaxClients ; i++) // for all the previously connected clients, we copy them to a temporary var { // If there is a real client in this slot if (svs.clients[i].state >= CS_CONNECTED) { // if the client is in a privateClient reserved slot, we move him on the reserved slots if (i >= oldDemoClients && i < oldDemoClients + sv_privateClients->integer) { oldClients[j++] = svs.clients[i]; // else the client is not a privateClient, and we move him to the first available slot after the privateClients slots } else { oldClients[k++] = svs.clients[i]; } } } // Fill in the remaining clients slots with empty clients (else the engine crash when copying into memory svs.clients) for (i = j; i < sv_privateClients->integer; i++) // Fill the privateClients empty slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } for (i = k; i < (sv_maxclients->integer - sv_democlients->integer); i++) // Fill the other normal clients slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } // free old clients arrays Z_Free(svs.clients); // == Allocating the new svs.clients and moving the saved clients over from the temporary var // allocate new svs.clients svs.clients = Z_Malloc(sv_maxclients->integer * sizeof(client_t)); Com_Memset(svs.clients, 0, sv_maxclients->integer * sizeof(client_t)); // copy the clients over (and move them depending on sv_democlients: if >0, move them upwards, if == 0, move them to their original slots) Com_Memcpy(svs.clients + sv_democlients->integer, oldClients, (sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // free the old clients on the hunk Hunk_FreeTempMemory(oldClients); // == Allocating snapshot entities // allocate new snapshot entities if (com_dedicated->integer) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } // == Server-side demos management // set demostate to none if it was just waiting to set maxclients and move real clients slots if (sv.demoState == DS_WAITINGSTOP) { sv.demoState = DS_NONE; Cvar_SetValue("sv_demoState", DS_NONE); } }
char * Sys_SecretSauce( char * buffer, int size ) { int len, bufLen; char *buf; bufLen = 4096; buf = Hunk_AllocateTempMemory( bufLen ); len = 0; if( bufLen - len >= sizeof( OSVERSIONINFO ) ) { OSVERSIONINFO vinfo; Com_Memset( &vinfo, 0, sizeof( vinfo ) ); //some bytes aren't written by the GetVersionEx vinfo.dwOSVersionInfoSize = sizeof( vinfo ); GetVersionEx( &vinfo ); Com_Memcpy( buf + len, &vinfo, sizeof( vinfo ) ); len += sizeof( vinfo ); } #if 0 // don't rely on mac address, if user disconects or disables then game becomes unregistered { DWORD cb, err; IP_ADAPTER_INFO *pInfos; cb = sizeof( IP_ADAPTER_INFO ) * 4; pInfos = Hunk_AllocateTempMemory( cb ); err = GetAdaptersInfo( pInfos, &cb ); if( err == ERROR_BUFFER_OVERFLOW ) { Hunk_FreeTempMemory( pInfos ); pInfos = Hunk_AllocateTempMemory( cb ); err = GetAdaptersInfo( pInfos, &cb ); } if( err == ERROR_SUCCESS ) { int i; int numAddrs = 0; int maxAddrs = cb / sizeof( IP_ADAPTER_INFO ); macAddr_t *addrs = Hunk_AllocateTempMemory( sizeof( macAddr_t ) * maxAddrs ); IP_ADAPTER_INFO *p; for( p = pInfos; p; p = p->Next ) { if( p->Type != MIB_IF_TYPE_ETHERNET ) continue; if( numAddrs == maxAddrs ) break; addrs[numAddrs].len = p->AddressLength; Com_Memcpy( &addrs[numAddrs].addr, p->Address, p->AddressLength ); numAddrs++; } qsort( addrs, numAddrs, sizeof( macAddr_t ), MacAddr_Cmp ); for( i = 0; i < numAddrs; i++ ) { if( addrs[i].len > bufLen - len ) break; Com_Memcpy( buf + len, addrs[i].addr, addrs[i].len ); len += addrs[i].len; } Hunk_FreeTempMemory( addrs ); } Hunk_FreeTempMemory( pInfos ); } #endif if( sizeof( cpuInfo_t ) <= bufLen - len ) { cpuInfo_t cpuInfo; Sys_GetCpuInfo( &cpuInfo ); Com_Memcpy( buf + len, &cpuInfo, sizeof( cpuInfo ) ); len += sizeof( cpuInfo ); } //MD5 the blob up Com_MD5Buffer( buffer, buf, len ); Hunk_FreeTempMemory( buf ); return buffer; }
/* ================= SV_LoadGame_f ================= */ void SV_LoadGame_f(void) { char filename[MAX_QPATH], mapname[MAX_QPATH], savedir[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile"); byte *buffer; int size; // dont allow command if another loadgame is pending if(Cvar_VariableIntegerValue("savegame_loading")) { return; } if(sv_reloading->integer) { // (SA) disabling // if(sv_reloading->integer && sv_reloading->integer != RELOAD_FAILED ) // game is in 'reload' mode, don't allow starting new maps yet. return; } Q_strncpyz(filename, Cmd_Argv(1), sizeof(filename)); if(!filename[0]) { Com_Printf("You must specify a savegame to load\n"); return; } if(com_gameInfo.usesProfiles && cl_profileStr[0]) { Com_sprintf(savedir, sizeof(savedir), "profiles/%s/save/", cl_profileStr); } else { Q_strncpyz(savedir, "save/", sizeof(savedir)); } /*if ( Q_strncmp( filename, "save/", 5 ) && Q_strncmp( filename, "save\\", 5 ) ) { Q_strncpyz( filename, va("save/%s", filename), sizeof( filename ) ); } */ // go through a va to avoid vsnprintf call with same source and target Q_strncpyz(filename, va("%s%s", savedir, filename), sizeof(filename)); // enforce .sav extension if(!strstr(filename, ".") || Q_strncmp(strstr(filename, ".") + 1, "sav", 3)) { Q_strcat(filename, sizeof(filename), ".sav"); } // use '/' instead of '\\' for directories while(strstr(filename, "\\")) { *(char *)strstr(filename, "\\") = '/'; } size = FS_ReadFile(filename, NULL); if(size < 0) { Com_Printf("Can't find savegame %s\n", filename); return; } //buffer = Hunk_AllocateTempMemory(size); FS_ReadFile(filename, (void **)&buffer); // read the mapname, if it is the same as the current map, then do a fast load Q_strncpyz(mapname, (const char *)(buffer + sizeof(int)), sizeof(mapname)); if(com_sv_running->integer && (com_frameTime != sv.serverId)) { // check mapname if(!Q_stricmp(mapname, sv_mapname->string)) { // same if(Q_stricmp(filename, va("%scurrent.sav", savedir)) != 0) { // copy it to the current savegame file FS_WriteFile(va("%scurrent.sav", savedir), buffer, size); } Hunk_FreeTempMemory(buffer); Cvar_Set("savegame_loading", "2"); // 2 means it's a restart, so stop rendering until we are loaded // set the filename Cvar_Set("savegame_filename", filename); // quick-restart the server SV_MapRestart_f(); // savegame will be loaded after restart return; } } Hunk_FreeTempMemory(buffer); // otherwise, do a slow load if(Cvar_VariableIntegerValue("sv_cheats")) { Cbuf_ExecuteText(EXEC_APPEND, va("spdevmap %s", filename)); } else { // no cheats Cbuf_ExecuteText(EXEC_APPEND, va("spmap %s", filename)); } }
/** * @brief The filename may be different than sfx->name in the case * of a forced fallback of a player specific sound * @param[in,out] sfx * @return */ qboolean S_LoadSound(sfx_t *sfx) { byte *data; short *samples; snd_info_t info; // player specific sounds are never directly loaded if (sfx->soundName[0] == '*') { return qfalse; } if (FS_FOpenFileRead(sfx->soundName, NULL, qfalse) <= 0) { // changed from debug to common print - let admins know and fix such missing files ... Com_Printf(S_COLOR_RED "ERROR: sound file \"%s\" does not exist or can't be read\n", sfx->soundName); return qfalse; } // load it in data = S_CodecLoad(sfx->soundName, &info); if (!data) { return qfalse; } if (info.width == 1) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName); } if ((info.rate != 11025) && (info.rate != 22050) && (info.rate != 44100)) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 11kHz, 22kHz nor 44kHz audio file. It has sample rate %i\n", sfx->soundName, info.rate); } samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2); sfx->lastTimeUsed = Sys_Milliseconds() + 1; // each of these compression schemes works just fine // but the 16bit quality is much nicer and with a local // install assured we can rely upon the sound memory // manager to do the right thing for us and page // sound in as needed if (info.channels == 1 && sfx->soundCompressed == qtrue) { sfx->soundCompressionMethod = 1; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw(samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs); S_AdpcmEncodeSound(sfx, samples); #if 0 } else if (info.channels == 1 && info.samples > (SND_CHUNK_SIZE * 16) && info.width > 1) { sfx->soundCompressionMethod = 3; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw(samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs)); encodeMuLaw(sfx, samples); } else if (info.channels == 1 && info.samples > (SND_CHUNK_SIZE * 6400) && info.width > 1) { sfx->soundCompressionMethod = 2; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw(samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs)); encodeWavelet(sfx, samples); #endif } else { sfx->soundCompressionMethod = 0; sfx->soundLength = info.samples; sfx->soundData = NULL; sfx->soundLength = ResampleSfx(sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse); } sfx->soundChannels = info.channels; Hunk_FreeTempMemory(samples); Hunk_FreeTempMemory(data); return qtrue; }
/* ============== S_LoadSound The filename may be different than sfx->name in the case of a forced fallback of a player specific sound ============== */ qboolean S_LoadSound( sfx_t *sfx ) { byte *data; short *samples; wavinfo_t info; int size; // player specific sounds are never directly loaded if ( sfx->soundName[0] == '*' ) { return qfalse; } // load it in size = FS_ReadFile( sfx->soundName, (void **)&data ); if ( !data ) { return qfalse; } info = GetWavinfo( sfx->soundName, data, size ); if ( info.channels != 1 ) { Com_Printf( "%s is a stereo wav file\n", sfx->soundName ); FS_FreeFile( data ); return qfalse; } if ( info.width == 1 ) { Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName ); } if ( info.rate != 22050 ) { Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName ); } samples = Hunk_AllocateTempMemory( info.samples * sizeof( short ) * 2 ); // DHM - Nerve sfx->lastTimeUsed = Sys_Milliseconds() + 1; // each of these compression schemes works just fine // but the 16bit quality is much nicer and with a local // install assured we can rely upon the sound memory // manager to do the right thing for us and page // sound in as needed if ( s_nocompressed->value ) { sfx->soundCompressionMethod = 0; sfx->soundLength = info.samples; sfx->soundData = NULL; ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse ); } else if ( sfx->soundCompressed == qtrue ) { sfx->soundCompressionMethod = 1; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, ( data + info.dataofs ) ); S_AdpcmEncodeSound( sfx, samples ); #ifdef COMPRESSION } else if ( info.samples > ( SND_CHUNK_SIZE * 16 ) && info.width > 1 ) { sfx->soundCompressionMethod = 3; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, ( data + info.dataofs ) ); encodeMuLaw( sfx, samples ); } else if ( info.samples > ( SND_CHUNK_SIZE * 6400 ) && info.width > 1 ) { sfx->soundCompressionMethod = 2; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, ( data + info.dataofs ) ); encodeWavelet( sfx, samples ); #endif } else { sfx->soundCompressionMethod = 0; sfx->soundLength = info.samples; sfx->soundData = NULL; ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse ); } Hunk_FreeTempMemory( samples ); FS_FreeFile( data ); return qtrue; }
/* ================== SV_Map_f Restart the server on a different map ================== */ static void SV_Map_f(void) { char *cmd, *map, smapname[MAX_QPATH], mapname[MAX_QPATH], expanded[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile"); qboolean killBots, cheat, buildScript; int savegameTime = -1; map = Cmd_Argv(1); if(!map) { return; } if(!com_gameInfo.spEnabled) { if(!Q_stricmp(Cmd_Argv(0), "spdevmap") || !Q_stricmp(Cmd_Argv(0), "spmap")) { Com_Printf("Single Player is not enabled.\n"); return; } } buildScript = (qboolean)Cvar_VariableIntegerValue("com_buildScript"); if(SV_GameIsSinglePlayer()) { if(!buildScript && sv_reloading->integer && sv_reloading->integer != RELOAD_NEXTMAP) { // game is in 'reload' mode, don't allow starting new maps yet. return; } // Trap a savegame load if(strstr(map, ".sav")) { // open the savegame, read the mapname, and copy it to the map string char savemap[MAX_QPATH], savedir[MAX_QPATH]; byte *buffer; int size, csize; if(com_gameInfo.usesProfiles && cl_profileStr[0]) { Com_sprintf(savedir, sizeof(savedir), "profiles/%s/save/", cl_profileStr); } else { Q_strncpyz(savedir, "save/", sizeof(savedir)); } if(!(strstr(map, savedir) == map)) { Com_sprintf(savemap, sizeof(savemap), "%s%s", savedir, map); } else { strcpy(savemap, map); } size = FS_ReadFile(savemap, NULL); if(size < 0) { Com_Printf("Can't find savegame %s\n", savemap); return; } //buffer = Hunk_AllocateTempMemory(size); FS_ReadFile(savemap, (void **)&buffer); if(Q_stricmp(savemap, va("%scurrent.sav", savedir)) != 0) { // copy it to the current savegame file FS_WriteFile(va("%scurrent.sav", savedir), buffer, size); // make sure it is the correct size csize = FS_ReadFile(va("%scurrent.sav", savedir), NULL); if(csize != size) { Hunk_FreeTempMemory(buffer); FS_Delete(va("%scurrent.sav", savedir)); // TTimo #ifdef __linux__ Com_Error(ERR_DROP, "Unable to save game.\n\nPlease check that you have at least 5mb free of disk space in your home directory."); #else Com_Error(ERR_DROP, "Insufficient free disk space.\n\nPlease free at least 5mb of free space on game drive."); #endif return; } } // set the cvar, so the game knows it needs to load the savegame once the clients have connected Cvar_Set("savegame_loading", "1"); // set the filename Cvar_Set("savegame_filename", savemap); // the mapname is at the very start of the savegame file Q_strncpyz(savemap, (char *)(buffer + sizeof(int)), sizeof(savemap)); // skip the version Q_strncpyz(smapname, savemap, sizeof(smapname)); map = smapname; savegameTime = *(int *)(buffer + sizeof(int) + MAX_QPATH); if(savegameTime >= 0) { svs.time = savegameTime; } Hunk_FreeTempMemory(buffer); } else { Cvar_Set("savegame_loading", "0"); // make sure it's turned off // set the filename Cvar_Set("savegame_filename", ""); } } else { Cvar_Set("savegame_loading", "0"); // make sure it's turned off // set the filename Cvar_Set("savegame_filename", ""); } // make sure the level exists before trying to change, so that // a typo at the server console won't end the game Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map); if(FS_ReadFile(expanded, NULL) == -1) { Com_Printf("Can't find map %s\n", expanded); return; } Cvar_Set("gamestate", va("%i", GS_INITIALIZE)); // NERVE - SMF - reset gamestate on map/devmap Cvar_Set("g_currentRound", "0"); // NERVE - SMF - reset the current round Cvar_Set("g_nextTimeLimit", "0"); // NERVE - SMF - reset the next time limit // START Mad Doctor I changes, 8/14/2002. Need a way to force load a single player map as single player if(!Q_stricmp(Cmd_Argv(0), "spdevmap") || !Q_stricmp(Cmd_Argv(0), "spmap")) { // This is explicitly asking for a single player load of this map Cvar_Set("g_gametype", va("%i", com_gameInfo.defaultSPGameType)); // force latched values to get set Cvar_Get("g_gametype", va("%i", com_gameInfo.defaultSPGameType), CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, "test"); // enable bot support for AI Cvar_Set("bot_enable", "1"); } // Rafael gameskill // Cvar_Get ("g_gameskill", "3", CVAR_SERVERINFO | CVAR_LATCH); // done cmd = Cmd_Argv(0); if(!Q_stricmp(cmd, "devmap")) { cheat = qtrue; killBots = qtrue; } else if(!Q_stricmp(Cmd_Argv(0), "spdevmap")) { cheat = qtrue; killBots = qtrue; } else { cheat = qfalse; killBots = qfalse; } // save the map name here cause on a map restart we reload the q3config.cfg // and thus nuke the arguments of the map command Q_strncpyz(mapname, map, sizeof(mapname)); // start up the map SV_SpawnServer(mapname, killBots); // set the cheat value // if the level was started with "map <levelname>", then // cheats will not be allowed. If started with "devmap <levelname>" // then cheats will be allowed if(cheat) { Cvar_Set("sv_cheats", "1"); } else { Cvar_Set("sv_cheats", "0"); } }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f(void) { int i, delay = 0; client_t *client; char *denied; qboolean isBot; gamestate_t new_gs, old_gs; // NERVE - SMF // make sure we aren't restarting twice in the same frame if(com_frameTime == sv.serverId) { return; } // make sure server is running if(!com_sv_running->integer) { Com_Printf("Server is not running.\n"); return; } if(Cmd_Argc() > 1) { delay = atoi(Cmd_Argv(1)); } if(delay) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring(CS_WARMUP, va("%i", sv.restartTime)); return; } // NERVE - SMF - read in gamestate or just default to GS_PLAYING old_gs = (gamestate_t)atoi(Cvar_VariableString("gamestate")); if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) { new_gs = GS_PLAYING; } else { if(Cmd_Argc() > 2) { new_gs = (gamestate_t)atoi(Cmd_Argv(2)); } else { new_gs = GS_PLAYING; } } if(!SV_TransitionGameState(new_gs, old_gs, delay)) { return; } // check for changes in variables that can't just be restarted // check for maxclients change if(sv_maxclients->modified) { char mapname[MAX_QPATH]; Com_Printf("sv_maxclients variable change -- restarting.\n"); // restart the map the slow way Q_strncpyz(mapname, Cvar_VariableString("mapname"), sizeof(mapname)); SV_SpawnServer(mapname, qfalse); return; } // Check for loading a saved game if(Cvar_VariableIntegerValue("savegame_loading")) { // open the current savegame, and find out what the time is, everything else we can ignore char savemap[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile"); byte *buffer; int size, savegameTime; if(com_gameInfo.usesProfiles) { Com_sprintf(savemap, sizeof(savemap), "profiles/%s/save/current.sav", cl_profileStr); } else { Q_strncpyz(savemap, "save/current.sav", sizeof(savemap)); } size = FS_ReadFile(savemap, NULL); if(size < 0) { Com_Printf("Can't find savegame %s\n", savemap); return; } //buffer = Hunk_AllocateTempMemory(size); FS_ReadFile(savemap, (void **)&buffer); // the mapname is at the very start of the savegame file savegameTime = *(int *)(buffer + sizeof(int) + MAX_QPATH); if(savegameTime >= 0) { svs.time = savegameTime; } Hunk_FreeTempMemory(buffer); } // done. // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set("sv_serverid", va("%i", sv.serverId)); // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; Cvar_Set("sv_serverRestarting", "1"); SV_RestartGameProgs(); // run a few frames to allow everything to settle for(i = 0; i < GAME_INIT_FRAMES; i++) { VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; } // create a baseline for more efficient communications // Gordon: meh, this wont work here as the client doesn't know it has happened // SV_CreateBaseline (); sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for(i = 0; i < sv_maxclients->integer; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if(client->state < CS_CONNECTED) { continue; } if(client->netchan.remoteAddress.type == NA_BOT) { if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) { continue; // dont carry across bots in single player } isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand(client, "map_restart\n"); // connect the client again, without the firstTime flag denied = (char*)VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot)); if(denied) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient(client, denied); if((!SV_GameIsSinglePlayer()) || (!isBot)) { Com_Printf("SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i); // bk010125 } continue; } client->state = CS_ACTIVE; SV_ClientEnterWorld(client, &client->lastUsercmd); } // run another frame to allow things to look at all the players VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; Cvar_Set("sv_serverRestarting", "0"); }
/* ================== SV_ChangeMaxClients ================== */ void SV_ChangeMaxClients( void ) { int oldMaxClients; int i; client_t *oldClients; int count; // get the highest client number in use count = 0; for ( i = 0; i < sv_maxclients->integer; i++ ) { if ( svs.clients[ i ].state >= CS_CONNECTED ) { if ( i > count ) { count = i; } } } count++; oldMaxClients = sv_maxclients->integer; // never go below the highest client number in use SV_BoundMaxClients( count ); // if still the same if ( sv_maxclients->integer == oldMaxClients ) { return; } oldClients = Hunk_AllocateTempMemory( count * sizeof( client_t ) ); // copy the clients to hunk memory for ( i = 0; i < count; i++ ) { if ( svs.clients[ i ].state >= CS_CONNECTED ) { oldClients[ i ] = svs.clients[ i ]; } else { Com_Memset( &oldClients[ i ], 0, sizeof( client_t ) ); } } // free old clients arrays //Z_Free( svs.clients ); free( svs.clients ); // RF, avoid trying to allocate large chunk on a fragmented zone // allocate new clients // RF, avoid trying to allocate large chunk on a fragmented zone svs.clients = calloc( sizeof( client_t ) * sv_maxclients->integer, 1 ); if ( !svs.clients ) { Com_Error( ERR_FATAL, "SV_Startup: unable to allocate svs.clients" ); } Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof( client_t ) ); // copy the clients over for ( i = 0; i < count; i++ ) { if ( oldClients[ i ].state >= CS_CONNECTED ) { svs.clients[ i ] = oldClients[ i ]; } } // free the old clients on the hunk Hunk_FreeTempMemory( oldClients ); // allocate new snapshot entities if ( com_dedicated->integer ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } }
/* ================== SV_ChangeMaxClients ================== */ static void SV_ChangeMaxClients( void ) { int oldMaxClients; int i, j; client_t *oldClients = NULL; int count = 0; qboolean firstTime = svs.clients == NULL; if ( !firstTime ) { // get the number of clients in use for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; } } } oldMaxClients = sv_maxclients->integer; // update the cvars Cvar_Get( "sv_maxclients", "8", 0 ); Cvar_Get( "sv_democlients", "0", 0 ); // make sure we have enough room for all clients if ( sv_democlients->integer + count > MAX_CLIENTS ) Cvar_SetValue( "sv_democlients", MAX_CLIENTS - count ); if ( sv_maxclients->integer < sv_democlients->integer + count ) { Cvar_SetValue( "sv_maxclients", sv_democlients->integer + count ); } sv_maxclients->modified = qfalse; sv_democlients->modified = qfalse; // if still the same if ( !firstTime && sv_maxclients->integer == oldMaxClients ) { // move people who are below sv_democlients up for ( i = 0; i < sv_democlients->integer; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { for ( j = sv_democlients->integer; j < sv_maxclients->integer; j++ ) { if ( svs.clients[j].state < CS_CONNECTED ) { svs.clients[j] = svs.clients[i]; break; } } Com_Memset( svs.clients + i, 0, sizeof(client_t) ); } } return; } if ( !firstTime ) { // copy the clients to hunk memory oldClients = Hunk_AllocateTempMemory( count * sizeof(client_t) ); for ( i = 0, j = 0 ; i < oldMaxClients ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { oldClients[j++] = svs.clients[i]; } } // free old clients arrays Z_Free( svs.clients ); } // allocate new clients svs.clients = Z_Malloc( sv_maxclients->integer * sizeof(client_t) ); Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) ); if ( !firstTime ) { // copy the clients over Com_Memcpy( svs.clients + sv_democlients->integer, oldClients, count * sizeof(client_t) ); // free the old clients on the hunk Hunk_FreeTempMemory( oldClients ); } // allocate new snapshot entities if ( com_dedicated->integer ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } }
/* ================= CL_OpenJoystickRemap joystickIdent could be a name or hash ================= */ qboolean CL_OpenJoystickRemap( int localPlayerNum, const char *joystickName, const char *joystickIdent ) { fileHandle_t f; char filename[MAX_QPATH]; char *buffer, *text, *token; int len, i; joyevent_t joyevent; int key; if ( !joystickName ) { return qfalse; } if ( !joystickIdent ) { joystickIdent = joystickName; } // check if already loaded for ( i = 0; i < CL_MAX_SPLITVIEW; i++ ) { if ( !strcmp(joyDevice[i].ident, joystickIdent ) ) { break; } } if ( i != CL_MAX_SPLITVIEW ) { playerJoyRemapIndex[localPlayerNum] = i; joyDevice[i].references++; return qtrue; } // find free slot for ( i = 0; i < CL_MAX_SPLITVIEW; i++ ) { if ( !joyDevice[i].references ) { break; } } if ( i == CL_MAX_SPLITVIEW ) { Com_Printf("BUG: Tried to open joystick but no free slot\n"); playerJoyRemapIndex[localPlayerNum] = -1; return qfalse; } playerJoyRemapIndex[localPlayerNum] = i; // initialize remap Com_Memset( &joyDevice[i], 0, sizeof ( joyDevice[0] ) ); Q_strncpyz( joyDevice[i].ident, joystickIdent, sizeof ( joyDevice[i].ident ) ); Q_strncpyz( joyDevice[i].name, joystickName, sizeof ( joyDevice[i].ident ) ); joyDevice[i].references = 1; Com_sprintf( filename, sizeof ( filename ), "joy-%s-%s.txt", JOY_PLATFORM, joyDevice[i].ident ); len = FS_SV_FOpenFileRead( filename, &f ); if ( !f ) { return qfalse; } buffer = Hunk_AllocateTempMemory(len+1); FS_Read (buffer, len, f); // guarantee that it will have a trailing 0 for string operations buffer[len] = 0; FS_FCloseFile( f ); text = buffer; while ( 1 ) { token = COM_Parse( &text ); if ( !*token ) { break; } if ( !CL_StringToJoyEvent( token, &joyevent) ) { SkipRestOfLine( &text ); Com_Printf ("\"%s\" isn't a valid joystick event in %s\n", token, filename ); continue; } token = COM_ParseExt( &text, qfalse ); if ( !*token ) { Com_Printf("WARNING: Missing key for joy event in %s\n", filename ); continue; } key = Key_StringToKeynum( token ); if ( key == -1 ) { Com_Printf( "\"%s\" isn't a valid key in %s\n", token, filename ); continue; } if ( !CL_SetKeyForJoyEvent( localPlayerNum, &joyevent, key ) ) { Com_Printf ("Max joystick remaps reached (%d), cannot add remap for %s.\n", MAX_JOY_REMAPS, CL_JoyEventToString( &joyevent ) ); break; } } Hunk_FreeTempMemory( buffer ); return qtrue; }
/* ================ Con_Dump_f Save the console contents out to a file ================ */ void Con_Dump_f (void) { int l, x, i; int32_t *line; fileHandle_t f; int bufferlen; char *buffer; char filename[MAX_QPATH]; if (Cmd_Argc() != 2) { Com_Printf ("%s\n", SE_GetString("CON_TEXT_DUMP_USAGE")); return; } Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) ); COM_DefaultExtension( filename, sizeof( filename ), ".txt" ); if(!COM_CompareExtension(filename, ".txt")) { Com_Printf( "Con_Dump_f: Only the \".txt\" extension is supported by this command!\n" ); return; } f = FS_FOpenFileWrite( filename ); if (!f) { Com_Printf ("ERROR: couldn't open %s.\n", filename); return; } Com_Printf ("Dumped console text to %s.\n", filename ); // skip empty lines for (l = con.current - con.totallines + 1 ; l <= con.current ; l++) { line = con.text + (l%con.totallines)*con.linewidth; for (x=0 ; x<con.linewidth ; x++) if ((line[x] & 0xff) != ' ') //che break; if (x != con.linewidth) break; } #ifdef _WIN32 bufferlen = con.linewidth + 3 * sizeof ( char ); #else bufferlen = con.linewidth + 2 * sizeof ( char ); #endif buffer = (char *)Hunk_AllocateTempMemory( bufferlen ); // write the remaining lines buffer[bufferlen-1] = 0; for ( ; l <= con.current ; l++) { line = con.text + (l%con.totallines)*con.linewidth; for(i=0; i<con.linewidth; i++) buffer[i] = (char) (line[i] & 0xff); for (x=con.linewidth-1 ; x>=0 ; x--) { if (buffer[x] == ' ') buffer[x] = 0; else break; } #ifdef _WIN32 Q_strcat(buffer, bufferlen, "\r\n"); #else Q_strcat(buffer, bufferlen, "\n"); #endif FS_Write(buffer, strlen(buffer), f); } Hunk_FreeTempMemory( buffer ); FS_FCloseFile( f ); }