/* ================ idCommonLocal::ProcessGameReturn ================ */ void idCommonLocal::ProcessGameReturn( const gameReturn_t & ret ) { // set joystick rumble if ( in_useJoystick.GetBool() && in_joystickRumble.GetBool() && !game->Shell_IsActive() && session->GetSignInManager().GetMasterInputDevice() >= 0 ) { Sys_SetRumble( session->GetSignInManager().GetMasterInputDevice(), ret.vibrationLow, ret.vibrationHigh ); // Only set the rumble on the active controller } else { for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_SetRumble( i, 0, 0 ); } } syncNextGameFrame = ret.syncNextGameFrame; if ( ret.sessionCommand[0] ) { idCmdArgs args; args.TokenizeString( ret.sessionCommand, false ); if ( !idStr::Icmp( args.Argv(0), "map" ) ) { MoveToNewMap( args.Argv( 1 ), false ); } else if ( !idStr::Icmp( args.Argv(0), "devmap" ) ) { MoveToNewMap( args.Argv( 1 ), true ); } else if ( !idStr::Icmp( args.Argv(0), "died" ) ) { if ( !IsMultiplayer() ) { game->Shell_Show( true ); } } else if ( !idStr::Icmp( args.Argv(0), "disconnect" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_INSERT, "stoprecording ; disconnect" ); } else if ( !idStr::Icmp( args.Argv(0), "endOfDemo" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_NOW, "endOfDemo" ); } } }
bool NumPlayersSelection( GameMode mode, GraphicsDevice *graphics, EventHandlers *handlers) { MenuSystem ms; MenuSystemInit( &ms, handlers, graphics, Vec2iZero(), graphics->cachedConfig.Res); ms.allowAborts = true; ms.root = ms.current = MenuCreateNormal( "", "Select number of players", MENU_TYPE_NORMAL, 0); for (int i = 0; i < MAX_LOCAL_PLAYERS; i++) { char buf[2]; if (IsMultiplayer(mode) && i == 0) { // At least two players for dogfights continue; } sprintf(buf, "%d", i + 1); MenuAddSubmenu(ms.current, MenuCreateReturn(buf, i + 1)); } MenuAddExitType(&ms, MENU_TYPE_RETURN); MenuLoop(&ms); const bool ok = !ms.hasAbort; if (ok) { const int numPlayers = ms.current->u.returnCode; for (int i = 0; i < (int)gPlayerDatas.size; i++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); CASSERT(!p->IsLocal, "unexpected local player"); } if (NetClientIsConnected(&gNetClient)) { // Tell the server that we want to add new players NetMsgNewPlayers np; np.ClientId = gNetClient.ClientId; np.NumPlayers = numPlayers; NetClientSendMsg(&gNetClient, MSG_NEW_PLAYERS, &np); } else { // We are the server, just add the players for (int i = 0; i < numPlayers; i++) { PlayerData *p = PlayerDataAdd(&gPlayerDatas); PlayerDataSetLocalDefaults(p, i); p->inputDevice = INPUT_DEVICE_UNSET; } } } MenuSystemTerminate(&ms); return ok; }
edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) { edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); if ( IsMultiplayer() && pentSpawnSpot->v.target ) { FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); } return pentSpawnSpot; }
void CGameLobbyManager::DoPendingDeleteSession(CGameLobby *pLobby) { CryLog("CGameLobbyManager::DoPendingDeleteSession() pLobby:%p", pLobby); if(pLobby == m_primaryLobby) { if(m_nextLobby) { CRY_ASSERT(m_primaryLobby && m_nextLobby); SAFE_DELETE(m_primaryLobby); m_primaryLobby = m_nextLobby; m_nextLobby = NULL; m_primaryLobby->SwitchToPrimaryLobby(); SetPrivateGame(m_primaryLobby, m_primaryLobby->IsPrivateGame()); CryLog("CGameLobbyManager::DoPendingDeleteSession - Moved to next session"); } else { CryLog("CGameLobbyManager::DoPendingDeleteSession - No sessions left"); #ifdef USE_C2_FRONTEND CFlashFrontEnd *pFlashMenu = g_pGame->GetFlashMenu(); if (pFlashMenu) { // Have to go all the way back to main then forward to play_online because the stack may // not include play_online (destroyed when we do a level rotation) if (IsMultiplayer() && pFlashMenu->IsScreenInStack("game_lobby")) { if (CMPMenuHub *pMPMenu = CMPMenuHub::GetMPMenuHub()) { pMPMenu->GoToCurrentLobbyServiceScreen(); // go to correct lobby service screen - play_online or play_lan } } } #endif //#ifdef USE_C2_FRONTEND CSquadManager *pSquadManager = g_pGame->GetSquadManager(); if (pSquadManager) { pSquadManager->GameSessionIdChanged(CSquadManager::eGSC_LeftSession, CrySessionInvalidID); } SetPrivateGame(NULL, false); } } else if(pLobby == m_nextLobby) { CryLog("CGameLobbyManager::DoPendingDeleteSession - Next Lobby deleted"); SAFE_DELETE(m_nextLobby); } m_bMergingIsComplete = false; }
//========================================================= // CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal //========================================================= int CSatchel::AddDuplicate(CBasePlayerItem *pOriginal) { CSatchel *pSatchel; if (IsMultiplayer()) { pSatchel = (CSatchel *)pOriginal; if (pSatchel->m_chargeReady != 0)return FALSE; } return CBasePlayerWeapon::AddDuplicate(pOriginal); }
void CRpg::Spawn() { Precache(); m_iId = WEAPON_RPG; SET_MODEL(ENT(pev), "models/w_rpg.mdl"); m_iOverloadLevel = TRUE;//turn on LTD if (IsMultiplayer())m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; else m_iDefaultAmmo = RPG_DEFAULT_GIVE; FallInit();// get ready to fall down. }
/* =============== idSessionLocal::SetMainMenuGuiVars =============== */ void idSessionLocal::SetMainMenuGuiVars(void) { guiMainMenu->SetStateString("serverlist_sel_0", "-1"); guiMainMenu->SetStateString("serverlist_selid_0", "-1"); guiMainMenu->SetStateInt("com_machineSpec", com_machineSpec.GetInteger()); // "inetGame" will hold a hand-typed inet address, which is not archived to a cvar guiMainMenu->SetStateString("inetGame", ""); // key bind names guiMainMenu->SetKeyBindingNames(); // flag for in-game menu if (mapSpawned) { guiMainMenu->SetStateString("inGame", IsMultiplayer() ? "2" : "1"); } else { guiMainMenu->SetStateString("inGame", "0"); } SetCDKeyGuiVars(); #ifdef ID_DEMO_BUILD guiMainMenu->SetStateString("nightmare", "0"); #else guiMainMenu->SetStateString("nightmare", cvarSystem->GetCVarBool("g_nightmare") ? "1" : "0"); #endif guiMainMenu->SetStateString("browser_levelshot", "guis/assets/splash/pdtempa"); SetMainMenuSkin(); // Mods Menu SetModsMenuGuiVars(); guiMsg->SetStateString("visible_hasxp", fileSystem->HasD3XP() ? "1" : "0"); #if defined( __linux__ ) guiMainMenu->SetStateString("driver_prompt", "1"); #else guiMainMenu->SetStateString("driver_prompt", "0"); #endif SetPbMenuGuiVars(); }
void CTriggerHurt :: Touch ( CBaseEntity *pOther ) { float fldmg; if ( !pOther->pev->takedamage ) return; if ( !FBitSet( pOther->pev->flags, FL_CLIENT|FL_MONSTER ) && !pOther->IsPushable() ) return; if ( IsMultiplayer() ) { if ( pev->dmgtime > gpGlobals->time ) { if ( gpGlobals->time != pev->dmg_take ) { // too early to hurt again, and not same frame with a different entity if ( pOther->IsPlayer() ) { int playerMask = 1 << (pOther->entindex() - 1); if ( pev->impulse & playerMask ) return; pev->impulse |= playerMask; } else return; } } else { pev->impulse = 0; if ( pOther->IsPlayer() ) { int playerMask = 1 << (pOther->entindex() - 1); pev->impulse |= playerMask; } } } else if( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->dmg_take ) return; fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second if ( fldmg < 0 ) pOther->TakeHealth( -fldmg, pev->button ); else pOther->TakeDamage( pev, pev, fldmg, pev->button ); pev->dmg_take = gpGlobals->time; pev->dmgtime = gpGlobals->time + 0.5; }
BOOL AddAmmo(CBaseEntity *pOther) { int iGive; if (IsMultiplayer()) { // hand out more ammo per rocket in multiplayer. iGive = AMMO_RPGCLIP_GIVE * 2; } else { iGive = AMMO_RPGCLIP_GIVE; } if (pOther->GiveAmmo(iGive, "rockets", ROCKET_MAX_CARRY) != -1) { EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); return TRUE; } return FALSE; }
void CTriggerCamera :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( pActivator && pActivator->IsPlayer( )) { // only at player m_hActivator = pActivator; } else if( !IsMultiplayer( )) { m_hActivator = UTIL_PlayerByIndex( 1 ); } else { ALERT( at_warning, "%s: %s activator not player. Ignored.\n", STRING( pev->classname ), STRING( pev->targetname )); return; } if ( useType == USE_TOGGLE ) { if ( m_iState == STATE_OFF ) useType = USE_ON; else useType = USE_OFF; } if ( useType == USE_ON ) { TurnOn(); } else if ( useType == USE_OFF ) { TurnOff(); } else if ( useType == USE_SHOWINFO ) { ALERT( at_console, "======/Xash Debug System/======\n"); ALERT( at_console, "classname: %s\n", STRING( pev->classname )); ALERT( at_console, "State: %s, Look at %s\n", GetStringForState( GetState()), pev->netname ? STRING( pev->netname ) : STRING( pev->targetname )); ALERT( at_console, "Speed: %g Camera target: %s\n", pev->speed, pTarget ? STRING(pTarget->pev->targetname) : "None" ); } }
/* ================= idCommonLocal::Frame ================= */ void idCommonLocal::Frame() { try { SCOPED_PROFILE_EVENT( "Common::Frame" ); // This is the only place this is incremented idLib::frameNumber++; // allow changing SIMD usage on the fly if ( com_forceGenericSIMD.IsModified() ) { idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() ); com_forceGenericSIMD.ClearModified(); } // Do the actual switch between Doom 3 and the classics here so // that things don't get confused in the middle of the frame. PerformGameSwitch(); // pump all the events Sys_GenerateEvents(); // write config file if anything changed WriteConfiguration(); eventLoop->RunEventLoop(); // Activate the shell if it's been requested if ( showShellRequested && game ) { game->Shell_Show( true ); showShellRequested = false; } // if the console or another gui is down, we don't need to hold the mouse cursor bool chatting = false; if ( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) ) { Sys_GrabMouseCursor( false ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true ); chatting = true; } else { Sys_GrabMouseCursor( true ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false ); } const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic(); // save the screenshot and audio from the last draw if needed if ( aviCaptureMode ) { idStr name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ ); renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); // remove any printed lines at the top before taking the screenshot console->ClearNotifyLines(); // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1 renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); } //-------------------------------------------- // wait for the GPU to finish drawing // // It is imporant to minimize the time spent between this // section and the call to renderSystem->RenderCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // this should exit right after vsync, with the GPU idle and ready to draw // This may block if the GPU isn't finished renderng the previous frame. frameTiming.startSyncTime = Sys_Microseconds(); const emptyCommand_t * renderCommands = NULL; if ( com_smp.GetBool() ) { renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } else { // the GPU will stay idle through command generation for minimal // input latency renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } frameTiming.finishSyncTime = Sys_Microseconds(); //-------------------------------------------- // Determine how many game tics we are going to run, // now that the previous frame is completely finished. // // It is important that any waiting on the GPU be done // before this, or there will be a bad stuttering when // dropping frames for performance management. //-------------------------------------------- // input: // thisFrameTime // com_noSleep // com_engineHz // com_fixedTic // com_deltaTimeClamp // IsMultiplayer // // in/out state: // gameFrame // gameTimeResidual // lastFrameTime // syncNextFrame // // Output: // numGameFrames // How many game frames to run int numGameFrames = 0; for(;;) { const int thisFrameTime = Sys_Milliseconds(); static int lastFrameTime = thisFrameTime; // initialized only the first time const int deltaMilliseconds = thisFrameTime - lastFrameTime; lastFrameTime = thisFrameTime; // if there was a large gap in time since the last frame, or the frame // rate is very very low, limit the number of frames we will run const int clampedDeltaMilliseconds = Min( deltaMilliseconds, com_deltaTimeClamp.GetInteger() ); gameTimeResidual += clampedDeltaMilliseconds * timescale.GetFloat(); // don't run any frames when paused if ( pauseGame ) { gameFrame++; gameTimeResidual = 0; break; } // debug cvar to force multiple game tics if ( com_fixedTic.GetInteger() > 0 ) { numGameFrames = com_fixedTic.GetInteger(); gameFrame += numGameFrames; gameTimeResidual = 0; break; } if ( syncNextGameFrame ) { // don't sleep at all syncNextGameFrame = false; gameFrame++; numGameFrames++; gameTimeResidual = 0; break; } for ( ;; ) { // How much time to wait before running the next frame, // based on com_engineHz const int frameDelay = FRAME_TO_MSEC( gameFrame + 1 ) - FRAME_TO_MSEC( gameFrame ); if ( gameTimeResidual < frameDelay ) { break; } gameTimeResidual -= frameDelay; gameFrame++; numGameFrames++; // if there is enough residual left, we may run additional frames } if ( numGameFrames > 0 ) { // ready to actually run them break; } // if we are vsyncing, we always want to run at least one game // frame and never sleep, which might happen due to scheduling issues // if we were just looking at real time. if ( com_noSleep.GetBool() ) { numGameFrames = 1; gameFrame += numGameFrames; gameTimeResidual = 0; break; } // not enough time has passed to run a frame, as might happen if // we don't have vsync on, or the monitor is running at 120hz while // com_engineHz is 60, so sleep a bit and check again Sys_Sleep( 0 ); } //-------------------------------------------- // It would be better to push as much of this as possible // either before or after the renderSystem->SwapCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // Update session and syncronize to the new session state after sleeping session->UpdateSignInManager(); session->Pump(); session->ProcessSnapAckQueue(); if ( session->GetState() == idSession::LOADING ) { // If the session reports we should be loading a map, load it! ExecuteMapChange(); mapSpawnData.savegameFile = NULL; mapSpawnData.persistentPlayerInfo.Clear(); return; } else if ( session->GetState() != idSession::INGAME && mapSpawned ) { // If the game is running, but the session reports we are not in a game, disconnect // This happens when a server disconnects us or we sign out LeaveGame(); return; } if ( mapSpawned && !pauseGame ) { if ( IsClient() ) { RunNetworkSnapshotFrame(); } } ExecuteReliableMessages(); // send frame and mouse events to active guis GuiFrameEvents(); //-------------------------------------------- // Prepare usercmds and kick off the game processing // in a background thread //-------------------------------------------- // get the previous usercmd for bypassed head tracking transform const usercmd_t previousCmd = usercmdGen->GetCurrentUsercmd(); // build a new usercmd int deviceNum = session->GetSignInManager().GetMasterInputDevice(); usercmdGen->BuildCurrentUsercmd( deviceNum ); if ( deviceNum == -1 ) { for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_PollJoystickInputEvents( i ); Sys_EndJoystickInputEvents(); } } if ( pauseGame ) { usercmdGen->Clear(); } usercmd_t newCmd = usercmdGen->GetCurrentUsercmd(); // Store server game time - don't let time go past last SS time in case we are extrapolating if ( IsClient() ) { newCmd.serverGameMilliseconds = std::min( Game()->GetServerGameTimeMs(), Game()->GetSSEndTime() ); } else { newCmd.serverGameMilliseconds = Game()->GetServerGameTimeMs(); } userCmdMgr.MakeReadPtrCurrentForPlayer( Game()->GetLocalClientNum() ); // Stuff a copy of this userCmd for each game frame we are going to run. // Ideally, the usercmds would be built in another thread so you could // still get 60hz control accuracy when the game is running slower. for ( int i = 0 ; i < numGameFrames ; i++ ) { newCmd.clientGameMilliseconds = FRAME_TO_MSEC( gameFrame-numGameFrames+i+1 ); userCmdMgr.PutUserCmdForPlayer( game->GetLocalClientNum(), newCmd ); } // If we're in Doom or Doom 2, run tics and upload the new texture. if ( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() ) ) { RunDoomClassicFrame(); } // start the game / draw command generation thread going in the background gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames ); if ( !com_smp.GetBool() ) { // in non-smp mode, run the commands we just generated, instead of // frame-delayed ones from a background thread renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers(); } //---------------------------------------- // Run the render back end, getting the GPU busy with new commands // ASAP to minimize the pipeline bubble. //---------------------------------------- frameTiming.startRenderTime = Sys_Microseconds(); renderSystem->RenderCommandBuffers( renderCommands ); if ( com_sleepRender.GetInteger() > 0 ) { // debug tool to test frame adaption Sys_Sleep( com_sleepRender.GetInteger() ); } frameTiming.finishRenderTime = Sys_Microseconds(); // make sure the game / draw thread has completed // This may block if the game is taking longer than the render back end gameThread.WaitForThread(); // Send local usermds to the server. // This happens after the game frame has run so that prediction data is up to date. SendUsercmds( Game()->GetLocalClientNum() ); // Now that we have an updated game frame, we can send out new snapshots to our clients session->Pump(); // Pump to get updated usercmds to relay SendSnapshots(); // Render the sound system using the latest commands from the game thread if ( pauseGame ) { soundWorld->Pause(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); } else { soundWorld->UnPause(); soundSystem->SetPlayingSoundWorld( soundWorld ); } soundSystem->Render(); // process the game return for map changes, etc ProcessGameReturn( ret ); idLobbyBase & lobby = session->GetActivePlatformLobbyBase(); if ( lobby.HasActivePeers() ) { if ( net_drawDebugHud.GetInteger() == 1 ) { lobby.DrawDebugNetworkHUD(); } if ( net_drawDebugHud.GetInteger() == 2 ) { lobby.DrawDebugNetworkHUD2(); } lobby.DrawDebugNetworkHUD_ServerSnapshotMetrics( net_drawDebugHud.GetInteger() == 3 ); } // report timing information if ( com_speeds.GetBool() ) { static int lastTime = Sys_Milliseconds(); int nowTime = Sys_Milliseconds(); int com_frameMsec = nowTime - lastTime; lastTime = nowTime; Printf( "frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld\n", idLib::frameNumber, com_frameMsec, time_gameFrame, time_frontend / 1000, time_backend / 1000 ); time_gameFrame = 0; time_gameDraw = 0; } // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack if ( !Sys_FPU_StackIsEmpty() ) { Printf( Sys_FPU_GetState() ); FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" ); } mainFrameTiming = frameTiming; session->GetSaveGameManager().Pump(); } catch( idException & ) { return; // an ERP_DROP was thrown } }
void GenerateFog() { int screen_x = *bw::screen_pos_x_tiles; if (screen_x != 0) screen_x--; int screen_y = *bw::screen_pos_y_tiles; if (screen_y != 0) screen_y--; uint32_t *flags = (*bw::map_tile_flags) + screen_y * *bw::map_width_tiles + screen_x; uint32_t *orig_flags = flags; uint8_t *pos = *bw::fog_arr1; int shown_value = *bw::fog_variance_amount; int fow_value = shown_value / 2; int y_pos = screen_y; for (int i = 0; i < 0x11; i++) { int x_pos = *bw::screen_pos_x_tiles - 1; flags = orig_flags; for (int i = 0; i < 0x18; i++) { // Obviously people can just remove multiplayer check if they wish // Bw had nice vision-based sync but it does not work with dynamically allocated sprites if (all_visions && !IsMultiplayer()) { if ((0xff00 & flags[0]) == 0xff00) *pos = 0; else if ((0xff & flags[0]) == 0xff) *pos = fow_value; else *pos = shown_value; } else if (IsReplay()) { if (*bw::replay_show_whole_map) *pos = shown_value; else if (!((*bw::replay_visions << 8) & ~flags[0])) *pos = 0; else if (!(*bw::replay_visions & ~flags[0])) *pos = fow_value; else *pos = shown_value; } else { if (*bw::player_exploration_visions & flags[0]) *pos = 0; else if (*bw::player_visions & flags[0]) *pos = fow_value; else *pos = shown_value; } if (x_pos < *bw::map_width_tiles - 1 && x_pos >= 0) flags++; x_pos++; pos++; } if (y_pos < *bw::map_height_tiles - 1 && y_pos >= 0) orig_flags += *bw::map_width_tiles; y_pos++; } // Blend fog // Screen is 0x18 x 0x11 tiles // Well every border has 1 nonvisible tile, it is only used for blending? pos = *bw::fog_arr1 + 0x18 + 0x1; uint8_t *out = *bw::fog_arr2 + 0x18 + 0x1; for (int i = 0; i < 0x11 - 2; i++) { for (int i = 0; i < 0x18 - 2; i++) { int val = pos[0] * 2; val = (val + pos[-1] + pos[1] + pos[-0x18] + pos[0x18]) * 2; val = (val + pos[-0x17] + pos[0x17] + pos[-0x19] + pos[0x19]) / 16; *out = val; pos++; out++; } pos += 2; out += 2; } }
/* =============== idCommonLocal::ExecuteMapChange Performs the initialization of a game based on session match parameters, used for both single player and multiplayer, but not for renderDemos, which don't create a game at all. Exits with mapSpawned = true =============== */ void idCommonLocal::ExecuteMapChange() { if ( session->GetState() != idSession::LOADING ) { idLib::Warning( "Session state is not LOADING in ExecuteMapChange" ); return; } // Clear all dialogs before beginning the load common->Dialog().ClearDialogs( true ); // Remember the current load ID. // This is so we can tell if we had a new loadmap request from within an existing loadmap call const int cachedLoadingID = session->GetLoadingID(); const idMatchParameters & matchParameters = session->GetActingGameStateLobbyBase().GetMatchParms(); if ( matchParameters.numSlots <= 0 ) { idLib::Warning( "numSlots <= 0 in ExecuteMapChange" ); return; } insideExecuteMapChange = true; common->Printf( "--------- Execute Map Change ---------\n" ); common->Printf( "Map: %s\n", matchParameters.mapName.c_str() ); // ensure that r_znear is reset to the default value // this fixes issues with the projection matrix getting messed up when switching maps or loading a saved game // while an in-game cinematic is playing. cvarSystem->SetCVarFloat( "r_znear", 1.0f ); // reset all cheat cvars for a multiplayer game if ( IsMultiplayer() ) { cvarSystem->ResetFlaggedVariables( CVAR_CHEAT ); } int start = Sys_Milliseconds(); for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_SetRumble( i, 0, 0 ); } // close console and remove any prints from the notify lines console->Close(); // clear all menu sounds soundWorld->Pause(); menuSoundWorld->ClearAllSoundEmitters(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); soundSystem->Render(); // extract the map name from serverinfo currentMapName = matchParameters.mapName; currentMapName.StripFileExtension(); idStrStatic< MAX_OSPATH > fullMapName = "maps/"; fullMapName += currentMapName; fullMapName.SetFileExtension( "map" ); if ( mapSpawnData.savegameFile ) { fileSystem->BeginLevelLoad( currentMapName, NULL, 0 ); } else { fileSystem->BeginLevelLoad( currentMapName, saveFile.GetDataPtr(), saveFile.GetAllocated() ); } // capture the current screen and start a wipe // immediately complete the wipe to fade out the level transition // run the wipe to completion StartWipe( "wipeMaterial", true ); CompleteWipe(); int sm = Sys_Milliseconds(); // shut down the existing game if it is running UnloadMap(); int ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to unload map\n", ms ); // Free media from previous level and // note which media we are going to need to load sm = Sys_Milliseconds(); renderSystem->BeginLevelLoad(); soundSystem->BeginLevelLoad(); declManager->BeginLevelLoad(); uiManager->BeginLevelLoad(); ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to free assets\n", ms ); //Sys_DumpMemory( true ); // load / program a gui to stay up on the screen while loading // set the loading gui that we will wipe to bool hellMap = false; LoadLoadingGui( currentMapName, hellMap ); // Stop rendering the wipe ClearWipe(); if ( fileSystem->UsingResourceFiles() ) { idStrStatic< MAX_OSPATH > manifestName = currentMapName; manifestName.Replace( "game/", "maps/" ); manifestName.Replace( "/mp/", "/" ); manifestName += ".preload"; idPreloadManifest manifest; manifest.LoadManifest( manifestName ); renderSystem->Preload( manifest, currentMapName ); soundSystem->Preload( manifest ); game->Preload( manifest ); } if ( common->IsMultiplayer() ) { // In multiplayer, make sure the player is either 60Hz or 120Hz // to avoid potential issues. const float mpEngineHz = ( com_engineHz.GetFloat() < 90.0f ) ? 60.0f : 120.0f; com_engineHz_denominator = 100LL * mpEngineHz; com_engineHz_latched = mpEngineHz; } else { // allow com_engineHz to be changed between map loads com_engineHz_denominator = 100LL * com_engineHz.GetFloat(); com_engineHz_latched = com_engineHz.GetFloat(); } // note any warning prints that happen during the load process common->ClearWarnings( currentMapName ); // release the mouse cursor // before we do this potentially long operation Sys_GrabMouseCursor( false ); // let the renderSystem load all the geometry if ( !renderWorld->InitFromMap( fullMapName ) ) { common->Error( "couldn't load %s", fullMapName.c_str() ); } // for the synchronous networking we needed to roll the angles over from // level to level, but now we can just clear everything usercmdGen->InitForNewMap(); // load and spawn all other entities ( from a savegame possibly ) if ( mapSpawnData.savegameFile ) { if ( !game->InitFromSaveGame( fullMapName, renderWorld, soundWorld, mapSpawnData.savegameFile, mapSpawnData.stringTableFile, mapSpawnData.savegameVersion ) ) { // If the loadgame failed, end the session, which will force us to go back to the main menu session->QuitMatchToTitle(); } } else { if ( !IsMultiplayer() ) { assert( game->GetLocalClientNum() == 0 ); assert( matchParameters.gameMode == GAME_MODE_SINGLEPLAYER ); assert( matchParameters.gameMap == GAME_MAP_SINGLEPLAYER ); game->SetPersistentPlayerInfo( 0, mapSpawnData.persistentPlayerInfo ); } game->SetServerInfo( matchParameters.serverInfo ); game->InitFromNewMap( fullMapName, renderWorld, soundWorld, matchParameters.gameMode, Sys_Milliseconds() ); } game->Shell_CreateMenu( true ); // Reset some values important to multiplayer ResetNetworkingState(); // If the session state is not loading here, something went wrong. if ( session->GetState() == idSession::LOADING && session->GetLoadingID() == cachedLoadingID ) { // Notify session we are done loading session->LoadingFinished(); while ( session->GetState() == idSession::LOADING ) { Sys_GenerateEvents(); session->UpdateSignInManager(); session->Pump(); Sys_Sleep( 10 ); } } if ( !mapSpawnData.savegameFile ) { // run a single frame to catch any resources that are referenced by events posted in spawn idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } if ( IsClient() ) { game->ClientRunFrame( emptyCommandManager, false, emptyGameReturn ); } else { game->RunFrame( emptyCommandManager, emptyGameReturn ); } } renderSystem->EndLevelLoad(); soundSystem->EndLevelLoad(); declManager->EndLevelLoad(); uiManager->EndLevelLoad( currentMapName ); fileSystem->EndLevelLoad(); if ( !mapSpawnData.savegameFile && !IsMultiplayer() ) { common->Printf( "----- Running initial game frames -----\n" ); // In single player, run a bunch of frames to make sure ragdolls are settled idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int i = 0; i < 100; i++ ) { for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } game->RunFrame( emptyCommandManager, emptyGameReturn ); } // kick off an auto-save of the game (so we can always continue in this map if we die before hitting an autosave) common->Printf( "----- Saving Game -----\n" ); SaveGame( "autosave" ); } common->Printf( "----- Generating Interactions -----\n" ); // let the renderSystem generate interactions now that everything is spawned renderWorld->GenerateAllInteractions(); { int vertexMemUsedKB = vertexCache.staticData.vertexMemUsed.GetValue() / 1024; int indexMemUsedKB = vertexCache.staticData.indexMemUsed.GetValue() / 1024; idLib::Printf( "Used %dkb of static vertex memory (%d%%)\n", vertexMemUsedKB, vertexMemUsedKB * 100 / ( STATIC_VERTEX_MEMORY / 1024 ) ); idLib::Printf( "Used %dkb of static index memory (%d%%)\n", indexMemUsedKB, indexMemUsedKB * 100 / ( STATIC_INDEX_MEMORY / 1024 ) ); } if ( common->JapaneseCensorship() ) { if ( currentMapName.Icmp( "game/mp/d3xpdm3" ) == 0 ) { const idMaterial * gizpool2 = declManager->FindMaterial( "textures/hell/gizpool2" ); idMaterial * chiglass1bluex = const_cast<idMaterial *>( declManager->FindMaterial( "textures/sfx/chiglass1bluex" ) ); idTempArray<char> text( gizpool2->GetTextLength() ); gizpool2->GetText( text.Ptr() ); chiglass1bluex->Parse( text.Ptr(), text.Num(), false ); } } common->PrintWarnings(); session->Pump(); if ( session->GetState() != idSession::INGAME ) { // Something went wrong, don't process stale reliables that have been queued up. reliableQueue.Clear(); } usercmdGen->Clear(); // remove any prints from the notify lines console->ClearNotifyLines(); Sys_SetPhysicalWorkMemory( -1, -1 ); // at this point we should be done with the loading gui so we kill it delete loadGUI; loadGUI = NULL; // capture the current screen and start a wipe StartWipe( "wipe2Material" ); // we are valid for game draws now insideExecuteMapChange = false; mapSpawned = true; Sys_ClearEvents(); int msec = Sys_Milliseconds() - start; common->Printf( "%6d msec to load %s\n", msec, currentMapName.c_str() ); //Sys_DumpMemory( false ); // Issue a render at the very end of the load process to update soundTime before the first frame soundSystem->Render(); }
/* =============== 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; }
static void Command_GameSpeed(uint8_t *data) { int speed = data[1]; if (!IsMultiplayer() && speed <= 6) *bw::game_speed = speed; }
/* =============== idCommonLocal::IsServer =============== */ bool idCommonLocal::IsServer() { return IsMultiplayer() && session->GetActingGameStateLobbyBase().IsHost(); }
/* =============== idCommonLocal::IsClient =============== */ bool idCommonLocal::IsClient() { return IsMultiplayer() && session->GetActingGameStateLobbyBase().IsPeer(); }
/* =============== 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; }