/* =============== Sys_GetConsoleKey =============== */ unsigned char Sys_GetConsoleKey(bool shifted) { static unsigned char keys[2] = { '`', '~' }; if (in_kbd.IsModified()) { idStr lang = in_kbd.GetString(); if (lang.Length()) { if (!lang.Icmp("french")) { keys[0] = '<'; keys[1] = '>'; } else if (!lang.Icmp("german")) { keys[0] = '^'; keys[1] = 176; // ° } else if (!lang.Icmp("italian")) { keys[0] = '\\'; keys[1] = '|'; } else if (!lang.Icmp("spanish")) { keys[0] = 186; // º keys[1] = 170; // ª } else if (!lang.Icmp("turkish")) { keys[0] = '"'; keys[1] = 233; // é } } in_kbd.ClearModified(); } return shifted ? keys[1] : keys[0]; }
/* ======================== idLobbyBackendDirect::GetConnectInfo ======================== */ lobbyConnectInfo_t idLobbyBackendDirect::GetConnectInfo() { lobbyConnectInfo_t connectInfo; // If we aren't the host, this lobby should have been joined through JoinFromConnectInfo if( IsHost() ) { // If we are the host, give them our ip address // DG: always using the first IP doesn't work, because on linux that's 127.0.0.1 // and even if not, this causes trouble with NAT. // So either use net_ip or, if it's not set ("localhost"), use 0.0.0.0 which is // a special case the client will treat as "just use the IP I used for the lobby" // (which is the right behavior for the Direct backend, I guess). // the client special case is in idLobby::HandleReliableMsg const char* ip = net_ip.GetString(); if( ip == NULL || idStr::Length( ip ) == 0 || idStr::Icmp( ip, "localhost" ) == 0 ) ip = "0.0.0.0"; // DG end Sys_StringToNetAdr( ip, &address, false ); address.port = net_port.GetInteger(); } connectInfo.netAddr = address; return connectInfo; }
idAudioHardware *idAudioHardware::Alloc() { #ifndef NO_ALSA if ( !strcmp( s_driver.GetString(), "best" ) ) { idAudioHardwareALSA *test = new idAudioHardwareALSA; if ( test->DLOpen() ) { common->Printf( "Alsa is available\n" ); return test; } common->Printf( "Alsa is not available\n" ); delete test; return new idAudioHardwareOSS; } if ( !strcmp( s_driver.GetString(), "alsa" ) ) { return new idAudioHardwareALSA; } #endif return new idAudioHardwareOSS; }
/* ================== idPort::InitForPort ================== */ bool idPort::InitForPort( int portNumber ) { netSocket = IPSocket( net_ip.GetString(), portNumber, &bound_to ); if ( netSocket <= 0 ) { netSocket = 0; memset( &bound_to, 0, sizeof( bound_to ) ); return false; } return true; }
/* ======================== idLocalUser::StorageSizeAvailable ======================== */ bool idLocalUser::StorageSizeAvailable( uint64 minSizeInBytes, int64 & neededBytes ) { int64 size = Sys_GetDriveFreeSpaceInBytes( fs_savepath.GetString() ); neededBytes = minSizeInBytes - size; if ( neededBytes < 0 ) { neededBytes = 0; } return neededBytes == 0; }
/* ============ idAASLocal::GetAreaNumAndLocation ============ */ bool idAASLocal::GetAreaNumAndLocation( idCVar &cvar, const idVec3 &origin, int &areaNum, idVec3 &location ) const { areaNum = 0; location.Zero(); if ( cvar.GetString()[0] == '\0' ) { return false; } if ( idStr::Icmp( cvar.GetString(), "memory" ) == 0 ) { cvar.SetString( aas_locationMemory.GetString() ); } if ( idStr::Icmp( cvar.GetString(), "current" ) == 0 ) { cvar.SetString( origin.ToString() ); } idLexer src( LEXFL_NOERRORS|LEXFL_NOWARNINGS ); src.LoadMemory( cvar.GetString(), idStr::Length( cvar.GetString() ), "areaNum" ); bool error = false; location.x = src.ParseFloat( &error ); location.y = src.ParseFloat( &error ); location.z = src.ParseFloat( &error ); if ( !error ) { areaNum = PointReachableAreaNum( location, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() ); PushPointIntoArea( areaNum, location ); return true; } src.Reset(); areaNum = src.ParseInt(); if ( ( areaNum > 0 ) && ( areaNum < file->GetNumAreas() ) ) { location = AreaCenter( areaNum ); return true; } return false; }
/* =============== idAudioHardwareALSA::DLOpen =============== */ bool idAudioHardwareALSA::DLOpen( void ) { const char *version; if ( m_handle ) { return true; } common->Printf( "dlopen(%s)\n", s_alsa_lib.GetString() ); if ( !( m_handle = dlopen( s_alsa_lib.GetString(), RTLD_NOW | RTLD_GLOBAL ) ) ) { common->Printf( "dlopen(%s) failed: %s\n", s_alsa_lib.GetString(), dlerror() ); return false; } // print the version if available id_snd_asoundlib_version = ( pfn_snd_asoundlib_version )dlsym( m_handle, "snd_asoundlib_version" ); if ( !id_snd_asoundlib_version ) { common->Printf( "dlsym(\"snd_asoundlib_version\") failed: %s\n", dlerror() ); common->Warning( "please consider upgrading alsa to a more recent version." ); } else { version = id_snd_asoundlib_version(); common->Printf( "asoundlib version: %s\n", version ); } // dlsym the symbols ALSA_DLSYM(snd_pcm_avail_update); ALSA_DLSYM(snd_pcm_close); ALSA_DLSYM(snd_pcm_hw_params); ALSA_DLSYM(snd_pcm_hw_params_any); ALSA_DLSYM(snd_pcm_hw_params_get_buffer_size); ALSA_DLSYM(snd_pcm_hw_params_set_access); ALSA_DLSYM(snd_pcm_hw_params_set_buffer_size_min); ALSA_DLSYM(snd_pcm_hw_params_set_channels); ALSA_DLSYM(snd_pcm_hw_params_set_format); ALSA_DLSYM(snd_pcm_hw_params_set_rate); ALSA_DLSYM(snd_pcm_hw_params_sizeof); ALSA_DLSYM(snd_pcm_open); ALSA_DLSYM(snd_pcm_prepare); ALSA_DLSYM(snd_pcm_state); ALSA_DLSYM(snd_pcm_writei); ALSA_DLSYM(snd_strerror); return true; }
/* ======================== idSignInManagerWin::RegisterLocalUser ======================== */ void idSignInManagerWin::RegisterLocalUser( int inputDevice ) { if( GetLocalUserByInputDevice( inputDevice ) != NULL ) { return; } static char machineName[128]; // DG: support for ui_name const char* nameSource = ui_name.GetString(); if( idStr::Length( nameSource ) == 0 ) { // ui_name was empty => default to hostname #ifdef _WIN32 DWORD len = 128; ::GetComputerName( machineName, &len ); #else gethostname( machineName, sizeof( machineName ) ); #endif nameSource = machineName; } // DG end idStr name( nameSource ); int nameLength = name.Length(); if( idStr::IsValidUTF8( nameSource, nameLength ) ) { int nameIndex = 0; int numChars = 0; name.Empty(); while( nameIndex < nameLength && numChars++ < idLocalUserWin::MAX_GAMERTAG_CHARS ) { uint32 c = idStr::UTF8Char( nameSource, nameIndex ); name.AppendUTF8Char( c ); } } idLib::Printf( "Added local user: %s\n", name.c_str() ); idLocalUserWin& localUser = *localUsers.Alloc(); localUser.Init( inputDevice, name.c_str(), localUsers.Num() ); localUser.SetLocalUserHandle( GetUniqueLocalUserHandle( localUser.GetGamerTag() ) ); session->OnLocalUserSignin( &localUser ); }
/* ================== InitForPort ================== */ bool idPort::InitForPort( int portNumber ) { int len = sizeof( struct sockaddr_in ); netSocket = NET_IPSocket( net_ip.GetString(), portNumber, &bound_to ); if ( netSocket <= 0 ) { netSocket = 0; memset( &bound_to, 0, sizeof( bound_to ) ); return false; } #if 0 if ( net_socksEnabled.GetBool() ) { NET_OpenSocks( portNumber ); } #endif udpPorts[ bound_to.port ] = new idUDPLag; return true; }
/* ================ idCollisionModelManagerLocal::DrawModel ================ */ void idCollisionModelManagerLocal::DrawModel( cmHandle_t handle, const idVec3& modelOrigin, const idMat3& modelAxis, const idVec3& viewOrigin, const float radius ) { cm_model_t* model; idVec3 viewPos; if( handle < 0 && handle >= numModels ) { return; } if( cm_drawColor.IsModified() ) { sscanf( cm_drawColor.GetString(), "%f %f %f %f", &cm_color.x, &cm_color.y, &cm_color.z, &cm_color.w ); cm_drawColor.ClearModified(); } model = models[ handle ]; viewPos = ( viewOrigin - modelOrigin ) * modelAxis.Transpose(); checkCount++; DrawNodePolygons( model, model->node, modelOrigin, modelAxis, viewPos, radius ); }
/* ======================== NET_OpenSocks ======================== */ void NET_OpenSocks( int port ) { sockaddr_in address; struct hostent* h; int len; bool rfc1929; unsigned char buf[64]; usingSocks = false; idLib::Printf( "Opening connection to SOCKS server.\n" ); if( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) { idLib::Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() ); return; } h = gethostbyname( net_socksServer.GetString() ); if( h == NULL ) { idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() ); return; } if( h->h_addrtype != AF_INET ) { idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" ); return; } address.sin_family = AF_INET; address.sin_addr.s_addr = *( in_addr_t* )h->h_addr_list[0]; address.sin_port = htons( ( short )net_socksPort.GetInteger() ); if( connect( socks_socket, ( sockaddr* )&address, sizeof( address ) ) == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() ); return; } // send socks authentication handshake if( *net_socksUsername.GetString() || *net_socksPassword.GetString() ) { rfc1929 = true; } else { rfc1929 = false; } buf[0] = 5; // SOCKS version // method count if( rfc1929 ) { buf[1] = 2; len = 4; } else { buf[1] = 1; len = 3; } buf[2] = 0; // method #1 - method id #00: no authentication if( rfc1929 ) { buf[2] = 2; // method #2 - method id #02: username/password } if( send( socks_socket, ( const char* )buf, len, 0 ) == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len != 2 || buf[0] != 5 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } switch( buf[1] ) { case 0: // no authentication break; case 2: // username/password authentication break; default: idLib::Printf( "NET_OpenSocks: request denied\n" ); return; } // do username/password authentication if needed if( buf[1] == 2 ) { int ulen; int plen; // build the request ulen = idStr::Length( net_socksUsername.GetString() ); plen = idStr::Length( net_socksPassword.GetString() ); buf[0] = 1; // username/password authentication version buf[1] = ulen; if( ulen ) { memcpy( &buf[2], net_socksUsername.GetString(), ulen ); } buf[2 + ulen] = plen; if( plen ) { memcpy( &buf[3 + ulen], net_socksPassword.GetString(), plen ); } // send it if( send( socks_socket, ( const char* )buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len != 2 || buf[0] != 1 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } if( buf[1] != 0 ) { idLib::Printf( "NET_OpenSocks: authentication failed\n" ); return; } } // send the UDP associate request buf[0] = 5; // SOCKS version buf[1] = 3; // command: UDP associate buf[2] = 0; // reserved buf[3] = 1; // address type: IPV4 *( int* )&buf[4] = INADDR_ANY; *( short* )&buf[8] = htons( ( short )port ); // port if( send( socks_socket, ( const char* )buf, 10, 0 ) == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len == SOCKET_ERROR ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len < 2 || buf[0] != 5 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } // check completion code if( buf[1] != 0 ) { idLib::Printf( "NET_OpenSocks: request denied: %i\n", buf[1] ); return; } if( buf[3] != 1 ) { idLib::Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] ); return; } socksRelayAddr.sin_family = AF_INET; socksRelayAddr.sin_addr.s_addr = *( int* )&buf[4]; socksRelayAddr.sin_port = *( short* )&buf[8]; memset( socksRelayAddr.sin_zero, 0, sizeof( socksRelayAddr.sin_zero ) ); usingSocks = true; }
/* ======================== idSaveGameThread::SaveGame ======================== */ int idSaveGameThread::Save() { idLocalUserWin * user = GetLocalUserFromSaveParms( data ); if ( user == NULL ) { data.saveLoadParms->errorCode = SAVEGAME_E_INVALID_USER; return -1; } idSaveLoadParms * callback = data.saveLoadParms; idStr saveFolder = "savegame"; saveFolder.AppendPath( callback->directory ); // Check for the required storage space. int64 requiredSizeBytes = 0; { for ( int i = 0; i < callback->files.Num(); i++ ) { idFile_SaveGame * file = callback->files[i]; requiredSizeBytes += ( file->Length() + sizeof( unsigned int ) ); // uint for checksum if ( file->type == SAVEGAMEFILE_PIPELINED ) { requiredSizeBytes += MIN_SAVEGAME_SIZE_BYTES; } } } int ret = ERROR_SUCCESS; // Check size of previous files if needed // ALL THE FILES RIGHT NOW---- could use pattern later... idStrList filesToDelete; if ( ( callback->mode & SAVEGAME_MBF_DELETE_FILES ) && !callback->cancelled ) { if ( fileSystem->IsFolder( saveFolder.c_str(), "fs_savePath" ) == FOLDER_YES ) { idFileList * files = fileSystem->ListFilesTree( saveFolder.c_str(), "*.*" ); for ( int i = 0; i < files->GetNumFiles(); i++ ) { requiredSizeBytes -= fileSystem->GetFileLength( files->GetFile( i ) ); filesToDelete.Append( files->GetFile( i ) ); } fileSystem->FreeFileList( files ); } } // Inform user about size required if necessary if ( requiredSizeBytes > 0 && !callback->cancelled ) { user->StorageSizeAvailable( requiredSizeBytes, callback->requiredSpaceInBytes ); if ( callback->requiredSpaceInBytes > 0 ) { // check to make sure savepath actually exists before erroring idStr directory = fs_savepath.GetString(); directory += "\\"; // so it doesn't think the last part is a file and ignores in the directory creation fileSystem->CreateOSPath( directory ); // we can't actually check FileExists in production builds, so just try to create it user->StorageSizeAvailable( requiredSizeBytes, callback->requiredSpaceInBytes ); if ( callback->requiredSpaceInBytes > 0 ) { callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM; // safe to return, haven't written any files yet return -1; } } } // Delete all previous files if needed // ALL THE FILES RIGHT NOW---- could use pattern later... for ( int i = 0; i < filesToDelete.Num() && !callback->cancelled; i++ ) { fileSystem->RemoveFile( filesToDelete[i].c_str() ); } // Save the raw files. for ( int i = 0; i < callback->files.Num() && ret == ERROR_SUCCESS && !callback->cancelled; i++ ) { idFile_SaveGame * file = callback->files[i]; idStr fileName = saveFolder; fileName.AppendPath( file->GetName() ); idStr tempFileName = va( "%s.temp", fileName.c_str() ); idFile * outputFile = fileSystem->OpenFileWrite( tempFileName, "fs_savePath" ); if ( outputFile == NULL ) { idLib::Warning( "[%s]: Couldn't open file for writing, %s. Error = %08x", __FUNCTION__, tempFileName.c_str(), GetLastError() ); file->error = true; callback->errorCode = SAVEGAME_E_UNKNOWN; ret = -1; continue; } if ( ( file->type & SAVEGAMEFILE_PIPELINED ) != 0 ) { idFile_SaveGamePipelined * inputFile = dynamic_cast< idFile_SaveGamePipelined * >( file ); assert( inputFile != NULL ); blockForIO_t block; while ( inputFile->NextWriteBlock( & block ) ) { if ( (size_t)outputFile->Write( block.data, block.bytes ) != block.bytes ) { idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() ); file->error = true; callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM; ret = -1; break; } } } else { if ( ( file->type & SAVEGAMEFILE_BINARY ) || ( file->type & SAVEGAMEFILE_COMPRESSED ) ) { if ( saveGame_checksum.GetBool() ) { unsigned int checksum = MD5_BlockChecksum( file->GetDataPtr(), file->Length() ); size_t size = outputFile->WriteBig( checksum ); if ( size != sizeof( checksum ) ) { idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() ); file->error = true; callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM; ret = -1; } } } size_t size = outputFile->Write( file->GetDataPtr(), file->Length() ); if ( size != (size_t)file->Length() ) { idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() ); file->error = true; callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM; ret = -1; } else { idLib::PrintfIf( saveGame_verbose.GetBool(), "Saved %s (%s)\n", fileName.c_str(), outputFile->GetFullPath() ); } } delete outputFile; if ( ret == ERROR_SUCCESS ) { // Remove the old file if ( !fileSystem->RenameFile( tempFileName, fileName, "fs_savePath" ) ) { idLib::Warning( "Could not start to rename temporary file %s to %s.", tempFileName.c_str(), fileName.c_str() ); } } else { fileSystem->RemoveFile( tempFileName ); idLib::Warning( "Invalid write to temporary file %s.", tempFileName.c_str() ); } } if ( data.saveLoadParms->cancelled ) { data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED; } // Removed because it seemed a bit drastic #if 0 // If there is an error, delete the partially saved folder if ( callback->errorCode != SAVEGAME_E_NONE ) { if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) { idFileList * files = fileSystem->ListFilesTree( saveFolder, "/|*" ); for ( int i = 0; i < files->GetNumFiles(); i++ ) { fileSystem->RemoveFile( files->GetFile( i ) ); } fileSystem->FreeFileList( files ); fileSystem->RemoveDir( saveFolder ); } } #endif return ret; }
/* =============== idCommonLocal::SaveGame =============== */ bool idCommonLocal::SaveGame( const char * saveName ) { if ( pipelineFile != NULL ) { // We're already in the middle of a save. Leave us alone. return false; } if ( com_disableAllSaves.GetBool() || ( com_disableAutoSaves.GetBool() && ( idStr::Icmp( saveName, "autosave" ) == 0 ) ) ) { return false; } if ( IsMultiplayer() ) { common->Printf( "Can't save during net play.\n" ); return false; } if (mapSpawnData.savegameFile != NULL ) { return false; } const idDict & persistentPlayerInfo = game->GetPersistentPlayerInfo( 0 ); if ( persistentPlayerInfo.GetInt( "health" ) <= 0 ) { common->Printf( "You must be alive to save the game\n" ); return false; } soundWorld->Pause(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); soundSystem->Render(); Dialog().ShowSaveIndicator( true ); if ( insideExecuteMapChange ) { UpdateLevelLoadPacifier(); } else { // Heremake sure we pump the gui enough times to show the 'saving' dialog const bool captureToImage = false; for ( int i = 0; i < NumScreenUpdatesToShowDialog; ++i ) { UpdateScreen( captureToImage ); } renderSystem->BeginAutomaticBackgroundSwaps( AUTORENDER_DIALOGICON ); } // Make sure the file is writable and the contents are cleared out (Set to write from the start of file) saveFile.MakeWritable(); saveFile.Clear( false ); stringsFile.MakeWritable(); stringsFile.Clear( false ); // Setup the save pipeline pipelineFile = new (TAG_SAVEGAMES) idFile_SaveGamePipelined(); pipelineFile->OpenForWriting( &saveFile ); // Write SaveGame Header: // Game Name / Version / Map Name / Persistant Player Info // game const char *gamename = GAME_NAME; saveFile.WriteString( gamename ); // map saveFile.WriteString( currentMapName ); saveFile.WriteBool( consoleUsed ); game->GetServerInfo().WriteToFileHandle( &saveFile ); // let the game save its state game->SaveGame( pipelineFile, &stringsFile ); pipelineFile->Finish(); idSaveGameDetails gameDetails; game->GetSaveGameDetails( gameDetails ); gameDetails.descriptors.Set( SAVEGAME_DETAIL_FIELD_LANGUAGE, sys_lang.GetString() ); gameDetails.descriptors.SetInt( SAVEGAME_DETAIL_FIELD_CHECKSUM, (int)gameDetails.descriptors.Checksum() ); gameDetails.slotName = saveName; ScrubSaveGameFileName( gameDetails.slotName ); saveFileEntryList_t files; files.Append( &stringsFile ); files.Append( &saveFile ); session->SaveGameSync( gameDetails.slotName, files, gameDetails ); if ( !insideExecuteMapChange ) { renderSystem->EndAutomaticBackgroundSwaps(); } syncNextGameFrame = true; return true; }
/* ===================== idAudioHardwareALSA::Initialize ===================== */ bool idAudioHardwareALSA::Initialize( void ) { int err; common->Printf( "------ Alsa Sound Initialization -----\n" ); if ( !DLOpen() ) { InitFailed(); return false; } if ( ( err = id_snd_pcm_open( &m_pcm_handle, s_alsa_pcm.GetString(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) < 0 ) { common->Printf( "snd_pcm_open SND_PCM_STREAM_PLAYBACK '%s' failed: %s\n", s_alsa_pcm.GetString(), id_snd_strerror( err ) ); InitFailed(); return false; } common->Printf( "opened Alsa PCM device %s for playback\n", s_alsa_pcm.GetString() ); // set hardware parameters ---------------------------------------------------------------------- // init hwparams with the full configuration space snd_pcm_hw_params_t *hwparams; // this one is a define id_snd_pcm_hw_params_alloca( &hwparams ); if ( ( err = id_snd_pcm_hw_params_any( m_pcm_handle, hwparams ) ) < 0 ) { common->Printf( "cannot configure the PCM device: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } if ( ( err = id_snd_pcm_hw_params_set_access( m_pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 ) { common->Printf( "SND_PCM_ACCESS_RW_INTERLEAVED failed: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } if ( ( err = id_snd_pcm_hw_params_set_format( m_pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE ) ) < 0 ) { common->Printf( "SND_PCM_FORMAT_S16_LE failed: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } // channels // sanity over number of speakers if ( idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 6 && idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 2 ) { common->Warning( "invalid value for s_numberOfSpeakers. Use either 2 or 6" ); idSoundSystemLocal::s_numberOfSpeakers.SetInteger( 2 ); } m_channels = idSoundSystemLocal::s_numberOfSpeakers.GetInteger(); if ( ( err = id_snd_pcm_hw_params_set_channels( m_pcm_handle, hwparams, m_channels ) ) < 0 ) { common->Printf( "error setting %d channels: %s\n", m_channels, id_snd_strerror( err ) ); if ( idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 2 ) { // fallback to stereo if that works m_channels = 2; if ( ( err = id_snd_pcm_hw_params_set_channels( m_pcm_handle, hwparams, m_channels ) ) < 0 ) { common->Printf( "fallback to stereo failed: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } else { common->Printf( "fallback to stereo\n" ); idSoundSystemLocal::s_numberOfSpeakers.SetInteger( 2 ); } } else { InitFailed(); return false; } } // set sample rate (frequency) if ( ( err = id_snd_pcm_hw_params_set_rate( m_pcm_handle, hwparams, PRIMARYFREQ, 0 ) ) < 0 ) { common->Printf( "failed to set 44.1KHz rate: %s - try ( +set s_alsa_pcm plughw:0 ? )\n", id_snd_strerror( err ) ); InitFailed(); return false; } // have enough space in the input buffer for our MIXBUFFER_SAMPLE feedings and async ticks snd_pcm_uframes_t frames; frames = MIXBUFFER_SAMPLES + MIXBUFFER_SAMPLES / 3; if ( ( err = id_snd_pcm_hw_params_set_buffer_size_min( m_pcm_handle, hwparams, &frames ) ) < 0 ) { common->Printf( "buffer size select failed: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } // apply parameters if ( ( err = id_snd_pcm_hw_params( m_pcm_handle, hwparams ) ) < 0 ) { common->Printf( "snd_pcm_hw_params failed: %s\n", id_snd_strerror( err ) ); InitFailed(); return false; } // check the buffer size if ( ( err = id_snd_pcm_hw_params_get_buffer_size( hwparams, &frames ) ) < 0 ) { common->Printf( "snd_pcm_hw_params_get_buffer_size failed: %s\n", id_snd_strerror( err ) ); } else { common->Printf( "device buffer size: %lu frames ( %lu bytes )\n", ( long unsigned int )frames, frames * m_channels * 2 ); } // TODO: can use swparams to setup the device so it doesn't underrun but rather loops over // snd_pcm_sw_params_set_stop_threshold // To get alsa to just loop on underruns. set the swparam stop_threshold to equal buffer size. The sound buffer will just loop and never throw an xrun. // allocate the final mix buffer m_buffer_size = MIXBUFFER_SAMPLES * m_channels * 2; m_buffer = malloc( m_buffer_size ); common->Printf( "allocated a mix buffer of %d bytes\n", m_buffer_size ); #ifdef _DEBUG // verbose the state snd_pcm_state_t curstate = id_snd_pcm_state( m_pcm_handle ); assert( curstate == SND_PCM_STATE_PREPARED ); #endif common->Printf( "--------------------------------------\n" ); return true; }
void idCollisionModelManagerLocal::DebugOutput( const idVec3& origin ) { int i, k, t; char buf[128]; idVec3 end; idAngles boxAngles; idMat3 modelAxis, boxAxis; idBounds bounds; trace_t trace; if( !cm_testCollision.GetBool() ) { return; } testend = ( idVec3* ) Mem_Alloc( cm_testTimes.GetInteger() * sizeof( idVec3 ), TAG_COLLISION ); if( cm_testReset.GetBool() || ( cm_testWalk.GetBool() && !start.Compare( start ) ) ) { total_translation = total_rotation = 0; min_translation = min_rotation = 999999; max_translation = max_rotation = -999999; num_translation = num_rotation = 0; cm_testReset.SetBool( false ); } if( cm_testWalk.GetBool() ) { start = origin; cm_testOrigin.SetString( va( "%1.2f %1.2f %1.2f", start[0], start[1], start[2] ) ); } else { sscanf( cm_testOrigin.GetString(), "%f %f %f", &start[0], &start[1], &start[2] ); } sscanf( cm_testBox.GetString(), "%f %f %f %f %f %f", &bounds[0][0], &bounds[0][1], &bounds[0][2], &bounds[1][0], &bounds[1][1], &bounds[1][2] ); sscanf( cm_testBoxRotation.GetString(), "%f %f %f", &boxAngles[0], &boxAngles[1], &boxAngles[2] ); boxAxis = boxAngles.ToMat3(); modelAxis.Identity(); idTraceModel itm( bounds ); idRandom random( 0 ); idTimer timer; if( cm_testRandomMany.GetBool() ) { // if many traces in one random direction for( i = 0; i < 3; i++ ) { testend[0][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat(); } for( k = 1; k < cm_testTimes.GetInteger(); k++ ) { testend[k] = testend[0]; } } else { // many traces each in a different random direction for( k = 0; k < cm_testTimes.GetInteger(); k++ ) { for( i = 0; i < 3; i++ ) { testend[k][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat(); } } } // translational collision detection timer.Clear(); timer.Start(); for( i = 0; i < cm_testTimes.GetInteger(); i++ ) { Translation( &trace, start, testend[i], &itm, boxAxis, CONTENTS_SOLID | CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis ); } timer.Stop(); t = timer.Milliseconds(); if( t < min_translation ) min_translation = t; if( t > max_translation ) max_translation = t; num_translation++; total_translation += t; if( cm_testTimes.GetInteger() > 9999 ) { sprintf( buf, "%3dK", ( int )( cm_testTimes.GetInteger() / 1000 ) ); } else { sprintf( buf, "%4d", cm_testTimes.GetInteger() ); } common->Printf( "%s translations: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_translation, max_translation, ( float ) total_translation / num_translation ); if( cm_testRandomMany.GetBool() ) { // if many traces in one random direction for( i = 0; i < 3; i++ ) { testend[0][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat(); } for( k = 1; k < cm_testTimes.GetInteger(); k++ ) { testend[k] = testend[0]; } } else { // many traces each in a different random direction for( k = 0; k < cm_testTimes.GetInteger(); k++ ) { for( i = 0; i < 3; i++ ) { testend[k][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat(); } } } if( cm_testRotation.GetBool() ) { // rotational collision detection idVec3 vec( random.CRandomFloat(), random.CRandomFloat(), random.RandomFloat() ); vec.Normalize(); idRotation rotation( vec3_origin, vec, cm_testAngle.GetFloat() ); timer.Clear(); timer.Start(); for( i = 0; i < cm_testTimes.GetInteger(); i++ ) { rotation.SetOrigin( testend[i] ); Rotation( &trace, start, rotation, &itm, boxAxis, CONTENTS_SOLID | CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis ); } timer.Stop(); t = timer.Milliseconds(); if( t < min_rotation ) min_rotation = t; if( t > max_rotation ) max_rotation = t; num_rotation++; total_rotation += t; if( cm_testTimes.GetInteger() > 9999 ) { sprintf( buf, "%3dK", ( int )( cm_testTimes.GetInteger() / 1000 ) ); } else { sprintf( buf, "%4d", cm_testTimes.GetInteger() ); } common->Printf( "%s rotation: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_rotation, max_rotation, ( float ) total_rotation / num_rotation ); } Mem_Free( testend ); testend = NULL; }
/* =============== idCommonLocal::LoadGame =============== */ bool idCommonLocal::LoadGame( const char * saveName ) { if ( IsMultiplayer() ) { common->Printf( "Can't load during net play.\n" ); if ( wipeForced ) { ClearWipe(); } return false; } if ( GetCurrentGame() != DOOM3_BFG ) { return false; } if ( session->GetSignInManager().GetMasterLocalUser() == NULL ) { return false; } if (mapSpawnData.savegameFile != NULL ) { return false; } bool found = false; const saveGameDetailsList_t & sgdl = session->GetSaveGameManager().GetEnumeratedSavegames(); for ( int i = 0; i < sgdl.Num(); i++ ) { if ( sgdl[i].slotName == saveName ) { if ( sgdl[i].GetLanguage() != sys_lang.GetString() ) { idStaticList< idSWFScriptFunction *, 4 > callbacks; idStaticList< idStrId, 4 > optionText; optionText.Append( idStrId( "#str_swf_continue" ) ); idStrStatic<256> langName = "#str_lang_" + sgdl[i].GetLanguage(); idStrStatic<256> msg; msg.Format( idLocalization::GetString( "#str_dlg_wrong_language" ), idLocalization::GetString( langName ) ); Dialog().AddDynamicDialog( GDM_SAVEGAME_WRONG_LANGUAGE, callbacks, optionText, true, msg, false, true ); if ( wipeForced ) { ClearWipe(); } return false; } found = true; break; } } if ( !found ) { common->Printf( "Could not find save '%s'\n", saveName ); if ( wipeForced ) { ClearWipe(); } return false; } mapSpawnData.savegameFile = &saveFile; mapSpawnData.stringTableFile = &stringsFile; saveFileEntryList_t files; files.Append( mapSpawnData.stringTableFile ); files.Append( mapSpawnData.savegameFile ); idStr slotName = saveName; ScrubSaveGameFileName( slotName ); saveFile.Clear( false ); stringsFile.Clear( false ); saveGameHandle_t loadGameHandle = session->LoadGameSync( slotName, files ); if ( loadGameHandle != 0 ) { return true; } mapSpawnData.savegameFile = NULL; if ( wipeForced ) { ClearWipe(); } return false; }
/* ================== idCommonLocal::VPrintf A raw string should NEVER be passed as fmt, because of "%f" type crashes. ================== */ void idCommonLocal::VPrintf( const char *fmt, va_list args ) { static bool logFileFailed = false; // if the cvar system is not initialized if ( !cvarSystem->IsInitialized() ) { return; } // optionally put a timestamp at the beginning of each print, // so we can see how long different init sections are taking int timeLength = 0; char msg[MAX_PRINT_MSG_SIZE]; msg[ 0 ] = '\0'; if ( com_timestampPrints.GetInteger() ) { int t = Sys_Milliseconds(); if ( com_timestampPrints.GetInteger() == 1 ) { sprintf( msg, "[%5.2f]", t * 0.001f ); } else { sprintf( msg, "[%i]", t ); } } timeLength = strlen( msg ); // don't overflow if ( idStr::vsnPrintf( msg+timeLength, MAX_PRINT_MSG_SIZE-timeLength-1, fmt, args ) < 0 ) { msg[sizeof(msg)-2] = '\n'; msg[sizeof(msg)-1] = '\0'; // avoid output garbling Sys_Printf( "idCommon::VPrintf: truncated to %d characters\n", strlen(msg)-1 ); } if ( rd_buffer ) { if ( (int)( strlen( msg ) + strlen( rd_buffer ) ) > ( rd_buffersize - 1 ) ) { rd_flush( rd_buffer ); *rd_buffer = 0; } strcat( rd_buffer, msg ); return; } #ifndef ID_RETAIL if ( com_printFilter.GetString() != NULL && com_printFilter.GetString()[ 0 ] != '\0' ) { idStrStatic< 4096 > filterBuf = com_printFilter.GetString(); idStrStatic< 4096 > msgBuf = msg; filterBuf.ToLower(); msgBuf.ToLower(); char *sp = strtok( &filterBuf[ 0 ], ";" ); bool p = false; for( ; sp != NULL ; ) { if ( strstr( msgBuf, sp ) != NULL ) { p = true; break; } sp = strtok( NULL, ";" ); } if ( !p ) { return; } } #endif if ( !idLib::IsMainThread() ) { #if defined( ID_PC_WIN ) OutputDebugString( msg ); #else printf( "%s", msg ); #endif // ID_PC_WIN return; } // echo to console buffer console->Print( msg ); // remove any color codes idStr::RemoveColors( msg ); // echo to dedicated console and early console Sys_Printf( "%s", msg ); // print to script debugger server // DebuggerServerPrint( msg ); #if 0 // !@# #if defined(_DEBUG) && defined(WIN32) if ( strlen( msg ) < 512 ) { TRACE( msg ); } #endif #endif // logFile if ( com_logFile.GetInteger() && !logFileFailed && fileSystem->IsInitialized() ) { static bool recursing; if ( !logFile && !recursing ) { const char *fileName = com_logFileName.GetString()[0] ? com_logFileName.GetString() : "qconsole.log"; // fileSystem->OpenFileWrite can cause recursive prints into here recursing = true; logFile = fileSystem->OpenFileWrite( fileName ); if ( !logFile ) { logFileFailed = true; FatalError( "failed to open log file '%s'\n", fileName ); } recursing = false; if ( com_logFile.GetInteger() > 1 ) { // force it to not buffer so we get valid // data even if we are crashing logFile->ForceFlush(); } time_t aclock; time( &aclock ); struct tm * newtime = localtime( &aclock ); Printf( "log file '%s' opened on %s\n", fileName, asctime( newtime ) ); } if ( logFile ) { logFile->Write( msg, strlen( msg ) ); logFile->Flush(); // ForceFlush doesn't help a whole lot } } // don't trigger any updates if we are in the process of doing a fatal error if ( com_errorEntered != ERP_FATAL ) { // update the console if we are in a long-running command, like dmap if ( com_refreshOnPrint ) { const bool captureToImage = false; UpdateScreen( captureToImage ); } } }
/* ======================== idSoundHardware_XAudio2::Update ======================== */ void idSoundHardware_XAudio2::Update() { if( pXAudio2 == NULL ) { int nowTime = Sys_Milliseconds(); if( lastResetTime + 1000 < nowTime ) { lastResetTime = nowTime; Init(); } return; } if( soundSystem->IsMuted() ) { pMasterVoice->SetVolume( 0.0f, OPERATION_SET ); } else { pMasterVoice->SetVolume( DBtoLinear( s_volume_dB.GetFloat() ), OPERATION_SET ); } pXAudio2->CommitChanges( XAUDIO2_COMMIT_ALL ); // IXAudio2SourceVoice::Stop() has been called for every sound on the // zombie list, but it is documented as asyncronous, so we have to wait // until it actually reports that it is no longer playing. for( int i = 0; i < zombieVoices.Num(); i++ ) { zombieVoices[i]->FlushSourceBuffers(); if( !zombieVoices[i]->IsPlaying() ) { freeVoices.Append( zombieVoices[i] ); zombieVoices.RemoveIndexFast( i ); i--; } else { static int playingZombies; playingZombies++; } } if( s_showPerfData.GetBool() ) { XAUDIO2_PERFORMANCE_DATA perfData; pXAudio2->GetPerformanceData( &perfData ); idLib::Printf( "Voices: %d/%d CPU: %.2f%% Mem: %dkb\n", perfData.ActiveSourceVoiceCount, perfData.TotalSourceVoiceCount, perfData.AudioCyclesSinceLastQuery / ( float )perfData.TotalCyclesSinceLastQuery, perfData.MemoryUsageInBytes / 1024 ); } if( vuMeterRMS == NULL ) { // Init probably hasn't been called yet return; } vuMeterRMS->Enable( s_showLevelMeter.GetBool() ); vuMeterPeak->Enable( s_showLevelMeter.GetBool() ); if( !s_showLevelMeter.GetBool() ) { pMasterVoice->DisableEffect( 0 ); return; } else { pMasterVoice->EnableEffect( 0 ); } float peakLevels[ 8 ]; float rmsLevels[ 8 ]; XAUDIO2FX_VOLUMEMETER_LEVELS levels; levels.ChannelCount = outputChannels; levels.pPeakLevels = peakLevels; levels.pRMSLevels = rmsLevels; if( levels.ChannelCount > 8 ) { levels.ChannelCount = 8; } pMasterVoice->GetEffectParameters( 0, &levels, sizeof( levels ) ); int currentTime = Sys_Milliseconds(); for( int i = 0; i < outputChannels; i++ ) { if( vuMeterPeakTimes[i] < currentTime ) { vuMeterPeak->SetValue( i, vuMeterPeak->GetValue( i ) * 0.9f, colorRed ); } } float width = 20.0f; float height = 200.0f; float left = 100.0f; float top = 100.0f; sscanf( s_meterPosition.GetString(), "%f %f %f %f", &left, &top, &width, &height ); vuMeterRMS->SetPosition( left, top, width * levels.ChannelCount, height ); vuMeterPeak->SetPosition( left, top, width * levels.ChannelCount, height ); for( uint32 i = 0; i < levels.ChannelCount; i++ ) { vuMeterRMS->SetValue( i, rmsLevels[ i ], idVec4( 0.5f, 1.0f, 0.0f, 1.00f ) ); if( peakLevels[ i ] >= vuMeterPeak->GetValue( i ) ) { vuMeterPeak->SetValue( i, peakLevels[ i ], colorRed ); vuMeterPeakTimes[i] = currentTime + s_meterTopTime.GetInteger(); } } }
const char* Sys_DefaultLanguage() { // sku breakdowns are as follows // EFIGS Digital // EF S North America // FIGS EU // E UK // JE Japan // If japanese exists, default to japanese // else if english exists, defaults to english // otherwise, french if( !fileSystem->UsingResourceFiles() ) { return ID_LANG_ENGLISH; } idStr fileName; //D3XP: Instead of just loading a single lang file for each language //we are going to load all files that begin with the language name //similar to the way pak files work. So you can place english001.lang //to add new strings to the english language dictionary idFileList* langFiles; langFiles = fileSystem->ListFilesTree( "strings", ".lang", true ); idStrList langList = langFiles->GetList(); // Loop through the list and filter idStrList currentLangList = langList; idStr temp; for( int i = 0; i < currentLangList.Num(); i++ ) { temp = currentLangList[i]; temp = temp.Right( temp.Length() - strlen( "strings/" ) ); temp = temp.Left( temp.Length() - strlen( ".lang" ) ); currentLangList[i] = temp; } if( currentLangList.Num() <= 0 ) { // call it English if no lang files exist sys_lang.SetString( ID_LANG_ENGLISH ); } else if( currentLangList.Num() == 1 ) { sys_lang.SetString( currentLangList[0] ); } else { if( currentLangList.Find( ID_LANG_JAPANESE ) ) { sys_lang.SetString( ID_LANG_JAPANESE ); } else if( currentLangList.Find( ID_LANG_ENGLISH ) ) { sys_lang.SetString( ID_LANG_ENGLISH ); } else if( currentLangList.Find( ID_LANG_FRENCH ) ) { sys_lang.SetString( ID_LANG_FRENCH ); } else if( currentLangList.Find( ID_LANG_GERMAN ) ) { sys_lang.SetString( ID_LANG_GERMAN ); } else if( currentLangList.Find( ID_LANG_ITALIAN ) ) { sys_lang.SetString( ID_LANG_GERMAN ); } else if( currentLangList.Find( ID_LANG_SPANISH ) ) { sys_lang.SetString( ID_LANG_GERMAN ); } else { sys_lang.SetString( currentLangList[0] ); } } fileSystem->FreeFileList( langFiles ); return sys_lang.GetString();// ID_LANG_ENGLISH; }
/* ============ sdUICrosshairInfo::DrawDamageIndicators ============ */ void sdUICrosshairInfo::DrawDamageIndicators( idPlayer* player ) { const float width = SCREEN_WIDTH * 1.0f / deviceContext->GetAspectRatioCorrection(); static idWinding2D drawWinding; float w = g_damageIndicatorWidth.GetFloat(); float h = g_damageIndicatorHeight.GetFloat(); float x = -( w * 0.5f ); float y = -( h * 0.5f ) - g_damageIndicatorHeight.GetFloat(); float viewYaw = player->renderView.viewaxis.ToAngles().yaw; float fadeTime = SEC2MS( g_damageIndicatorFadeTime.GetFloat() ); idMat2 matrix; for( int i = 0; i < player->damageEvents.Num(); i++ ) { const idPlayer::damageEvent_t& event = player->damageEvents[ i ]; if( event.hitTime <= 0 ) { continue; } idVec4 color; if ( event.hitDamage > 0 ) { color.ToVec3() = sdTypeFromString< idVec3 >( g_damageIndicatorColor.GetString() ); } else { color.ToVec3() = sdTypeFromString< idVec3 >( g_repairIndicatorColor.GetString() ); } color.w = 1.0f - static_cast< float > ( gameLocal.time - event.hitTime ) / fadeTime; if ( event.hitDamage > 0 ) { color.w *= g_damageIndicatorAlphaScale.GetFloat(); } else { color.w *= g_repairIndicatorAlphaScale.GetFloat(); } if( color.w <= 0.0f || color.w > 1.0f ) { continue; } uiDrawPart_t* part = NULL; if( event.hitDamage <= 20.0f ) { part = &crosshairParts[ CP_SMALL_DAMAGE ]; } else if( event.hitDamage <= 40.0f ) { part = &crosshairParts[ CP_MEDIUM_DAMAGE ]; } else { part = &crosshairParts[ CP_LARGE_DAMAGE ]; } drawWinding.Clear(); drawWinding.AddPoint( x, y, part->mi.st0.x, part->mi.st0.y ); drawWinding.AddPoint( x + w, y, part->mi.st1.x, part->mi.st0.y ); drawWinding.AddPoint( x + w, y + h, part->mi.st1.x, part->mi.st1.y ); drawWinding.AddPoint( x, y + h, part->mi.st0.x, part->mi.st1.y ); float angle = event.hitAngle; if ( event.updateDirection ) { angle -= viewYaw; } matrix.Rotation( DEG2RAD( angle ) ); for( int i = 0; i < drawWinding.GetNumPoints(); i++ ) { idVec2& pt = drawWinding[ i ]; pt *= matrix; pt.x += width * 0.5f; pt.y += SCREEN_HEIGHT * 0.5f; } deviceContext->DrawWindingMaterial( drawWinding, part->mi.material, color ); } }
/* ======================== idSoundSample_XAudio2::Load ======================== */ void idSoundSample_XAudio2::LoadResource() { FreeData(); if ( idStr::Icmpn( GetName(), "_default", 8 ) == 0 ) { MakeDefault(); return; } if ( s_noSound.GetBool() ) { MakeDefault(); return; } loaded = false; for ( int i = 0; i < 2; i++ ) { idStrStatic< MAX_OSPATH > sampleName = GetName(); if ( ( i == 0 ) && !sampleName.Replace( "/vo/", va( "/vo/%s/", sys_lang.GetString() ) ) ) { i++; } idStrStatic< MAX_OSPATH > generatedName = "generated/"; generatedName.Append( sampleName ); { if ( s_useCompression.GetBool() ) { sampleName.Append( ".msadpcm" ); } else { sampleName.Append( ".wav" ); } generatedName.Append( ".idwav" ); } loaded = LoadGeneratedSample( generatedName ) || LoadWav( sampleName ); if ( !loaded && s_useCompression.GetBool() ) { sampleName.SetFileExtension( "wav" ); loaded = LoadWav( sampleName ); } if ( loaded ) { if ( cvarSystem->GetCVarBool( "fs_buildresources" ) ) { fileSystem->AddSamplePreload( GetName() ); WriteAllSamples( GetName() ); if ( sampleName.Find( "/vo/" ) >= 0 ) { for ( int i = 0; i < Sys_NumLangs(); i++ ) { const char * lang = Sys_Lang( i ); if ( idStr::Icmp( lang, ID_LANG_ENGLISH ) == 0 ) { continue; } idStrStatic< MAX_OSPATH > locName = GetName(); locName.Replace( "/vo/", va( "/vo/%s/", Sys_Lang( i ) ) ); WriteAllSamples( locName ); } } } return; } } if ( !loaded ) { // make it default if everything else fails MakeDefault(); } return; }