From 65d12cbaace65dcba09b91c605e0bdae8ea1da07 Mon Sep 17 00:00:00 2001 From: Stradex Date: Thu, 11 Jun 2020 04:19:27 -0300 Subject: [PATCH 1/9] added com_gameHz to play with higher FPS --- neo/d3xp/Camera.cpp | 4 +- neo/d3xp/Game_local.cpp | 72 ++++++++++++++++++++----- neo/d3xp/Game_local.h | 3 ++ neo/d3xp/Moveable.cpp | 4 +- neo/d3xp/Mover.cpp | 4 +- neo/d3xp/PlayerView.cpp | 2 +- neo/d3xp/Projectile.cpp | 2 +- neo/d3xp/SmokeParticles.cpp | 2 +- neo/d3xp/physics/Force_Drag.cpp | 5 +- neo/d3xp/physics/Physics.cpp | 4 +- neo/d3xp/physics/Physics_AF.cpp | 2 +- neo/d3xp/physics/Physics_RigidBody.cpp | 2 +- neo/d3xp/script/Script_Thread.cpp | 2 +- neo/framework/Common.cpp | 50 ++++++++++++++--- neo/framework/Common.h | 4 ++ neo/framework/Session.cpp | 12 ++--- neo/framework/UsercmdGen.cpp | 8 +-- neo/framework/UsercmdGen.h | 3 -- neo/framework/async/AsyncClient.cpp | 35 ++++++++---- neo/framework/async/AsyncServer.cpp | 11 ++-- neo/game/Camera.cpp | 4 +- neo/game/Game_local.cpp | 44 +++++++++++++++ neo/game/Game_local.h | 4 +- neo/game/Moveable.cpp | 4 +- neo/game/Mover.cpp | 2 +- neo/game/Player.cpp | 1 + neo/game/Projectile.cpp | 2 +- neo/game/SmokeParticles.cpp | 2 +- neo/game/physics/Force_Drag.cpp | 5 +- neo/game/physics/Physics.cpp | 4 +- neo/game/physics/Physics_AF.cpp | 2 +- neo/game/physics/Physics_RigidBody.cpp | 2 +- neo/game/script/Script_Thread.cpp | 2 +- neo/renderer/RenderSystem_init.cpp | 2 +- neo/renderer/RenderWorld.cpp | 6 +++ neo/renderer/tr_light.cpp | 31 ++++++++++- neo/renderer/tr_local.h | 3 ++ neo/sound/snd_emitter.cpp | 2 +- neo/sound/snd_local.h | 1 - neo/sys/osx/Doom 3.rsrc | Bin 0 -> 10514 bytes neo/ui/Window.cpp | 2 +- 41 files changed, 270 insertions(+), 86 deletions(-) create mode 100644 neo/sys/osx/Doom 3.rsrc diff --git a/neo/d3xp/Camera.cpp b/neo/d3xp/Camera.cpp index dedba94fc..d15776adf 100644 --- a/neo/d3xp/Camera.cpp +++ b/neo/d3xp/Camera.cpp @@ -514,7 +514,7 @@ void idCameraAnim::Think( void ) { return; } - if ( frameRate == USERCMD_HZ ) { + if ( frameRate == gameLocal.gameFps ) { frameTime = gameLocal.time - starttime; frame = frameTime / gameLocal.msec; } else { @@ -568,7 +568,7 @@ void idCameraAnim::GetViewParms( renderView_t *view ) { SetTimeState ts( timeGroup ); #endif - if ( frameRate == USERCMD_HZ ) { + if ( frameRate == gameLocal.gameFps ) { frameTime = gameLocal.time - starttime; frame = frameTime / gameLocal.msec; lerp = 0.0f; diff --git a/neo/d3xp/Game_local.cpp b/neo/d3xp/Game_local.cpp index dc0903727..73148279e 100644 --- a/neo/d3xp/Game_local.cpp +++ b/neo/d3xp/Game_local.cpp @@ -309,6 +309,10 @@ void idGameLocal::Init( void ) { const idDict *dict; idAAS *aas; + msec = 16; //60fps + gameMsec = msec; + gameFps = 60; //60fps + #ifndef GAME_DLL TestGameAPI(); @@ -326,6 +330,11 @@ void idGameLocal::Init( void ) { #endif + //Update MSEC and gameFps + gameFps = cvarSystem->GetCVarInteger("com_gameHz"); + msec = idMath::FtoiFast(1000.0f / static_cast(cvarSystem->GetCVarInteger("com_gameHz"))); + gameMsec = msec; + Printf( "----- Initializing Game -----\n" ); Printf( "gamename: %s\n", GAME_VERSION ); Printf( "gamedate: %s\n", __DATE__ ); @@ -1292,6 +1301,8 @@ void idGameLocal::MapPopulate( void ) { // before the physics are run so entities can bind correctly Printf( "==== Processing events ====\n" ); idEvent::ServiceEvents(); + + SetScriptFPS(static_cast(this->gameFps)); } /* @@ -1354,6 +1365,8 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo gameRenderWorld = renderWorld; gameSoundWorld = soundWorld; + SetScriptFPS(static_cast(this->gameFps)); + idRestoreGame savegame( saveGameFile ); savegame.ReadBuildNumber(); @@ -1520,7 +1533,7 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo } } if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); } #endif @@ -4821,7 +4834,7 @@ void idGameLocal::ComputeSlowMsec() { // stop the state slowmoState = SLOWMO_STATE_OFF; - slowmoMsec = USERCMD_MSEC; + slowmoMsec = (float)gameMsec; } // check the player state @@ -4842,7 +4855,7 @@ void idGameLocal::ComputeSlowMsec() { slowmoMsec = msec; if ( gameSoundWorld ) { gameSoundWorld->SetSlowmo( true ); - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); } } else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) { @@ -4856,10 +4869,10 @@ void idGameLocal::ComputeSlowMsec() { // do any necessary ramping if ( slowmoState == SLOWMO_STATE_RAMPUP ) { - delta = 4 - slowmoMsec; + delta = idMath::Rint(4.0 * 60.0 / (float)gameFps) - slowmoMsec; if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = 4; + slowmoMsec = idMath::Rint(4.0 * 60.0 / (float)gameFps); slowmoState = SLOWMO_STATE_ON; } else { @@ -4867,14 +4880,14 @@ void idGameLocal::ComputeSlowMsec() { } if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); } } else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) { - delta = 16 - slowmoMsec; + delta = idMath::Rint(16.0 * 60.0 / (float)gameFps) - slowmoMsec; if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = 16; + slowmoMsec = idMath::Rint(16.0*60.0/(float)gameFps); slowmoState = SLOWMO_STATE_OFF; if ( gameSoundWorld ) { gameSoundWorld->SetSlowmo( false ); @@ -4885,7 +4898,7 @@ void idGameLocal::ComputeSlowMsec() { } if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); } } } @@ -4896,19 +4909,19 @@ idGameLocal::ResetSlowTimeVars ============ */ void idGameLocal::ResetSlowTimeVars() { - msec = USERCMD_MSEC; - slowmoMsec = USERCMD_MSEC; + msec = gameMsec; + slowmoMsec = gameMsec; slowmoState = SLOWMO_STATE_OFF; fast.framenum = 0; fast.previousTime = 0; fast.time = 0; - fast.msec = USERCMD_MSEC; + fast.msec = gameMsec; slow.framenum = 0; slow.previousTime = 0; slow.time = 0; - slow.msec = USERCMD_MSEC; + slow.msec = gameMsec; } /* @@ -4986,3 +4999,36 @@ idGameLocal::GetMapLoadingGUI =============== */ void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } + +/* +=================== +idGameLocal::SetScriptFPS +=================== +*/ +void idGameLocal::SetScriptFPS(const float tCom_gameHz) +{ + idVarDef* fpsDef = program.GetDef(&type_float, "GAME_FPS", &def_namespace); + if (fpsDef != NULL) { + eval_t fpsValue; + fpsValue._float = tCom_gameHz; + fpsDef->SetValue(fpsValue, false); + + common->Printf("GAME_FPS: %f\n", tCom_gameHz); + } + else { + common->Printf("Unable to find GAME_FPS def\n"); + } + + float frameRate = 1.0 / tCom_gameHz; + idVarDef* frameRateDef = program.GetDef(&type_float, "GAME_FRAMETIME", &def_namespace); + if (frameRateDef != NULL) { + eval_t frameRateValue; + frameRateValue._float = frameRate; + frameRateDef->SetValue(frameRateValue, false); + + common->Printf("GAME_FRAMETIME to: %f\n", frameRate); + } + else { + common->Printf("Unable to find GAME_FRAMETIME def\n"); + } +} diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index cb229cd99..2ff620930 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -299,6 +299,8 @@ class idGameLocal : public idGame { int previousTime; // time in msec of last frame int time; // in msec int msec; // time since last update in milliseconds + int gameFps; //added by Stradex for com_gameHz + int gameMsec; //added by Stradex for com_gameHz (ROE) int vacuumAreaNum; // -1 if level doesn't have any outside areas @@ -586,6 +588,7 @@ class idGameLocal : public idGame { void RunDebugInfo( void ); void InitScriptForMap( void ); + void SetScriptFPS(const float tCom_gameHz); void InitConsoleCommands( void ); void ShutdownConsoleCommands( void ); diff --git a/neo/d3xp/Moveable.cpp b/neo/d3xp/Moveable.cpp index 0ba26a851..0efc11edf 100644 --- a/neo/d3xp/Moveable.cpp +++ b/neo/d3xp/Moveable.cpp @@ -460,14 +460,14 @@ bool idMoveable::FollowInitialSplinePath( void ) { if ( initialSpline != NULL ) { if ( gameLocal.time < initialSpline->GetTime( initialSpline->GetNumValues() - 1 ) ) { idVec3 splinePos = initialSpline->GetCurrentValue( gameLocal.time ); - idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * USERCMD_HZ; + idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * gameLocal.gameFps; physicsObj.SetLinearVelocity( linearVelocity ); idVec3 splineDir = initialSpline->GetCurrentFirstDerivative( gameLocal.time ); idVec3 dir = initialSplineDir * physicsObj.GetAxis(); idVec3 angularVelocity = dir.Cross( splineDir ); angularVelocity.Normalize(); - angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * USERCMD_HZ; + angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * gameLocal.gameFps; physicsObj.SetAngularVelocity( angularVelocity ); return true; } else { diff --git a/neo/d3xp/Mover.cpp b/neo/d3xp/Mover.cpp index 4e4160fb1..4c327f8bf 100644 --- a/neo/d3xp/Mover.cpp +++ b/neo/d3xp/Mover.cpp @@ -2838,9 +2838,9 @@ void idMover_Binary::Use_BinaryMover( idEntity *activator ) { activatedBy = activator; if ( moverState == MOVER_POS1 ) { - // FIXME: start moving USERCMD_MSEC later, because if this was player + // FIXME: start moving gameLocal.msec later, because if this was player // triggered, gameLocal.time hasn't been advanced yet - MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time + USERCMD_MSEC ); + MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time + gameLocal.gameMsec ); SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); // open areaportal diff --git a/neo/d3xp/PlayerView.cpp b/neo/d3xp/PlayerView.cpp index 750e20d07..01d47c3e1 100644 --- a/neo/d3xp/PlayerView.cpp +++ b/neo/d3xp/PlayerView.cpp @@ -308,7 +308,7 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) if ( blobTime ) { screenBlob_t* blob = GetScreenBlob(); blob->startFadeTime = gameLocal.slow.time; - blob->finishTime = gameLocal.slow.time + blobTime * g_blobTime.GetFloat() * ( ( float )gameLocal.msec / USERCMD_MSEC ); + blob->finishTime = gameLocal.slow.time + blobTime * g_blobTime.GetFloat() * ( ( float )gameLocal.msec / gameLocal.gameMsec ); const char* materialName = damageDef->GetString( "mtr_blob" ); blob->material = declManager->FindMaterial( materialName ); diff --git a/neo/d3xp/Projectile.cpp b/neo/d3xp/Projectile.cpp index 51023b6de..59c6fe949 100644 --- a/neo/d3xp/Projectile.cpp +++ b/neo/d3xp/Projectile.cpp @@ -1610,7 +1610,7 @@ void idGuidedProjectile::Launch( const idVec3 &start, const idVec3 &dir, const i angles = vel.ToAngles(); speed = vel.Length(); rndScale = spawnArgs.GetAngles( "random", "15 15 0" ); - turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )USERCMD_HZ; + turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )gameLocal.gameFps; clamp_dist = spawnArgs.GetFloat( "clamp_dist", "256" ); burstMode = spawnArgs.GetBool( "burstMode" ); unGuided = false; diff --git a/neo/d3xp/SmokeParticles.cpp b/neo/d3xp/SmokeParticles.cpp index 710baecf2..a39b3a347 100644 --- a/neo/d3xp/SmokeParticles.cpp +++ b/neo/d3xp/SmokeParticles.cpp @@ -236,7 +236,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } - prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was USERCMD_MSEC*/ ) / finalParticleTime) * stage->totalParticles ); + prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was gameLocal.msec*/ ) / finalParticleTime) * stage->totalParticles ); if ( prevCount < -1 ) { prevCount = -1; } diff --git a/neo/d3xp/physics/Force_Drag.cpp b/neo/d3xp/physics/Force_Drag.cpp index f8682a11e..4b36356e5 100644 --- a/neo/d3xp/physics/Force_Drag.cpp +++ b/neo/d3xp/physics/Force_Drag.cpp @@ -29,6 +29,7 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "framework/UsercmdGen.h" +#include "Game_local.h" #include "physics/Physics.h" #include "physics/Force_Drag.h" @@ -139,9 +140,9 @@ void idForce_Drag::Evaluate( int time ) { l2 = dir2.Normalize(); rotation.Set( centerOfMass, dir2.Cross( dir1 ), RAD2DEG( idMath::ACos( dir1 * dir2 ) ) ); - physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC( USERCMD_MSEC ), id ); + physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC( gameLocal.gameMsec ), id ); - velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( USERCMD_MSEC ) ); + velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( gameLocal.gameMsec ) ); physics->SetLinearVelocity( velocity, id ); } diff --git a/neo/d3xp/physics/Physics.cpp b/neo/d3xp/physics/Physics.cpp index 86e35d464..262770405 100644 --- a/neo/d3xp/physics/Physics.cpp +++ b/neo/d3xp/physics/Physics.cpp @@ -75,6 +75,6 @@ idPhysics::SnapTimeToPhysicsFrame */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { int s; - s = t + USERCMD_MSEC - 1; - return ( s - s % USERCMD_MSEC ); + s = t + gameLocal.gameMsec - 1; + return ( s - s % gameLocal.gameMsec ); } diff --git a/neo/d3xp/physics/Physics_AF.cpp b/neo/d3xp/physics/Physics_AF.cpp index 098a4bfc7..c2fef5575 100644 --- a/neo/d3xp/physics/Physics_AF.cpp +++ b/neo/d3xp/physics/Physics_AF.cpp @@ -6608,7 +6608,7 @@ idPhysics_AF::idPhysics_AF( void ) { memset( ¤t, 0, sizeof( current ) ); current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; + current.lastTimeStep = gameLocal.gameMsec; saved = current; linearFriction = 0.005f; diff --git a/neo/d3xp/physics/Physics_RigidBody.cpp b/neo/d3xp/physics/Physics_RigidBody.cpp index 838065699..503ba456c 100644 --- a/neo/d3xp/physics/Physics_RigidBody.cpp +++ b/neo/d3xp/physics/Physics_RigidBody.cpp @@ -447,7 +447,7 @@ idPhysics_RigidBody::idPhysics_RigidBody( void ) { memset( ¤t, 0, sizeof( current ) ); current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; + current.lastTimeStep = gameLocal.gameMsec; current.i.position.Zero(); current.i.orientation.Identity(); diff --git a/neo/d3xp/script/Script_Thread.cpp b/neo/d3xp/script/Script_Thread.cpp index cb8263310..520a7322f 100644 --- a/neo/d3xp/script/Script_Thread.cpp +++ b/neo/d3xp/script/Script_Thread.cpp @@ -1849,7 +1849,7 @@ idThread::Event_GetTicsPerSecond ================ */ void idThread::Event_GetTicsPerSecond( void ) { - idThread::ReturnFloat( USERCMD_HZ ); + idThread::ReturnFloat( gameLocal.gameFps ); } /* diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index 37648c907..0a9e0ae81 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -104,6 +104,15 @@ idCVar com_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | idCVar com_product_lang_ext( "com_product_lang_ext", "1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_ARCHIVE, "Extension to use when creating language files." ); + +//Stradex: start +idCVar com_gameHz("com_gameHz", "60", CVAR_INTEGER | CVAR_ARCHIVE | CVAR_SYSTEM, "Frames per second the game runs at", 10, 1024); + +int com_gameMSRate = 1000 / 60; //Refreshed later +int com_realGameHz = 60; +bool tReloadingEngine = false; +//Stradex: end + // com_speeds times int time_gameFrame; int time_gameDraw; @@ -1516,14 +1525,24 @@ void Com_ReloadEngine_f( const idCmdArgs &args ) { } common->Printf( "============= ReloadEngine start =============\n" ); + + tReloadingEngine = true; + if ( !menu ) { Sys_ShowConsole( 1, false ); } + + + com_realGameHz = com_gameHz.GetInteger(); + commonLocal.ShutdownGame( true ); commonLocal.InitGame(); if ( !menu && !idAsyncNetwork::serverDedicated.GetBool() ) { Sys_ShowConsole( 0, false ); } + + tReloadingEngine = false; + common->Printf( "============= ReloadEngine end ===============\n" ); if ( !cmdSystem->PostReloadEngine() ) { @@ -2404,7 +2423,7 @@ void idCommonLocal::Frame( void ) { eventLoop->RunEventLoop(); - com_frameTime = com_ticNumber * USERCMD_MSEC; + com_frameTime = com_ticNumber * com_gameMSRate; idAsyncNetwork::RunFrame(); @@ -2450,7 +2469,7 @@ idCommonLocal::GUIFrame void idCommonLocal::GUIFrame( bool execCmd, bool network ) { Sys_GenerateEvents(); eventLoop->RunEventLoop( execCmd ); // and execute any commands - com_frameTime = com_ticNumber * USERCMD_MSEC; + com_frameTime = com_ticNumber * com_gameMSRate; if ( network ) { idAsyncNetwork::RunFrame(); } @@ -2530,7 +2549,7 @@ idCommonLocal::Async void idCommonLocal::Async( void ) { int msec = Sys_Milliseconds(); if ( !lastTicMsec ) { - lastTicMsec = msec - USERCMD_MSEC; + lastTicMsec = msec - com_gameMSRate; } if ( !com_preciseTic.GetBool() ) { @@ -2539,7 +2558,7 @@ void idCommonLocal::Async( void ) { return; } - int ticMsec = USERCMD_MSEC; + int ticMsec = com_gameMSRate; // the number of msec per tic can be varies with the timescale cvar float timescale = com_timescale.GetFloat(); @@ -2552,8 +2571,8 @@ void idCommonLocal::Async( void ) { // don't skip too many if ( timescale == 1.0f ) { - if ( lastTicMsec + 10 * USERCMD_MSEC < msec ) { - lastTicMsec = msec - 10*USERCMD_MSEC; + if ( lastTicMsec + 10 * com_gameMSRate < msec ) { + lastTicMsec = msec - 10* com_gameMSRate; } } @@ -2753,7 +2772,7 @@ static unsigned int AsyncTimer(unsigned int interval, void *) { // calculate the next interval to get as close to 60fps as possible unsigned int now = SDL_GetTicks(); - unsigned int tick = com_ticNumber * USERCMD_MSEC; + unsigned int tick = com_ticNumber * com_gameMSRate; if (now >= tick) return 1; @@ -2940,6 +2959,11 @@ void idCommonLocal::Init( int argc, char **argv ) { // game specific initialization InitGame(); + //stradex: start + com_realGameHz = com_gameHz.GetInteger(); + com_gameMSRate = idMath::FtoiFast(1000.0f / static_cast(com_gameHz.GetInteger())); + //stradex: end + // don't add startup commands if no CD key is present #if ID_ENFORCE_KEY if ( !session->CDKeysAreValid( false ) || !AddStartupCommands() ) { @@ -2972,7 +2996,7 @@ void idCommonLocal::Init( int argc, char **argv ) { Sys_Error( "Error during initialization" ); } - async_timer = SDL_AddTimer(USERCMD_MSEC, AsyncTimer, NULL); + async_timer = SDL_AddTimer(com_gameMSRate, AsyncTimer, NULL); if (!async_timer) Sys_Error("Error while starting the async timer: %s", SDL_GetError()); @@ -3106,6 +3130,16 @@ void idCommonLocal::InitGame( void ) { // if any archived cvars are modified after this, we will trigger a writing of the config file cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE ); +#ifndef ID_DEDICATED + if (tReloadingEngine) { + com_gameHz.SetInteger(com_realGameHz); + com_gameMSRate = idMath::FtoiFast(1000.0f / static_cast(com_gameHz.GetInteger())); + //reset time and tics + com_frameNumber = 0; + com_ticNumber = 0; + } +#endif + // init the user command input code usercmdGen->Init(); diff --git a/neo/framework/Common.h b/neo/framework/Common.h index c0400bb47..90270078e 100644 --- a/neo/framework/Common.h +++ b/neo/framework/Common.h @@ -74,6 +74,10 @@ extern idCVar com_showSoundDecoders; extern idCVar com_makingBuild; extern idCVar com_updateLoadSize; +extern idCVar com_gameHz; +extern int com_gameMSRate; +extern int com_realGameHz; + extern int time_gameFrame; // game logic time extern int time_gameDraw; // game present time extern int time_frontend; // renderer frontend time diff --git a/neo/framework/Session.cpp b/neo/framework/Session.cpp index 73585a2eb..24ed00204 100644 --- a/neo/framework/Session.cpp +++ b/neo/framework/Session.cpp @@ -497,7 +497,7 @@ void idSessionLocal::StartWipe( const char *_wipeMaterial, bool hold ) { wipeMaterial = declManager->FindMaterial( _wipeMaterial, false ); wipeStartTic = com_ticNumber; - wipeStopTic = wipeStartTic + 1000.0f / USERCMD_MSEC * com_wipeSeconds.GetFloat(); + wipeStopTic = wipeStartTic + 1000.0f / com_gameMSRate * com_wipeSeconds.GetFloat(); wipeHold = hold; } @@ -538,14 +538,14 @@ void idSessionLocal::ShowLoadingGui() { int stop = Sys_Milliseconds() + 1000; int force = 10; while ( Sys_Milliseconds() < stop || force-- > 0 ) { - com_frameTime = com_ticNumber * USERCMD_MSEC; + com_frameTime = com_ticNumber * com_gameMSRate; session->Frame(); session->UpdateScreen( false ); } #else - int stop = com_ticNumber + 1000.0f / USERCMD_MSEC * 1.0f; + int stop = com_ticNumber + 1000.0f / com_gameMSRate * 1.0f; while ( com_ticNumber < stop ) { - com_frameTime = com_ticNumber * USERCMD_MSEC; + com_frameTime = com_ticNumber * com_gameMSRate; session->Frame(); session->UpdateScreen( false ); } @@ -2545,7 +2545,7 @@ void idSessionLocal::Frame() { name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviTicStart ); - float ratio = 30.0f / ( 1000.0f / USERCMD_MSEC / com_aviDemoTics.GetInteger() ); + float ratio = 30.0f / ( 1000.0f / com_gameMSRate / com_aviDemoTics.GetInteger() ); aviDemoFrameCount += ratio; if ( aviTicStart + 1 != ( int )aviDemoFrameCount ) { // skipped frames so write them out @@ -2669,7 +2669,7 @@ void idSessionLocal::Frame() { // don't let a long onDemand sound load unsync everything if ( timeHitch ) { - int skip = timeHitch / USERCMD_MSEC; + int skip = timeHitch / com_gameMSRate; lastGameTic += skip; numCmdsToRun -= skip; timeHitch = 0; diff --git a/neo/framework/UsercmdGen.cpp b/neo/framework/UsercmdGen.cpp index f1b213f7b..57bc68cd6 100644 --- a/neo/framework/UsercmdGen.cpp +++ b/neo/framework/UsercmdGen.cpp @@ -532,9 +532,9 @@ void idUsercmdGenLocal::AdjustAngles( void ) { float speed; if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) { - speed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat(); + speed = idMath::M_MS2SEC * com_gameMSRate * in_angleSpeedKey.GetFloat(); } else { - speed = idMath::M_MS2SEC * USERCMD_MSEC; + speed = idMath::M_MS2SEC * com_gameMSRate; } if ( !ButtonState( UB_STRAFE ) ) { @@ -681,9 +681,9 @@ void idUsercmdGenLocal::JoystickMove( void ) { float anglespeed; if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) { - anglespeed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat(); + anglespeed = idMath::M_MS2SEC * com_gameMSRate * in_angleSpeedKey.GetFloat(); } else { - anglespeed = idMath::M_MS2SEC * USERCMD_MSEC; + anglespeed = idMath::M_MS2SEC * com_gameMSRate; } if ( !ButtonState( UB_STRAFE ) ) { diff --git a/neo/framework/UsercmdGen.h b/neo/framework/UsercmdGen.h index 17e88fe8f..656fb7df5 100644 --- a/neo/framework/UsercmdGen.h +++ b/neo/framework/UsercmdGen.h @@ -37,9 +37,6 @@ If you have questions concerning this license or the applicable additional terms =============================================================================== */ -const int USERCMD_HZ = 60; // 60 frames per second -const int USERCMD_MSEC = 1000 / USERCMD_HZ; - // usercmd_t->button bits const int BUTTON_ATTACK = BIT(0); const int BUTTON_RUN = BIT(1); diff --git a/neo/framework/async/AsyncClient.cpp b/neo/framework/async/AsyncClient.cpp index 306c458f5..2eff5db5a 100644 --- a/neo/framework/async/AsyncClient.cpp +++ b/neo/framework/async/AsyncClient.cpp @@ -1055,6 +1055,7 @@ idAsyncClient::ProcessChallengeResponseMessage */ void idAsyncClient::ProcessChallengeResponseMessage( const netadr_t from, const idBitMsg &msg ) { char serverGame[ MAX_STRING_CHARS ], serverGameBase[ MAX_STRING_CHARS ]; + short int serverGameHz; if ( clientState != CS_CHALLENGING ) { common->Printf( "Unwanted challenge response received.\n" ); @@ -1063,6 +1064,7 @@ void idAsyncClient::ProcessChallengeResponseMessage( const netadr_t from, const serverChallenge = msg.ReadInt(); serverId = msg.ReadShort(); + serverGameHz = msg.ReadShort(); msg.ReadString( serverGameBase, MAX_STRING_CHARS ); msg.ReadString( serverGame, MAX_STRING_CHARS ); @@ -1080,12 +1082,23 @@ void idAsyncClient::ProcessChallengeResponseMessage( const netadr_t from, const } common->Printf( "The server is running a different mod (%s-%s). Restarting..\n", serverGameBase, serverGame ); cvarSystem->SetCVarString( "fs_game_base", serverGameBase ); + cvarSystem->SetCVarInteger("com_gameHz", serverGameHz); //Lets update com_Gamehz just to gain some time cvarSystem->SetCVarString( "fs_game", serverGame ); cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reloadEngine" ); cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "reconnect\n" ); return; } + //added by Stradex to update client fps before joining the game + + if (serverGameHz != com_realGameHz) { //we need to reload fps + common->Printf("Server is running with different com_gameHz (%d). Restarting..\n", serverGameHz); + cvarSystem->SetCVarInteger("com_gameHz", serverGameHz); + cmdSystem->BufferCommandText(CMD_EXEC_NOW, "reloadEngine"); + cmdSystem->BufferCommandText(CMD_EXEC_APPEND, "reconnect\n"); + return; + } + common->Printf( "received challenge response 0x%x from %s\n", serverChallenge, Sys_NetAdrToString( from ) ); // start sending connect packets instead of challenge request packets @@ -1776,7 +1789,7 @@ void idAsyncClient::RunFrame( void ) { do { // blocking read with game time residual timeout - newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), USERCMD_MSEC - ( gameTimeResidual + clientPredictTime ) - 1 ); + newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), com_gameMSRate - ( gameTimeResidual + clientPredictTime ) - 1 ); if ( newPacket ) { msg.Init( msgBuf, sizeof( msgBuf ) ); msg.SetSize( size ); @@ -1789,14 +1802,14 @@ void idAsyncClient::RunFrame( void ) { } while( newPacket ); - } while( gameTimeResidual + clientPredictTime < USERCMD_MSEC ); + } while( gameTimeResidual + clientPredictTime < com_gameMSRate ); // update server list serverList.RunFrame(); if ( clientState == CS_DISCONNECTED ) { usercmdGen->GetDirectUsercmd(); - gameTimeResidual = USERCMD_MSEC - 1; + gameTimeResidual = com_gameMSRate - 1; clientPredictTime = 0; return; } @@ -1804,7 +1817,7 @@ void idAsyncClient::RunFrame( void ) { if ( clientState == CS_PURERESTART ) { clientState = CS_DISCONNECTED; Reconnect(); - gameTimeResidual = USERCMD_MSEC - 1; + gameTimeResidual = com_gameMSRate - 1; clientPredictTime = 0; return; } @@ -1814,7 +1827,7 @@ void idAsyncClient::RunFrame( void ) { // also need to read mouse for the connecting guis usercmdGen->GetDirectUsercmd(); SetupConnection(); - gameTimeResidual = USERCMD_MSEC - 1; + gameTimeResidual = com_gameMSRate - 1; clientPredictTime = 0; return; } @@ -1838,20 +1851,20 @@ void idAsyncClient::RunFrame( void ) { cvarSystem->ClearModifiedFlags( CVAR_USERINFO ); } - if ( gameTimeResidual + clientPredictTime >= USERCMD_MSEC ) { + if ( gameTimeResidual + clientPredictTime >= com_gameMSRate ) { lastFrameDelta = 0; } // generate user commands for the predicted time - while ( gameTimeResidual + clientPredictTime >= USERCMD_MSEC ) { + while ( gameTimeResidual + clientPredictTime >= com_gameMSRate ) { // send the user commands of this client to the server SendUsercmdsToServer(); // update time gameFrame++; - gameTime += USERCMD_MSEC; - gameTimeResidual -= USERCMD_MSEC; + gameTime += com_gameMSRate; + gameTimeResidual -= com_gameMSRate; // run from the snapshot up to the local game frame while ( snapshotGameFrame < gameFrame ) { @@ -1862,7 +1875,7 @@ void idAsyncClient::RunFrame( void ) { DuplicateUsercmds( snapshotGameFrame, snapshotGameTime ); // indicate the last prediction frame before a render - bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < USERCMD_MSEC ); + bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < com_gameMSRate ); // run client prediction gameReturn_t ret = game->ClientPrediction( clientNum, userCmds[ snapshotGameFrame & ( MAX_USERCMD_BACKUP - 1 ) ], lastPredictFrame ); @@ -1870,7 +1883,7 @@ void idAsyncClient::RunFrame( void ) { idAsyncNetwork::ExecuteSessionCommand( ret.sessionCommand ); snapshotGameFrame++; - snapshotGameTime += USERCMD_MSEC; + snapshotGameTime += com_gameMSRate; } } } diff --git a/neo/framework/async/AsyncServer.cpp b/neo/framework/async/AsyncServer.cpp index 9f6981fcc..f7cdda177 100644 --- a/neo/framework/async/AsyncServer.cpp +++ b/neo/framework/async/AsyncServer.cpp @@ -1515,6 +1515,7 @@ void idAsyncServer::ProcessChallengeMessage( const netadr_t from, const idBitMsg outMsg.WriteString( "challengeResponse" ); outMsg.WriteInt( challenges[i].challenge ); outMsg.WriteShort( serverId ); + outMsg.WriteShort(static_cast(cvarSystem->GetCVarInteger("com_gameHz"))); //added by Stradex to force client sync gamehz outMsg.WriteString( cvarSystem->GetCVarString( "fs_game_base" ) ); outMsg.WriteString( cvarSystem->GetCVarString( "fs_game" ) ); @@ -2377,7 +2378,7 @@ void idAsyncServer::RunFrame( void ) { do { // blocking read with game time residual timeout - newPacket = serverPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), USERCMD_MSEC - gameTimeResidual - 1 ); + newPacket = serverPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), com_gameMSRate - gameTimeResidual - 1 ); if ( newPacket ) { msg.Init( msgBuf, sizeof( msgBuf ) ); msg.SetSize( size ); @@ -2392,7 +2393,7 @@ void idAsyncServer::RunFrame( void ) { } while( newPacket ); - } while( gameTimeResidual < USERCMD_MSEC ); + } while( gameTimeResidual < com_gameMSRate ); // send heart beat to master servers MasterHeartbeat(); @@ -2433,7 +2434,7 @@ void idAsyncServer::RunFrame( void ) { } // advance the server game - while( gameTimeResidual >= USERCMD_MSEC ) { + while( gameTimeResidual >= com_gameMSRate ) { // sample input for the local client LocalClientInput(); @@ -2448,8 +2449,8 @@ void idAsyncServer::RunFrame( void ) { // update time gameFrame++; - gameTime += USERCMD_MSEC; - gameTimeResidual -= USERCMD_MSEC; + gameTime += com_gameMSRate; + gameTimeResidual -= com_gameMSRate; } // duplicate usercmds so there is always at least one available to send with snapshots diff --git a/neo/game/Camera.cpp b/neo/game/Camera.cpp index eddef3733..117f19a37 100644 --- a/neo/game/Camera.cpp +++ b/neo/game/Camera.cpp @@ -514,7 +514,7 @@ void idCameraAnim::Think( void ) { return; } - if ( frameRate == USERCMD_HZ ) { + if ( frameRate == gameLocal.gameFps ) { frameTime = gameLocal.time - starttime; frame = frameTime / gameLocal.msec; } else { @@ -564,7 +564,7 @@ void idCameraAnim::GetViewParms( renderView_t *view ) { return; } - if ( frameRate == USERCMD_HZ ) { + if ( frameRate == gameLocal.gameFps ) { frameTime = gameLocal.time - starttime; frame = frameTime / gameLocal.msec; lerp = 0.0f; diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index 41f11767a..a5d75f82d 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -279,6 +279,9 @@ void idGameLocal::Init( void ) { const idDict *dict; idAAS *aas; + msec = 16; //60fps + gameFps = 60; //60fps + #ifndef GAME_DLL TestGameAPI(); @@ -296,6 +299,10 @@ void idGameLocal::Init( void ) { #endif + //Update MSEC and gameFps + gameFps = cvarSystem->GetCVarInteger("com_gameHz"); + msec = idMath::FtoiFast(1000.0f / static_cast(cvarSystem->GetCVarInteger("com_gameHz"))); + Printf( "----- Initializing Game -----\n" ); Printf( "gamename: %s\n", GAME_VERSION ); Printf( "gamedate: %s\n", __DATE__ ); @@ -1172,6 +1179,8 @@ void idGameLocal::MapPopulate( void ) { // before the physics are run so entities can bind correctly Printf( "==== Processing events ====\n" ); idEvent::ServiceEvents(); + + SetScriptFPS(static_cast(this->gameFps)); } /* @@ -1234,6 +1243,8 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo gameRenderWorld = renderWorld; gameSoundWorld = soundWorld; + SetScriptFPS(static_cast(this->gameFps)); + idRestoreGame savegame( saveGameFile ); savegame.ReadBuildNumber(); @@ -4386,3 +4397,36 @@ idGameLocal::GetMapLoadingGUI =============== */ void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } + +/* +=================== +idGameLocal::SetScriptFPS +=================== +*/ +void idGameLocal::SetScriptFPS(const float tCom_gameHz) +{ + idVarDef* fpsDef = program.GetDef(&type_float, "GAME_FPS", &def_namespace); + if (fpsDef != NULL) { + eval_t fpsValue; + fpsValue._float = tCom_gameHz; + fpsDef->SetValue(fpsValue, false); + + common->Printf("GAME_FPS: %f\n", tCom_gameHz); + } + else { + common->Printf("Unable to find GAME_FPS def\n"); + } + + float frameRate = 1.0 / tCom_gameHz; + idVarDef* frameRateDef = program.GetDef(&type_float, "GAME_FRAMETIME", &def_namespace); + if (frameRateDef != NULL) { + eval_t frameRateValue; + frameRateValue._float = frameRate; + frameRateDef->SetValue(frameRateValue, false); + + common->Printf("GAME_FRAMETIME to: %f\n", frameRate); + } + else { + common->Printf("Unable to find GAME_FRAMETIME def\n"); + } +} diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index 1f724434b..d32c91e60 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -272,7 +272,8 @@ class idGameLocal : public idGame { int framenum; int previousTime; // time in msec of last frame int time; // in msec - static const int msec = USERCMD_MSEC; // time since last update in milliseconds + int msec; // time since last update in milliseconds + int gameFps; //added by Stradex for com_gameHz int vacuumAreaNum; // -1 if level doesn't have any outside areas @@ -518,6 +519,7 @@ class idGameLocal : public idGame { void RunDebugInfo( void ); void InitScriptForMap( void ); + void SetScriptFPS(const float tCom_gameHz); void InitConsoleCommands( void ); void ShutdownConsoleCommands( void ); diff --git a/neo/game/Moveable.cpp b/neo/game/Moveable.cpp index e13ecd6a4..aaf9d9328 100644 --- a/neo/game/Moveable.cpp +++ b/neo/game/Moveable.cpp @@ -392,14 +392,14 @@ bool idMoveable::FollowInitialSplinePath( void ) { if ( initialSpline != NULL ) { if ( gameLocal.time < initialSpline->GetTime( initialSpline->GetNumValues() - 1 ) ) { idVec3 splinePos = initialSpline->GetCurrentValue( gameLocal.time ); - idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * USERCMD_HZ; + idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * gameLocal.gameFps; physicsObj.SetLinearVelocity( linearVelocity ); idVec3 splineDir = initialSpline->GetCurrentFirstDerivative( gameLocal.time ); idVec3 dir = initialSplineDir * physicsObj.GetAxis(); idVec3 angularVelocity = dir.Cross( splineDir ); angularVelocity.Normalize(); - angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * USERCMD_HZ; + angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * gameLocal.gameFps; physicsObj.SetAngularVelocity( angularVelocity ); return true; } else { diff --git a/neo/game/Mover.cpp b/neo/game/Mover.cpp index 9f1a8199c..d66828634 100644 --- a/neo/game/Mover.cpp +++ b/neo/game/Mover.cpp @@ -2809,7 +2809,7 @@ void idMover_Binary::Use_BinaryMover( idEntity *activator ) { if ( moverState == MOVER_POS1 ) { // FIXME: start moving USERCMD_MSEC later, because if this was player // triggered, gameLocal.time hasn't been advanced yet - MatchActivateTeam( MOVER_1TO2, gameLocal.time + USERCMD_MSEC ); + MatchActivateTeam( MOVER_1TO2, gameLocal.time + gameLocal.msec ); SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); // open areaportal diff --git a/neo/game/Player.cpp b/neo/game/Player.cpp index 8caaab4b4..7bfaf40c9 100644 --- a/neo/game/Player.cpp +++ b/neo/game/Player.cpp @@ -1295,6 +1295,7 @@ void idPlayer::Init( void ) { stamina = pm_stamina.GetFloat(); // air always initialized to maximum too + pm_airTics.SetFloat((static_cast(gameLocal.gameFps) / 60.0) * pm_airTics.GetFloat()); //update for com_gameHz airTics = pm_airTics.GetFloat(); airless = false; diff --git a/neo/game/Projectile.cpp b/neo/game/Projectile.cpp index c353ca0c6..592126746 100644 --- a/neo/game/Projectile.cpp +++ b/neo/game/Projectile.cpp @@ -1430,7 +1430,7 @@ void idGuidedProjectile::Launch( const idVec3 &start, const idVec3 &dir, const i angles = vel.ToAngles(); speed = vel.Length(); rndScale = spawnArgs.GetAngles( "random", "15 15 0" ); - turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )USERCMD_HZ; + turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )gameLocal.gameFps; clamp_dist = spawnArgs.GetFloat( "clamp_dist", "256" ); burstMode = spawnArgs.GetBool( "burstMode" ); unGuided = false; diff --git a/neo/game/SmokeParticles.cpp b/neo/game/SmokeParticles.cpp index e63307d4c..18997973b 100644 --- a/neo/game/SmokeParticles.cpp +++ b/neo/game/SmokeParticles.cpp @@ -221,7 +221,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } - prevCount = floor( ((float)( deltaMsec - USERCMD_MSEC ) / finalParticleTime) * stage->totalParticles ); + prevCount = floor( ((float)( deltaMsec - gameLocal.msec) / finalParticleTime) * stage->totalParticles ); if ( prevCount < -1 ) { prevCount = -1; } diff --git a/neo/game/physics/Force_Drag.cpp b/neo/game/physics/Force_Drag.cpp index f8682a11e..d6978f585 100644 --- a/neo/game/physics/Force_Drag.cpp +++ b/neo/game/physics/Force_Drag.cpp @@ -29,6 +29,7 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "framework/UsercmdGen.h" +#include "Game_local.h" #include "physics/Physics.h" #include "physics/Force_Drag.h" @@ -139,9 +140,9 @@ void idForce_Drag::Evaluate( int time ) { l2 = dir2.Normalize(); rotation.Set( centerOfMass, dir2.Cross( dir1 ), RAD2DEG( idMath::ACos( dir1 * dir2 ) ) ); - physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC( USERCMD_MSEC ), id ); + physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC(gameLocal.msec ), id ); - velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( USERCMD_MSEC ) ); + velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( gameLocal.msec) ); physics->SetLinearVelocity( velocity, id ); } diff --git a/neo/game/physics/Physics.cpp b/neo/game/physics/Physics.cpp index 86e35d464..0542895f6 100644 --- a/neo/game/physics/Physics.cpp +++ b/neo/game/physics/Physics.cpp @@ -75,6 +75,6 @@ idPhysics::SnapTimeToPhysicsFrame */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { int s; - s = t + USERCMD_MSEC - 1; - return ( s - s % USERCMD_MSEC ); + s = t + gameLocal.msec - 1; + return ( s - s % gameLocal.msec); } diff --git a/neo/game/physics/Physics_AF.cpp b/neo/game/physics/Physics_AF.cpp index 373048076..8ecdddac2 100644 --- a/neo/game/physics/Physics_AF.cpp +++ b/neo/game/physics/Physics_AF.cpp @@ -6607,7 +6607,7 @@ idPhysics_AF::idPhysics_AF( void ) { memset( ¤t, 0, sizeof( current ) ); current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; + current.lastTimeStep = gameLocal.msec; saved = current; linearFriction = 0.005f; diff --git a/neo/game/physics/Physics_RigidBody.cpp b/neo/game/physics/Physics_RigidBody.cpp index 838065699..6187fb99c 100644 --- a/neo/game/physics/Physics_RigidBody.cpp +++ b/neo/game/physics/Physics_RigidBody.cpp @@ -447,7 +447,7 @@ idPhysics_RigidBody::idPhysics_RigidBody( void ) { memset( ¤t, 0, sizeof( current ) ); current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; + current.lastTimeStep = gameLocal.msec; current.i.position.Zero(); current.i.orientation.Identity(); diff --git a/neo/game/script/Script_Thread.cpp b/neo/game/script/Script_Thread.cpp index 58daa5d92..e4bb560f8 100644 --- a/neo/game/script/Script_Thread.cpp +++ b/neo/game/script/Script_Thread.cpp @@ -1769,7 +1769,7 @@ idThread::Event_GetTicsPerSecond ================ */ void idThread::Event_GetTicsPerSecond( void ) { - idThread::ReturnFloat( USERCMD_HZ ); + idThread::ReturnFloat( gameLocal.gameFps ); } /* diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index 818da194a..84866c994 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -86,7 +86,7 @@ idCVar r_znear( "r_znear", "3", CVAR_RENDERER | CVAR_FLOAT, "near Z clip plane d idCVar r_ignoreGLErrors( "r_ignoreGLErrors", "1", CVAR_RENDERER | CVAR_BOOL, "ignore GL errors" ); idCVar r_finish( "r_finish", "0", CVAR_RENDERER | CVAR_BOOL, "force a call to glFinish() every frame" ); -idCVar r_swapInterval( "r_swapInterval", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "changes the GL swap interval" ); +idCVar r_swapInterval( "r_swapInterval", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "changes the GL swap interval" ); idCVar r_gamma( "r_gamma", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f ); idCVar r_brightness( "r_brightness", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f ); diff --git a/neo/renderer/RenderWorld.cpp b/neo/renderer/RenderWorld.cpp index 227c96d26..c8fa8efd5 100644 --- a/neo/renderer/RenderWorld.cpp +++ b/neo/renderer/RenderWorld.cpp @@ -432,6 +432,12 @@ void idRenderWorldLocal::UpdateLightDef( qhandle_t lightHandle, const renderLigh light->archived = false; } + // new for BFG edition: force noShadows on spectrum lights so teleport spawns + // don't cause such a slowdown. Hell writing shouldn't be shadowed anyway... + if (light->parms.shader && light->parms.shader->Spectrum()) { + light->parms.noShadows = true; + } + if ( light->lightHasMoved ) { light->parms.prelightModel = NULL; } diff --git a/neo/renderer/tr_light.cpp b/neo/renderer/tr_light.cpp index 5a6819946..5a04cc036 100644 --- a/neo/renderer/tr_light.cpp +++ b/neo/renderer/tr_light.cpp @@ -1573,10 +1573,12 @@ R_RemoveUnecessaryViewLights ===================== */ void R_RemoveUnecessaryViewLights( void ) { - viewLight_t *vLight; + viewLight_t* vLight; + int numViewLights = 0; // go through each visible light for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) { + numViewLights++; // if the light didn't have any lit surfaces visible, there is no need to // draw any of the shadows. We still keep the vLight for debugging // draws @@ -1621,4 +1623,31 @@ void R_RemoveUnecessaryViewLights( void ) { vLight->scissorRect.Intersect( surfRect ); } } + + + // BFG optimization: sort the viewLights list so the largest lights come first, which will reduce + // the chance of GPU pipeline bubbles + struct sortLight_t { + viewLight_t* vLight; + int screenArea; + static int sort(const void* a, const void* b) { + return ((sortLight_t*)a)->screenArea - ((sortLight_t*)b)->screenArea; + } + }; + sortLight_t* sortLights = (sortLight_t*)_malloca(sizeof(sortLight_t) * numViewLights); + int numSortLightsFilled = 0; + for (viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next) { + sortLights[numSortLightsFilled].vLight = vLight; + sortLights[numSortLightsFilled].screenArea = vLight->scissorRect.GetArea(); + numSortLightsFilled++; + } + + qsort(sortLights, numSortLightsFilled, sizeof(sortLights[0]), sortLight_t::sort); + + // rebuild the linked list in order + tr.viewDef->viewLights = NULL; + for (int i = 0; i < numSortLightsFilled; i++) { + sortLights[i].vLight->next = tr.viewDef->viewLights; + tr.viewDef->viewLights = sortLights[i].vLight; + } } diff --git a/neo/renderer/tr_local.h b/neo/renderer/tr_local.h index eca4bc87e..2909eb424 100644 --- a/neo/renderer/tr_local.h +++ b/neo/renderer/tr_local.h @@ -69,6 +69,9 @@ class idScreenRect { void Union( const idScreenRect &rect ); bool Equals( const idScreenRect &rect ) const; bool IsEmpty() const; + + //From BFG Edition + int GetArea() const { return (x2 - x1 + 1) * (y2 - y1 + 1); } }; idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ); diff --git a/neo/sound/snd_emitter.cpp b/neo/sound/snd_emitter.cpp index 08c6fa387..8630902cc 100644 --- a/neo/sound/snd_emitter.cpp +++ b/neo/sound/snd_emitter.cpp @@ -478,7 +478,7 @@ void idSoundEmitterLocal::CheckForCompletion( int current44kHzTime ) { } // free decoder memory if no sound was decoded for a while - if ( chan->decoder != NULL && chan->decoder->GetLastDecodeTime() < current44kHzTime - SOUND_DECODER_FREE_DELAY ) { + if ( chan->decoder != NULL && chan->decoder->GetLastDecodeTime() < current44kHzTime - (1000 * MIXBUFFER_SAMPLES / com_gameMSRate)) { chan->decoder->ClearDecoder(); } diff --git a/neo/sound/snd_local.h b/neo/sound/snd_local.h index f85f8c6dd..c5b489bb2 100644 --- a/neo/sound/snd_local.h +++ b/neo/sound/snd_local.h @@ -59,7 +59,6 @@ typedef enum { } soundDemoCommand_t; const int SOUND_MAX_CHANNELS = 8; -const int SOUND_DECODER_FREE_DELAY = 1000 * MIXBUFFER_SAMPLES / USERCMD_MSEC; // four seconds const int PRIMARYFREQ = 44100; // samples per second const float SND_EPSILON = 1.0f / 32768.0f; // if volume is below this, it will always multiply to zero diff --git a/neo/sys/osx/Doom 3.rsrc b/neo/sys/osx/Doom 3.rsrc new file mode 100644 index 0000000000000000000000000000000000000000..14327b9d798fb26a948c415c23d63a4e173970d7 GIT binary patch literal 10514 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 Yzya`pfAoSQKivZUv+s3mitpY31QGbB;{X5v literal 0 HcmV?d00001 diff --git a/neo/ui/Window.cpp b/neo/ui/Window.cpp index 2bdf96f1f..167748894 100644 --- a/neo/ui/Window.cpp +++ b/neo/ui/Window.cpp @@ -600,7 +600,7 @@ idWindow::RunTimeEvents */ bool idWindow::RunTimeEvents(int time) { - if ( time - lastTimeRun < USERCMD_MSEC ) { + if ( time - lastTimeRun < com_gameMSRate ) { //common->Printf("Skipping gui time events at %i\n", time); return false; } From 6d9f3d30786d3c3e4f6b1867d8cb5a471094d59f Mon Sep 17 00:00:00 2001 From: Stradex Date: Thu, 11 Jun 2020 14:03:09 -0300 Subject: [PATCH 2/9] fix: change _malloca to _alloca --- neo/renderer/tr_light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/renderer/tr_light.cpp b/neo/renderer/tr_light.cpp index 5a04cc036..72b5970a2 100644 --- a/neo/renderer/tr_light.cpp +++ b/neo/renderer/tr_light.cpp @@ -1634,7 +1634,7 @@ void R_RemoveUnecessaryViewLights( void ) { return ((sortLight_t*)a)->screenArea - ((sortLight_t*)b)->screenArea; } }; - sortLight_t* sortLights = (sortLight_t*)_malloca(sizeof(sortLight_t) * numViewLights); + sortLight_t* sortLights = (sortLight_t*)_alloca(sizeof(sortLight_t) * numViewLights); int numSortLightsFilled = 0; for (viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next) { sortLights[numSortLightsFilled].vLight = vLight; From 9ab12b73af0142bfa1344b4adb861b0ee329c153 Mon Sep 17 00:00:00 2001 From: Stradex Date: Thu, 11 Jun 2020 21:31:07 -0300 Subject: [PATCH 3/9] hack: inject GAME_FPS, GAME_FRAMETIME and CHAINGUN_FIRE_SKIPFRAMES in order to avoid having to use custom pak content --- neo/game/Game_local.cpp | 1 + neo/idlib/Parser.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index a5d75f82d..99d552a19 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -4405,6 +4405,7 @@ idGameLocal::SetScriptFPS */ void idGameLocal::SetScriptFPS(const float tCom_gameHz) { + idVarDef* fpsDef = program.GetDef(&type_float, "GAME_FPS", &def_namespace); if (fpsDef != NULL) { eval_t fpsValue; diff --git a/neo/idlib/Parser.cpp b/neo/idlib/Parser.cpp index 86a57d34d..c72ca66fd 100644 --- a/neo/idlib/Parser.cpp +++ b/neo/idlib/Parser.cpp @@ -249,6 +249,7 @@ define_t *idParser::CopyDefine( define_t *define ) { newdefine->hashnext = NULL; //copy the define tokens newdefine->tokens = NULL; + for (lasttoken = NULL, token = define->tokens; token; token = token->next) { newtoken = new idToken(token); newtoken->next = NULL; @@ -772,6 +773,7 @@ int idParser::ExpandDefine( idToken *deftoken, define_t *define, idToken **first if ( define->builtin ) { return idParser::ExpandBuiltinDefine( deftoken, define, firsttoken, lasttoken ); } + // if the define has parameters if ( define->numparms ) { if ( !idParser::ReadDefineParms( define, parms, MAX_DEFINEPARMS ) ) { @@ -1098,6 +1100,8 @@ int idParser::Directive_define( void ) { if ( !idParser::ReadLine( &token ) ) { return true; } + + // if it is a define with parameters if ( token.WhiteSpaceBeforeToken() == 0 && token == "(" ) { // read the define parameters @@ -1142,10 +1146,32 @@ int idParser::Directive_define( void ) { } } } + if ( !idParser::ReadLine( &token ) ) { return true; } } + + + //UGLY HACK Stradex: workaround to have com_gameHz working without having to modify script files and avoiding new pak data + if (idStr::Icmp(define->name, "GAME_FPS") == 0) { + token = cvarSystem->GetCVarString("com_gameHz"); + } + else if (idStr::Icmp(define->name, "GAME_FRAMETIME") == 0) { + float hackGameMsec = 1.0f / static_cast(cvarSystem->GetCVarInteger("com_gameHz")); + char sHackMsec[64]; + sprintf(sHackMsec, "%.3f", hackGameMsec); + token = static_cast(sHackMsec); + } + else if (idStr::Icmp(define->name, "CHAINGUN_FIRE_SKIPFRAMES") == 0) { + int newSkipFramesVal = (int)idMath::Rint(cvarSystem->GetCVarFloat("com_gameHz")/ 7.0); //FIXME: Would be better to actually read the original value from CHAINGUN_FIRE_SKIPFRAMES instead of using 7.0 directly + char sHackSkipFramesVal[64]; + sprintf(sHackSkipFramesVal, "%d", newSkipFramesVal); + token = static_cast(sHackSkipFramesVal); + } + //UGLY HACK ends + + // read the defined stuff last = NULL; do @@ -1160,6 +1186,7 @@ int idParser::Directive_define( void ) { if ( last ) last->next = t; else define->tokens = t; last = t; + } while( idParser::ReadLine( &token ) ); if ( last ) { From 8738450bb8aa1abc86891e788bc0cf0bec2bb825 Mon Sep 17 00:00:00 2001 From: Stradex Date: Fri, 12 Jun 2020 02:21:17 -0300 Subject: [PATCH 4/9] remove setscriptfps not used anymore --- neo/d3xp/Game_local.cpp | 39 +-------------------------------------- neo/d3xp/Game_local.h | 1 - neo/game/Game_local.cpp | 40 +--------------------------------------- neo/game/Game_local.h | 1 - 4 files changed, 2 insertions(+), 79 deletions(-) diff --git a/neo/d3xp/Game_local.cpp b/neo/d3xp/Game_local.cpp index 73148279e..9c492d253 100644 --- a/neo/d3xp/Game_local.cpp +++ b/neo/d3xp/Game_local.cpp @@ -1301,8 +1301,6 @@ void idGameLocal::MapPopulate( void ) { // before the physics are run so entities can bind correctly Printf( "==== Processing events ====\n" ); idEvent::ServiceEvents(); - - SetScriptFPS(static_cast(this->gameFps)); } /* @@ -1365,8 +1363,6 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo gameRenderWorld = renderWorld; gameSoundWorld = soundWorld; - SetScriptFPS(static_cast(this->gameFps)); - idRestoreGame savegame( saveGameFile ); savegame.ReadBuildNumber(); @@ -4998,37 +4994,4 @@ void idGameLocal::SwitchTeam( int clientNum, int team ) { idGameLocal::GetMapLoadingGUI =============== */ -void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } - -/* -=================== -idGameLocal::SetScriptFPS -=================== -*/ -void idGameLocal::SetScriptFPS(const float tCom_gameHz) -{ - idVarDef* fpsDef = program.GetDef(&type_float, "GAME_FPS", &def_namespace); - if (fpsDef != NULL) { - eval_t fpsValue; - fpsValue._float = tCom_gameHz; - fpsDef->SetValue(fpsValue, false); - - common->Printf("GAME_FPS: %f\n", tCom_gameHz); - } - else { - common->Printf("Unable to find GAME_FPS def\n"); - } - - float frameRate = 1.0 / tCom_gameHz; - idVarDef* frameRateDef = program.GetDef(&type_float, "GAME_FRAMETIME", &def_namespace); - if (frameRateDef != NULL) { - eval_t frameRateValue; - frameRateValue._float = frameRate; - frameRateDef->SetValue(frameRateValue, false); - - common->Printf("GAME_FRAMETIME to: %f\n", frameRate); - } - else { - common->Printf("Unable to find GAME_FRAMETIME def\n"); - } -} +void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } \ No newline at end of file diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index 2ff620930..ba22c28ab 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -588,7 +588,6 @@ class idGameLocal : public idGame { void RunDebugInfo( void ); void InitScriptForMap( void ); - void SetScriptFPS(const float tCom_gameHz); void InitConsoleCommands( void ); void ShutdownConsoleCommands( void ); diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index 99d552a19..71f186453 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -1179,8 +1179,6 @@ void idGameLocal::MapPopulate( void ) { // before the physics are run so entities can bind correctly Printf( "==== Processing events ====\n" ); idEvent::ServiceEvents(); - - SetScriptFPS(static_cast(this->gameFps)); } /* @@ -1243,8 +1241,6 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo gameRenderWorld = renderWorld; gameSoundWorld = soundWorld; - SetScriptFPS(static_cast(this->gameFps)); - idRestoreGame savegame( saveGameFile ); savegame.ReadBuildNumber(); @@ -4396,38 +4392,4 @@ void idGameLocal::SwitchTeam( int clientNum, int team ) { idGameLocal::GetMapLoadingGUI =============== */ -void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } - -/* -=================== -idGameLocal::SetScriptFPS -=================== -*/ -void idGameLocal::SetScriptFPS(const float tCom_gameHz) -{ - - idVarDef* fpsDef = program.GetDef(&type_float, "GAME_FPS", &def_namespace); - if (fpsDef != NULL) { - eval_t fpsValue; - fpsValue._float = tCom_gameHz; - fpsDef->SetValue(fpsValue, false); - - common->Printf("GAME_FPS: %f\n", tCom_gameHz); - } - else { - common->Printf("Unable to find GAME_FPS def\n"); - } - - float frameRate = 1.0 / tCom_gameHz; - idVarDef* frameRateDef = program.GetDef(&type_float, "GAME_FRAMETIME", &def_namespace); - if (frameRateDef != NULL) { - eval_t frameRateValue; - frameRateValue._float = frameRate; - frameRateDef->SetValue(frameRateValue, false); - - common->Printf("GAME_FRAMETIME to: %f\n", frameRate); - } - else { - common->Printf("Unable to find GAME_FRAMETIME def\n"); - } -} +void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } \ No newline at end of file diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index d32c91e60..13562af18 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -519,7 +519,6 @@ class idGameLocal : public idGame { void RunDebugInfo( void ); void InitScriptForMap( void ); - void SetScriptFPS(const float tCom_gameHz); void InitConsoleCommands( void ); void ShutdownConsoleCommands( void ); From 695d050c08fe1331e81325207c769fed9c1918e5 Mon Sep 17 00:00:00 2001 From: Stradex Date: Fri, 12 Jun 2020 04:51:36 -0300 Subject: [PATCH 5/9] improved framerate precision using float instead of integer. (not d3xp yet) --- neo/framework/Common.cpp | 35 +++++++++++++++++------------ neo/framework/Common.h | 26 ++++++++++++++++++++- neo/framework/Session.cpp | 4 ++-- neo/framework/async/AsyncClient.cpp | 22 +++++++++--------- neo/framework/async/AsyncServer.cpp | 10 ++++----- neo/game/Game_local.cpp | 9 ++++---- neo/game/Game_local.h | 2 +- neo/game/Mover.cpp | 2 +- neo/game/SmokeParticles.cpp | 2 +- neo/game/physics/Physics.cpp | 4 ++-- neo/game/script/Script_Thread.cpp | 4 ++-- neo/sound/snd_emitter.cpp | 2 +- neo/ui/Window.cpp | 2 +- 13 files changed, 78 insertions(+), 46 deletions(-) diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index 0a9e0ae81..c03d7ffdb 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -108,7 +108,7 @@ idCVar com_product_lang_ext( "com_product_lang_ext", "1", CVAR_INTEGER | CVAR_SY //Stradex: start idCVar com_gameHz("com_gameHz", "60", CVAR_INTEGER | CVAR_ARCHIVE | CVAR_SYSTEM, "Frames per second the game runs at", 10, 1024); -int com_gameMSRate = 1000 / 60; //Refreshed later +float com_gameMSRate = 1000.0f / 60.0f; //Refreshed later (changed to float to improve precision) int com_realGameHz = 60; bool tReloadingEngine = false; //Stradex: end @@ -190,6 +190,8 @@ class idCommonLocal : public idCommon { // NOTE: this doesn't do anything yet, but allows to add ugly mod-specific hacks without breaking the Game interface virtual bool GetAdditionalFunction(idCommon::FunctionType ft, idCommon::FunctionPointer* out_fnptr, void** out_userArg); + virtual float Get_com_gameMSRate(void); + // DG end void InitGame( void ); @@ -2423,7 +2425,7 @@ void idCommonLocal::Frame( void ) { eventLoop->RunEventLoop(); - com_frameTime = com_ticNumber * com_gameMSRate; + com_frameTime = FRAME_TO_MSEC(com_ticNumber); idAsyncNetwork::RunFrame(); @@ -2469,7 +2471,7 @@ idCommonLocal::GUIFrame void idCommonLocal::GUIFrame( bool execCmd, bool network ) { Sys_GenerateEvents(); eventLoop->RunEventLoop( execCmd ); // and execute any commands - com_frameTime = com_ticNumber * com_gameMSRate; + com_frameTime = FRAME_TO_MSEC(com_ticNumber); if ( network ) { idAsyncNetwork::RunFrame(); } @@ -2507,7 +2509,7 @@ typedef struct { static const int MAX_ASYNC_STATS = 1024; asyncStats_t com_asyncStats[MAX_ASYNC_STATS]; // indexed by com_ticNumber int prevAsyncMsec; -int lastTicMsec; +float lastTicMsec; //float for better precision with framerate void idCommonLocal::SingleAsyncTic( void ) { // main thread code can prevent this from happening while modifying @@ -2547,7 +2549,7 @@ idCommonLocal::Async ================= */ void idCommonLocal::Async( void ) { - int msec = Sys_Milliseconds(); + float msec = static_cast(Sys_Milliseconds()); if ( !lastTicMsec ) { lastTicMsec = msec - com_gameMSRate; } @@ -2558,21 +2560,21 @@ void idCommonLocal::Async( void ) { return; } - int ticMsec = com_gameMSRate; + float ticMsec = com_gameMSRate; // the number of msec per tic can be varies with the timescale cvar float timescale = com_timescale.GetFloat(); if ( timescale != 1.0f ) { ticMsec /= timescale; - if ( ticMsec < 1 ) { - ticMsec = 1; + if ( ticMsec < 1.0 ) { + ticMsec = 1.0; } } // don't skip too many if ( timescale == 1.0f ) { - if ( lastTicMsec + 10 * com_gameMSRate < msec ) { - lastTicMsec = msec - 10* com_gameMSRate; + if ( lastTicMsec + 10.0 * com_gameMSRate < msec ) { + lastTicMsec = msec - 10.0* com_gameMSRate; } } @@ -2772,7 +2774,7 @@ static unsigned int AsyncTimer(unsigned int interval, void *) { // calculate the next interval to get as close to 60fps as possible unsigned int now = SDL_GetTicks(); - unsigned int tick = com_ticNumber * com_gameMSRate; + unsigned int tick = FRAME_TO_MSEC(com_ticNumber); if (now >= tick) return 1; @@ -2961,7 +2963,7 @@ void idCommonLocal::Init( int argc, char **argv ) { //stradex: start com_realGameHz = com_gameHz.GetInteger(); - com_gameMSRate = idMath::FtoiFast(1000.0f / static_cast(com_gameHz.GetInteger())); + com_gameMSRate = 1000.0f / static_cast(com_gameHz.GetInteger()); //stradex: end // don't add startup commands if no CD key is present @@ -2996,7 +2998,7 @@ void idCommonLocal::Init( int argc, char **argv ) { Sys_Error( "Error during initialization" ); } - async_timer = SDL_AddTimer(com_gameMSRate, AsyncTimer, NULL); + async_timer = SDL_AddTimer((int)idMath::Floor(com_gameMSRate), AsyncTimer, NULL); if (!async_timer) Sys_Error("Error while starting the async timer: %s", SDL_GetError()); @@ -3133,7 +3135,7 @@ void idCommonLocal::InitGame( void ) { #ifndef ID_DEDICATED if (tReloadingEngine) { com_gameHz.SetInteger(com_realGameHz); - com_gameMSRate = idMath::FtoiFast(1000.0f / static_cast(com_gameHz.GetInteger())); + com_gameMSRate = 1000.0f / static_cast(com_gameHz.GetInteger()); //reset time and tics com_frameNumber = 0; com_ticNumber = 0; @@ -3306,6 +3308,11 @@ bool idCommonLocal::GetAdditionalFunction(idCommon::FunctionType ft, idCommon::F } } +float idCommonLocal::Get_com_gameMSRate() { + return com_gameMSRate; +} + + idGameCallbacks gameCallbacks; diff --git a/neo/framework/Common.h b/neo/framework/Common.h index 90270078e..a0fe3ce71 100644 --- a/neo/framework/Common.h +++ b/neo/framework/Common.h @@ -75,7 +75,7 @@ extern idCVar com_makingBuild; extern idCVar com_updateLoadSize; extern idCVar com_gameHz; -extern int com_gameMSRate; +extern float com_gameMSRate; extern int com_realGameHz; extern int time_gameFrame; // game logic time @@ -275,8 +275,32 @@ class idCommon { // *out_fnptr will be the function (you'll have to cast it probably) // *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL) virtual bool GetAdditionalFunction(FunctionType ft, FunctionPointer* out_fnptr, void** out_userArg) = 0; + + virtual float Get_com_gameMSRate(void) = 0; }; extern idCommon * common; +// Returns the msec the frame starts on +ID_INLINE int FRAME_TO_MSEC(int frame) +{ + return (int)idMath::Rint(static_cast(frame) * common->Get_com_gameMSRate()); +} +// Rounds DOWN to the nearest frame +ID_INLINE int MSEC_TO_FRAME_FLOOR(int msec) +{ + return (int)idMath::Floor(static_cast(msec) / common->Get_com_gameMSRate()); +} +// Rounds UP to the nearest frame +ID_INLINE int MSEC_TO_FRAME_CEIL(int msec) +{ + return (int)idMath::Ceil(static_cast(msec) / common->Get_com_gameMSRate()); +} +// Aligns msec so it starts on a frame bondary +ID_INLINE int MSEC_ALIGN_TO_FRAME(int msec) +{ + return FRAME_TO_MSEC(MSEC_TO_FRAME_CEIL(msec)); +} + + #endif /* !__COMMON_H__ */ diff --git a/neo/framework/Session.cpp b/neo/framework/Session.cpp index 24ed00204..5179054f2 100644 --- a/neo/framework/Session.cpp +++ b/neo/framework/Session.cpp @@ -538,7 +538,7 @@ void idSessionLocal::ShowLoadingGui() { int stop = Sys_Milliseconds() + 1000; int force = 10; while ( Sys_Milliseconds() < stop || force-- > 0 ) { - com_frameTime = com_ticNumber * com_gameMSRate; + com_frameTime = FRAME_TO_MSEC(com_ticNumber); session->Frame(); session->UpdateScreen( false ); } @@ -2669,7 +2669,7 @@ void idSessionLocal::Frame() { // don't let a long onDemand sound load unsync everything if ( timeHitch ) { - int skip = timeHitch / com_gameMSRate; + int skip = timeHitch / (int)idMath::Rint(com_gameMSRate); lastGameTic += skip; numCmdsToRun -= skip; timeHitch = 0; diff --git a/neo/framework/async/AsyncClient.cpp b/neo/framework/async/AsyncClient.cpp index 2eff5db5a..414c215af 100644 --- a/neo/framework/async/AsyncClient.cpp +++ b/neo/framework/async/AsyncClient.cpp @@ -1789,7 +1789,7 @@ void idAsyncClient::RunFrame( void ) { do { // blocking read with game time residual timeout - newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), com_gameMSRate - ( gameTimeResidual + clientPredictTime ) - 1 ); + newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), (int)idMath::Rint(com_gameMSRate) - ( gameTimeResidual + clientPredictTime ) - 1 ); if ( newPacket ) { msg.Init( msgBuf, sizeof( msgBuf ) ); msg.SetSize( size ); @@ -1802,14 +1802,14 @@ void idAsyncClient::RunFrame( void ) { } while( newPacket ); - } while( gameTimeResidual + clientPredictTime < com_gameMSRate ); + } while( gameTimeResidual + clientPredictTime < (int)idMath::Rint(com_gameMSRate) ); // update server list serverList.RunFrame(); if ( clientState == CS_DISCONNECTED ) { usercmdGen->GetDirectUsercmd(); - gameTimeResidual = com_gameMSRate - 1; + gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; clientPredictTime = 0; return; } @@ -1817,7 +1817,7 @@ void idAsyncClient::RunFrame( void ) { if ( clientState == CS_PURERESTART ) { clientState = CS_DISCONNECTED; Reconnect(); - gameTimeResidual = com_gameMSRate - 1; + gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; clientPredictTime = 0; return; } @@ -1827,7 +1827,7 @@ void idAsyncClient::RunFrame( void ) { // also need to read mouse for the connecting guis usercmdGen->GetDirectUsercmd(); SetupConnection(); - gameTimeResidual = com_gameMSRate - 1; + gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; clientPredictTime = 0; return; } @@ -1851,20 +1851,20 @@ void idAsyncClient::RunFrame( void ) { cvarSystem->ClearModifiedFlags( CVAR_USERINFO ); } - if ( gameTimeResidual + clientPredictTime >= com_gameMSRate ) { + if ( gameTimeResidual + clientPredictTime >= (int)idMath::Rint(com_gameMSRate)) { lastFrameDelta = 0; } // generate user commands for the predicted time - while ( gameTimeResidual + clientPredictTime >= com_gameMSRate ) { + while ( gameTimeResidual + clientPredictTime >= (int)idMath::Rint(com_gameMSRate)) { // send the user commands of this client to the server SendUsercmdsToServer(); // update time gameFrame++; - gameTime += com_gameMSRate; - gameTimeResidual -= com_gameMSRate; + gameTime = FRAME_TO_MSEC(gameFrame); + gameTimeResidual -= (int)idMath::Rint(com_gameMSRate); // run from the snapshot up to the local game frame while ( snapshotGameFrame < gameFrame ) { @@ -1875,7 +1875,7 @@ void idAsyncClient::RunFrame( void ) { DuplicateUsercmds( snapshotGameFrame, snapshotGameTime ); // indicate the last prediction frame before a render - bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < com_gameMSRate ); + bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < (int)idMath::Rint(com_gameMSRate) ); // run client prediction gameReturn_t ret = game->ClientPrediction( clientNum, userCmds[ snapshotGameFrame & ( MAX_USERCMD_BACKUP - 1 ) ], lastPredictFrame ); @@ -1883,7 +1883,7 @@ void idAsyncClient::RunFrame( void ) { idAsyncNetwork::ExecuteSessionCommand( ret.sessionCommand ); snapshotGameFrame++; - snapshotGameTime += com_gameMSRate; + snapshotGameTime = FRAME_TO_MSEC(snapshotGameFrame); } } } diff --git a/neo/framework/async/AsyncServer.cpp b/neo/framework/async/AsyncServer.cpp index f7cdda177..343825096 100644 --- a/neo/framework/async/AsyncServer.cpp +++ b/neo/framework/async/AsyncServer.cpp @@ -2378,7 +2378,7 @@ void idAsyncServer::RunFrame( void ) { do { // blocking read with game time residual timeout - newPacket = serverPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), com_gameMSRate - gameTimeResidual - 1 ); + newPacket = serverPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), (int)idMath::Rint(com_gameMSRate) - gameTimeResidual - 1 ); if ( newPacket ) { msg.Init( msgBuf, sizeof( msgBuf ) ); msg.SetSize( size ); @@ -2393,7 +2393,7 @@ void idAsyncServer::RunFrame( void ) { } while( newPacket ); - } while( gameTimeResidual < com_gameMSRate ); + } while( gameTimeResidual < (int)idMath::Rint(com_gameMSRate) ); // send heart beat to master servers MasterHeartbeat(); @@ -2434,7 +2434,7 @@ void idAsyncServer::RunFrame( void ) { } // advance the server game - while( gameTimeResidual >= com_gameMSRate ) { + while( gameTimeResidual >= (int)idMath::Rint(com_gameMSRate) ) { // sample input for the local client LocalClientInput(); @@ -2449,8 +2449,8 @@ void idAsyncServer::RunFrame( void ) { // update time gameFrame++; - gameTime += com_gameMSRate; - gameTimeResidual -= com_gameMSRate; + gameTime = FRAME_TO_MSEC(gameFrame); + gameTimeResidual -= (int)idMath::Rint(com_gameMSRate); } // duplicate usercmds so there is always at least one available to send with snapshots diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index 71f186453..813085f3a 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -301,7 +301,8 @@ void idGameLocal::Init( void ) { //Update MSEC and gameFps gameFps = cvarSystem->GetCVarInteger("com_gameHz"); - msec = idMath::FtoiFast(1000.0f / static_cast(cvarSystem->GetCVarInteger("com_gameHz"))); + msec = 1000.0f/ cvarSystem->GetCVarFloat("com_gameHz"); + Printf("msec: %d\n", msec); Printf( "----- Initializing Game -----\n" ); Printf( "gamename: %s\n", GAME_VERSION ); @@ -2210,7 +2211,7 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { // update the game time framenum++; previousTime = time; - time += msec; + time = FRAME_TO_MSEC(framenum); realClientTime = time; #ifdef GAME_DLL @@ -3545,7 +3546,7 @@ idGameLocal::AlertAI void idGameLocal::AlertAI( idEntity *ent ) { if ( ent && ent->IsType( idActor::Type ) ) { // alert them for the next frame - lastAIAlertTime = time + msec; + lastAIAlertTime = time + (int)idMath::Rint(msec); lastAIAlertEntity = static_cast( ent ); } } @@ -3950,7 +3951,7 @@ void idGameLocal::SetCamera( idCamera *cam ) { } else { inCinematic = false; - cinematicStopTime = time + msec; + cinematicStopTime = time + (int)idMath::Rint(msec); // restore r_znear cvarSystem->SetCVarFloat( "r_znear", 3.0f ); diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index 13562af18..7b0e1f4fb 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -272,7 +272,7 @@ class idGameLocal : public idGame { int framenum; int previousTime; // time in msec of last frame int time; // in msec - int msec; // time since last update in milliseconds + float msec; // time since last update in milliseconds int gameFps; //added by Stradex for com_gameHz int vacuumAreaNum; // -1 if level doesn't have any outside areas diff --git a/neo/game/Mover.cpp b/neo/game/Mover.cpp index d66828634..aa3759689 100644 --- a/neo/game/Mover.cpp +++ b/neo/game/Mover.cpp @@ -2809,7 +2809,7 @@ void idMover_Binary::Use_BinaryMover( idEntity *activator ) { if ( moverState == MOVER_POS1 ) { // FIXME: start moving USERCMD_MSEC later, because if this was player // triggered, gameLocal.time hasn't been advanced yet - MatchActivateTeam( MOVER_1TO2, gameLocal.time + gameLocal.msec ); + MatchActivateTeam( MOVER_1TO2, gameLocal.time + (int)idMath::Rint(gameLocal.msec) ); SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); // open areaportal diff --git a/neo/game/SmokeParticles.cpp b/neo/game/SmokeParticles.cpp index 18997973b..bb9ea3f3b 100644 --- a/neo/game/SmokeParticles.cpp +++ b/neo/game/SmokeParticles.cpp @@ -221,7 +221,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } - prevCount = floor( ((float)( deltaMsec - gameLocal.msec) / finalParticleTime) * stage->totalParticles ); + prevCount = floor( ((float)( deltaMsec - (int)idMath::Rint(gameLocal.msec)) / finalParticleTime) * stage->totalParticles ); if ( prevCount < -1 ) { prevCount = -1; } diff --git a/neo/game/physics/Physics.cpp b/neo/game/physics/Physics.cpp index 0542895f6..253bc1e3f 100644 --- a/neo/game/physics/Physics.cpp +++ b/neo/game/physics/Physics.cpp @@ -75,6 +75,6 @@ idPhysics::SnapTimeToPhysicsFrame */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { int s; - s = t + gameLocal.msec - 1; - return ( s - s % gameLocal.msec); + s = t + (int)idMath::Rint(gameLocal.msec) - 1; + return ( s - s % (int)idMath::Rint(gameLocal.msec)); } diff --git a/neo/game/script/Script_Thread.cpp b/neo/game/script/Script_Thread.cpp index e4bb560f8..a1ac709e0 100644 --- a/neo/game/script/Script_Thread.cpp +++ b/neo/game/script/Script_Thread.cpp @@ -669,7 +669,7 @@ bool idThread::Execute( void ) { if ( waitingUntil > lastExecuteTime ) { PostEventMS( &EV_Thread_Execute, waitingUntil - lastExecuteTime ); } else if ( interpreter.MultiFrameEventInProgress() ) { - PostEventMS( &EV_Thread_Execute, gameLocal.msec ); + PostEventMS( &EV_Thread_Execute, (int)idMath::Rint(gameLocal.msec) ); } } @@ -910,7 +910,7 @@ void idThread::WaitFrame( void ) { // manual control threads don't set waitingUntil so that they can be run again // that frame if necessary. if ( !manualControl ) { - waitingUntil = gameLocal.time + gameLocal.msec; + waitingUntil = gameLocal.time + (int)idMath::Rint(gameLocal.msec); } } diff --git a/neo/sound/snd_emitter.cpp b/neo/sound/snd_emitter.cpp index 8630902cc..0cd535190 100644 --- a/neo/sound/snd_emitter.cpp +++ b/neo/sound/snd_emitter.cpp @@ -478,7 +478,7 @@ void idSoundEmitterLocal::CheckForCompletion( int current44kHzTime ) { } // free decoder memory if no sound was decoded for a while - if ( chan->decoder != NULL && chan->decoder->GetLastDecodeTime() < current44kHzTime - (1000 * MIXBUFFER_SAMPLES / com_gameMSRate)) { + if ( chan->decoder != NULL && chan->decoder->GetLastDecodeTime() < current44kHzTime - (1000 * MIXBUFFER_SAMPLES / (int)idMath::Rint(com_gameMSRate))) { chan->decoder->ClearDecoder(); } diff --git a/neo/ui/Window.cpp b/neo/ui/Window.cpp index 167748894..c581a85e1 100644 --- a/neo/ui/Window.cpp +++ b/neo/ui/Window.cpp @@ -600,7 +600,7 @@ idWindow::RunTimeEvents */ bool idWindow::RunTimeEvents(int time) { - if ( time - lastTimeRun < com_gameMSRate ) { + if ( time - lastTimeRun < idMath::Rint(com_gameMSRate) ) { //common->Printf("Skipping gui time events at %i\n", time); return false; } From 15f4e5e8c9f3125c1b015fb3f20991e61002ea3e Mon Sep 17 00:00:00 2001 From: Stradex Date: Sat, 13 Jun 2020 03:03:03 -0300 Subject: [PATCH 6/9] update: support for d3xp --- neo/d3xp/Game_local.cpp | 32 ++++++++++++++++--------------- neo/d3xp/Game_local.h | 17 ++++++++-------- neo/d3xp/Game_network.cpp | 5 +++-- neo/d3xp/SmokeParticles.cpp | 2 +- neo/d3xp/physics/Physics.cpp | 4 ++-- neo/d3xp/script/Script_Thread.cpp | 4 ++-- neo/game/Projectile.cpp | 2 +- neo/game/physics/Physics.cpp | 4 +--- 8 files changed, 36 insertions(+), 34 deletions(-) diff --git a/neo/d3xp/Game_local.cpp b/neo/d3xp/Game_local.cpp index 9c492d253..a0b990c53 100644 --- a/neo/d3xp/Game_local.cpp +++ b/neo/d3xp/Game_local.cpp @@ -248,6 +248,7 @@ void idGameLocal::Clear( void ) { framenum = 0; previousTime = 0; time = 0; + preciseTime = 0.0f; vacuumAreaNum = 0; mapFileName.Clear(); mapFile = NULL; @@ -309,7 +310,7 @@ void idGameLocal::Init( void ) { const idDict *dict; idAAS *aas; - msec = 16; //60fps + msec = 16.0; //60fps gameMsec = msec; gameFps = 60; //60fps @@ -332,7 +333,7 @@ void idGameLocal::Init( void ) { //Update MSEC and gameFps gameFps = cvarSystem->GetCVarInteger("com_gameHz"); - msec = idMath::FtoiFast(1000.0f / static_cast(cvarSystem->GetCVarInteger("com_gameHz"))); + msec = 1000.0f / cvarSystem->GetCVarFloat("com_gameHz"); gameMsec = msec; Printf( "----- Initializing Game -----\n" ); @@ -608,7 +609,7 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteInt( time ); #ifdef _D3XP - savegame.WriteInt( msec ); + savegame.WriteFloat( msec ); #endif savegame.WriteInt( vacuumAreaNum ); @@ -1487,7 +1488,7 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadInt( time ); #ifdef _D3XP - savegame.ReadInt( msec ); + savegame.ReadFloat( msec ); #endif savegame.ReadInt( vacuumAreaNum ); @@ -2440,7 +2441,8 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { // update the game time framenum++; previousTime = time; - time += msec; + preciseTime += msec; + time = (int)idMath::Rint(preciseTime); realClientTime = time; #ifdef _D3XP @@ -3821,7 +3823,7 @@ idGameLocal::AlertAI void idGameLocal::AlertAI( idEntity *ent ) { if ( ent && ent->IsType( idActor::Type ) ) { // alert them for the next frame - lastAIAlertTime = time + msec; + lastAIAlertTime = time + (int)idMath::Rint(msec); lastAIAlertEntity = static_cast( ent ); } } @@ -4234,7 +4236,7 @@ void idGameLocal::SetCamera( idCamera *cam ) { } else { inCinematic = false; - cinematicStopTime = time + msec; + cinematicStopTime = time + idMath::Rint(msec); // restore r_znear cvarSystem->SetCVarFloat( "r_znear", 3.0f ); @@ -4830,7 +4832,7 @@ void idGameLocal::ComputeSlowMsec() { // stop the state slowmoState = SLOWMO_STATE_OFF; - slowmoMsec = (float)gameMsec; + slowmoMsec = gameMsec; } // check the player state @@ -4851,7 +4853,7 @@ void idGameLocal::ComputeSlowMsec() { slowmoMsec = msec; if ( gameSoundWorld ) { gameSoundWorld->SetSlowmo( true ); - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / gameMsec ); } } else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) { @@ -4865,10 +4867,10 @@ void idGameLocal::ComputeSlowMsec() { // do any necessary ramping if ( slowmoState == SLOWMO_STATE_RAMPUP ) { - delta = idMath::Rint(4.0 * 60.0 / (float)gameFps) - slowmoMsec; + delta = 4.0 * 60.0 / (float)gameFps - slowmoMsec; if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = idMath::Rint(4.0 * 60.0 / (float)gameFps); + slowmoMsec = 4.0 * 60.0 / (float)gameFps; slowmoState = SLOWMO_STATE_ON; } else { @@ -4876,14 +4878,14 @@ void idGameLocal::ComputeSlowMsec() { } if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / gameMsec ); } } else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) { - delta = idMath::Rint(16.0 * 60.0 / (float)gameFps) - slowmoMsec; + delta = 16.0 * 60.0 / gameFps - slowmoMsec; if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = idMath::Rint(16.0*60.0/(float)gameFps); + slowmoMsec = 16.0*60.0/(float)gameFps; slowmoState = SLOWMO_STATE_OFF; if ( gameSoundWorld ) { gameSoundWorld->SetSlowmo( false ); @@ -4894,7 +4896,7 @@ void idGameLocal::ComputeSlowMsec() { } if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)gameMsec ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / gameMsec ); } } } diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index ba22c28ab..422d30e67 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -225,14 +225,14 @@ class idEntityPtr { struct timeState_t { int time; int previousTime; - int msec; + float msec; int framenum; int realClientTime; - void Set( int t, int pt, int ms, int f, int rct ) { time = t; previousTime = pt; msec = ms; framenum = f; realClientTime = rct; }; - void Get( int& t, int& pt, int& ms, int& f, int& rct ) { t = time; pt = previousTime; ms = msec; f = framenum; rct = realClientTime; }; - void Save( idSaveGame *savefile ) const { savefile->WriteInt( time ); savefile->WriteInt( previousTime ); savefile->WriteInt( msec ); savefile->WriteInt( framenum ); savefile->WriteInt( realClientTime ); } - void Restore( idRestoreGame *savefile ) { savefile->ReadInt( time ); savefile->ReadInt( previousTime ); savefile->ReadInt( msec ); savefile->ReadInt( framenum ); savefile->ReadInt( realClientTime ); } + void Set( int t, int pt, float ms, int f, int rct ) { time = t; previousTime = pt; msec = ms; framenum = f; realClientTime = rct; }; + void Get( int& t, int& pt, float& ms, int& f, int& rct ) { t = time; pt = previousTime; ms = msec; f = framenum; rct = realClientTime; }; + void Save( idSaveGame *savefile ) const { savefile->WriteInt( time ); savefile->WriteInt( previousTime ); savefile->WriteFloat( msec ); savefile->WriteInt( framenum ); savefile->WriteInt( realClientTime ); } + void Restore( idRestoreGame *savefile ) { savefile->ReadInt( time ); savefile->ReadInt( previousTime ); savefile->ReadFloat( msec ); savefile->ReadInt( framenum ); savefile->ReadInt( realClientTime ); } void Increment() { framenum++; previousTime = time; time += msec; realClientTime = time; }; }; @@ -298,9 +298,10 @@ class idGameLocal : public idGame { int framenum; int previousTime; // time in msec of last frame int time; // in msec - int msec; // time since last update in milliseconds + float msec; // time since last update in milliseconds + float preciseTime; // added by Stradex for cm_gameHz fidelity int gameFps; //added by Stradex for com_gameHz - int gameMsec; //added by Stradex for com_gameHz (ROE) + float gameMsec; //added by Stradex for com_gameHz (ROE) int vacuumAreaNum; // -1 if level doesn't have any outside areas @@ -485,7 +486,7 @@ class idGameLocal : public idGame { // added the following to assist licensees with merge issues int GetFrameNum() const { return framenum; }; int GetTime() const { return time; }; - int GetMSec() const { return msec; }; + float GetMSec() const { return msec; }; int GetNextClientNum( int current ) const; idPlayer * GetClientByNum( int current ) const; diff --git a/neo/d3xp/Game_network.cpp b/neo/d3xp/Game_network.cpp index 36d799eee..3b180af89 100644 --- a/neo/d3xp/Game_network.cpp +++ b/neo/d3xp/Game_network.cpp @@ -1008,7 +1008,7 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam // update the game time framenum = gameFrame; time = gameTime; - previousTime = time - msec; + previousTime = time - idMath::Rint(msec); // so that StartSound/StopSound doesn't risk skipping isNewFrame = true; @@ -1532,7 +1532,8 @@ gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clie // update the game time framenum++; previousTime = time; - time += msec; + preciseTime += msec; + time = (int)idMath::Rint(preciseTime); // update the real client time and the new frame flag if ( time > realClientTime ) { diff --git a/neo/d3xp/SmokeParticles.cpp b/neo/d3xp/SmokeParticles.cpp index a39b3a347..03e0f20f0 100644 --- a/neo/d3xp/SmokeParticles.cpp +++ b/neo/d3xp/SmokeParticles.cpp @@ -236,7 +236,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } - prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was gameLocal.msec*/ ) / finalParticleTime) * stage->totalParticles ); + prevCount = floor( ((float)( deltaMsec - (int)idMath::Rint(gameLocal.msec) /*_D3XP - FIX - was gameLocal.msec*/ ) / finalParticleTime) * stage->totalParticles ); if ( prevCount < -1 ) { prevCount = -1; } diff --git a/neo/d3xp/physics/Physics.cpp b/neo/d3xp/physics/Physics.cpp index 262770405..ef1ad1d86 100644 --- a/neo/d3xp/physics/Physics.cpp +++ b/neo/d3xp/physics/Physics.cpp @@ -75,6 +75,6 @@ idPhysics::SnapTimeToPhysicsFrame */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { int s; - s = t + gameLocal.gameMsec - 1; - return ( s - s % gameLocal.gameMsec ); + s = t + (int)idMath::Rint(gameLocal.gameMsec) - 1; + return ( s - s % (int)idMath::Rint(gameLocal.gameMsec) ); } diff --git a/neo/d3xp/script/Script_Thread.cpp b/neo/d3xp/script/Script_Thread.cpp index 520a7322f..2b972314b 100644 --- a/neo/d3xp/script/Script_Thread.cpp +++ b/neo/d3xp/script/Script_Thread.cpp @@ -691,7 +691,7 @@ bool idThread::Execute( void ) { if ( waitingUntil > lastExecuteTime ) { PostEventMS( &EV_Thread_Execute, waitingUntil - lastExecuteTime ); } else if ( interpreter.MultiFrameEventInProgress() ) { - PostEventMS( &EV_Thread_Execute, gameLocal.msec ); + PostEventMS( &EV_Thread_Execute, idMath::Rint(gameLocal.msec) ); } } @@ -932,7 +932,7 @@ void idThread::WaitFrame( void ) { // manual control threads don't set waitingUntil so that they can be run again // that frame if necessary. if ( !manualControl ) { - waitingUntil = gameLocal.time + gameLocal.msec; + waitingUntil = gameLocal.time + idMath::Rint(gameLocal.msec); } } diff --git a/neo/game/Projectile.cpp b/neo/game/Projectile.cpp index 592126746..222219042 100644 --- a/neo/game/Projectile.cpp +++ b/neo/game/Projectile.cpp @@ -858,7 +858,7 @@ void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) { renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); light_fadetime = spawnArgs.GetFloat( "explode_light_fadetime", "0.5" ); lightStartTime = gameLocal.time; - lightEndTime = gameLocal.time + SEC2MS( light_fadetime ); + lightEndTime = MSEC_ALIGN_TO_FRAME(gameLocal.time + SEC2MS( light_fadetime )); BecomeActive( TH_THINK ); } diff --git a/neo/game/physics/Physics.cpp b/neo/game/physics/Physics.cpp index 253bc1e3f..b71880dbe 100644 --- a/neo/game/physics/Physics.cpp +++ b/neo/game/physics/Physics.cpp @@ -74,7 +74,5 @@ idPhysics::SnapTimeToPhysicsFrame ================ */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { - int s; - s = t + (int)idMath::Rint(gameLocal.msec) - 1; - return ( s - s % (int)idMath::Rint(gameLocal.msec)); + return MSEC_ALIGN_TO_FRAME(t); } From d6c73042eb47638858cde6b814efd8179bce61c8 Mon Sep 17 00:00:00 2001 From: Stradex Date: Sat, 13 Jun 2020 03:21:40 -0300 Subject: [PATCH 7/9] fix: multiplayer fix and more --- neo/d3xp/Game_local.h | 2 +- neo/game/Game_local.h | 2 +- neo/game/Game_network.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index 422d30e67..620fc290e 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -486,7 +486,7 @@ class idGameLocal : public idGame { // added the following to assist licensees with merge issues int GetFrameNum() const { return framenum; }; int GetTime() const { return time; }; - float GetMSec() const { return msec; }; + int GetMSec() const { return (int)idMath::Rint(msec); }; int GetNextClientNum( int current ) const; idPlayer * GetClientByNum( int current ) const; diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index 7b0e1f4fb..ac38c7c97 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -422,7 +422,7 @@ class idGameLocal : public idGame { // added the following to assist licensees with merge issues int GetFrameNum() const { return framenum; }; int GetTime() const { return time; }; - int GetMSec() const { return msec; }; + int GetMSec() const { return (int)idMath::Rint(msec); }; int GetNextClientNum( int current ) const; idPlayer * GetClientByNum( int current ) const; diff --git a/neo/game/Game_network.cpp b/neo/game/Game_network.cpp index c26d9068d..4d8869f1a 100644 --- a/neo/game/Game_network.cpp +++ b/neo/game/Game_network.cpp @@ -994,7 +994,7 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam // update the game time framenum = gameFrame; time = gameTime; - previousTime = time - msec; + previousTime = time - idMath::Rint(msec); // so that StartSound/StopSound doesn't risk skipping isNewFrame = true; @@ -1492,7 +1492,7 @@ gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clie // update the game time framenum++; previousTime = time; - time += msec; + time = FRAME_TO_MSEC(framenum); // update the real client time and the new frame flag if ( time > realClientTime ) { From bb0dd7d1b96fff9b5d6cc3de808c8e6a4a92b18b Mon Sep 17 00:00:00 2001 From: Stradex Date: Sun, 14 Jun 2020 06:37:15 -0300 Subject: [PATCH 8/9] fix: desync between client and server --- neo/framework/async/AsyncClient.cpp | 32 ++++++++++++++--------------- neo/framework/async/AsyncClient.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/neo/framework/async/AsyncClient.cpp b/neo/framework/async/AsyncClient.cpp index 414c215af..3ea492059 100644 --- a/neo/framework/async/AsyncClient.cpp +++ b/neo/framework/async/AsyncClient.cpp @@ -78,7 +78,7 @@ void idAsyncClient::Clear( void ) { snapshotSequence = 0; gameInitId = GAME_INIT_ID_INVALID; gameFrame = 0; - gameTimeResidual = 0; + gameTimeResidual = 0.0f; gameTime = 0; memset( userCmds, 0, sizeof( userCmds ) ); backgroundDownload.completed = true; @@ -718,7 +718,7 @@ void idAsyncClient::InitGame( int serverGameInitId, int serverGameFrame, int ser gameInitId = serverGameInitId; gameFrame = snapshotGameFrame = serverGameFrame; gameTime = snapshotGameTime = serverGameTime; - gameTimeResidual = 0; + gameTimeResidual = 0.0f; memset( userCmds, 0, sizeof( userCmds ) ); for ( int i = 0; i < MAX_ASYNC_CLIENTS; i++ ) { @@ -831,7 +831,7 @@ void idAsyncClient::ProcessUnreliableServerMessage( const idBitMsg &msg ) { // if this is the first snapshot after a game init was received if ( clientState == CS_CONNECTED ) { - gameTimeResidual = 0; + gameTimeResidual = 0.0f; clientState = CS_INGAME; assert( !sessLocal.GetActiveMenu( ) ); if ( idAsyncNetwork::verbose.GetInteger() ) { @@ -843,7 +843,7 @@ void idAsyncClient::ProcessUnreliableServerMessage( const idBitMsg &msg ) { if ( gameTime < snapshotGameTime || gameTime > snapshotGameTime + idAsyncNetwork::clientMaxPrediction.GetInteger() ) { gameFrame = snapshotGameFrame; gameTime = snapshotGameTime; - gameTimeResidual = idMath::ClampInt( -idAsyncNetwork::clientMaxPrediction.GetInteger(), idAsyncNetwork::clientMaxPrediction.GetInteger(), gameTimeResidual ); + gameTimeResidual = idMath::ClampFloat( -idAsyncNetwork::clientMaxPrediction.GetFloat(), idAsyncNetwork::clientMaxPrediction.GetFloat(), gameTimeResidual ); clientPredictTime = idMath::ClampInt( -idAsyncNetwork::clientMaxPrediction.GetInteger(), idAsyncNetwork::clientMaxPrediction.GetInteger(), clientPredictTime ); } @@ -1781,7 +1781,7 @@ void idAsyncClient::RunFrame( void ) { // handle ongoing pk4 downloads and patch downloads HandleDownloads(); - gameTimeResidual += msec; + gameTimeResidual += (float)msec; // spin in place processing incoming packets until enough time lapsed to run a new game frame do { @@ -1789,7 +1789,7 @@ void idAsyncClient::RunFrame( void ) { do { // blocking read with game time residual timeout - newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), (int)idMath::Rint(com_gameMSRate) - ( gameTimeResidual + clientPredictTime ) - 1 ); + newPacket = clientPort.GetPacketBlocking( from, msgBuf, size, sizeof( msgBuf ), (int)idMath::Rint(com_gameMSRate - (gameTimeResidual + (float)clientPredictTime) - 1.0f) ); if ( newPacket ) { msg.Init( msgBuf, sizeof( msgBuf ) ); msg.SetSize( size ); @@ -1798,18 +1798,18 @@ void idAsyncClient::RunFrame( void ) { } msec = UpdateTime( 100 ); - gameTimeResidual += msec; + gameTimeResidual += (float)msec; } while( newPacket ); - } while( gameTimeResidual + clientPredictTime < (int)idMath::Rint(com_gameMSRate) ); + } while( gameTimeResidual + (float)clientPredictTime < com_gameMSRate); // update server list serverList.RunFrame(); if ( clientState == CS_DISCONNECTED ) { usercmdGen->GetDirectUsercmd(); - gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; + gameTimeResidual = com_gameMSRate - 1.0f; clientPredictTime = 0; return; } @@ -1817,7 +1817,7 @@ void idAsyncClient::RunFrame( void ) { if ( clientState == CS_PURERESTART ) { clientState = CS_DISCONNECTED; Reconnect(); - gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; + gameTimeResidual = com_gameMSRate - 1.0f; clientPredictTime = 0; return; } @@ -1827,7 +1827,7 @@ void idAsyncClient::RunFrame( void ) { // also need to read mouse for the connecting guis usercmdGen->GetDirectUsercmd(); SetupConnection(); - gameTimeResidual = (int)idMath::Rint(com_gameMSRate) - 1; + gameTimeResidual = com_gameMSRate - 1.0f; clientPredictTime = 0; return; } @@ -1839,7 +1839,7 @@ void idAsyncClient::RunFrame( void ) { // if not yet in the game send empty messages to keep data flowing through the channel if ( clientState < CS_INGAME ) { Idle(); - gameTimeResidual = 0; + gameTimeResidual = 0.0f; return; } @@ -1851,12 +1851,12 @@ void idAsyncClient::RunFrame( void ) { cvarSystem->ClearModifiedFlags( CVAR_USERINFO ); } - if ( gameTimeResidual + clientPredictTime >= (int)idMath::Rint(com_gameMSRate)) { + if ( gameTimeResidual + (float)clientPredictTime >= com_gameMSRate) { lastFrameDelta = 0; } // generate user commands for the predicted time - while ( gameTimeResidual + clientPredictTime >= (int)idMath::Rint(com_gameMSRate)) { + while ( gameTimeResidual + (float)clientPredictTime >= com_gameMSRate) { // send the user commands of this client to the server SendUsercmdsToServer(); @@ -1864,7 +1864,7 @@ void idAsyncClient::RunFrame( void ) { // update time gameFrame++; gameTime = FRAME_TO_MSEC(gameFrame); - gameTimeResidual -= (int)idMath::Rint(com_gameMSRate); + gameTimeResidual -= com_gameMSRate; // run from the snapshot up to the local game frame while ( snapshotGameFrame < gameFrame ) { @@ -1875,7 +1875,7 @@ void idAsyncClient::RunFrame( void ) { DuplicateUsercmds( snapshotGameFrame, snapshotGameTime ); // indicate the last prediction frame before a render - bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < (int)idMath::Rint(com_gameMSRate) ); + bool lastPredictFrame = ( (snapshotGameFrame + 1 >= gameFrame) && (gameTimeResidual + (float)clientPredictTime < com_gameMSRate) ); // run client prediction gameReturn_t ret = game->ClientPrediction( clientNum, userCmds[ snapshotGameFrame & ( MAX_USERCMD_BACKUP - 1 ) ], lastPredictFrame ); diff --git a/neo/framework/async/AsyncClient.h b/neo/framework/async/AsyncClient.h index 2609f8db4..e5fa654c2 100644 --- a/neo/framework/async/AsyncClient.h +++ b/neo/framework/async/AsyncClient.h @@ -156,7 +156,7 @@ class idAsyncClient { int gameInitId; // game initialization identification int gameFrame; // local game frame int gameTime; // local game time - int gameTimeResidual; // left over time from previous frame + float gameTimeResidual; // left over time from previous frame usercmd_t userCmds[MAX_USERCMD_BACKUP][MAX_ASYNC_CLIENTS]; From 168b0273a8ea3c8515ec1c2c075288692fc61385 Mon Sep 17 00:00:00 2001 From: Stradex Date: Mon, 15 Jun 2020 17:26:54 -0300 Subject: [PATCH 9/9] Fix: game now running original game logic speed and solve bug with physics with player not working correctly --- neo/d3xp/Game_local.cpp | 6 ++++++ neo/framework/Common.cpp | 2 ++ neo/game/Game_local.cpp | 11 ++++++++++- neo/game/Game_local.h | 1 + neo/game/Game_network.cpp | 5 ++++- neo/game/Projectile.cpp | 3 ++- neo/game/physics/Physics.cpp | 5 ++++- 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/neo/d3xp/Game_local.cpp b/neo/d3xp/Game_local.cpp index a0b990c53..7fab32508 100644 --- a/neo/d3xp/Game_local.cpp +++ b/neo/d3xp/Game_local.cpp @@ -334,6 +334,7 @@ void idGameLocal::Init( void ) { //Update MSEC and gameFps gameFps = cvarSystem->GetCVarInteger("com_gameHz"); msec = 1000.0f / cvarSystem->GetCVarFloat("com_gameHz"); + msec *= 0.96f*0.96f; //HACK to emulate OG D3 msec error, in order to have exactly the same game logic speed gameMsec = msec; Printf( "----- Initializing Game -----\n" ); @@ -604,6 +605,8 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteBool( isMultiplayer ); savegame.WriteInt( gameType ); + savegame.WriteFloat(preciseTime); + savegame.WriteInt( framenum ); savegame.WriteInt( previousTime ); savegame.WriteInt( time ); @@ -1010,6 +1013,7 @@ void idGameLocal::LoadMap( const char *mapName, int randseed ) { previousTime = 0; time = 0; + preciseTime = 0.0f; framenum = 0; sessionCommand = ""; nextGibTime = 0; @@ -1483,6 +1487,8 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadBool( isMultiplayer ); savegame.ReadInt( (int &)gameType ); + savegame.ReadFloat(preciseTime); + savegame.ReadInt( framenum ); savegame.ReadInt( previousTime ); savegame.ReadInt( time ); diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index c03d7ffdb..62b9b9c4f 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -2964,6 +2964,7 @@ void idCommonLocal::Init( int argc, char **argv ) { //stradex: start com_realGameHz = com_gameHz.GetInteger(); com_gameMSRate = 1000.0f / static_cast(com_gameHz.GetInteger()); + //com_gameMSRate *= 0.96f; //HACK: force OG D3 msec error to ensure the games feels exactly the same in terms of speed. //stradex: end // don't add startup commands if no CD key is present @@ -3136,6 +3137,7 @@ void idCommonLocal::InitGame( void ) { if (tReloadingEngine) { com_gameHz.SetInteger(com_realGameHz); com_gameMSRate = 1000.0f / static_cast(com_gameHz.GetInteger()); + //com_gameMSRate *= 0.96f; //HACK: force OG D3 msec error to ensure the games feels exactly the same in terms of speed. //reset time and tics com_frameNumber = 0; com_ticNumber = 0; diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index 813085f3a..065fdc566 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -211,6 +211,7 @@ void idGameLocal::Clear( void ) { framenum = 0; previousTime = 0; time = 0; + preciseTime = 0.0f; vacuumAreaNum = 0; mapFileName.Clear(); mapFile = NULL; @@ -302,6 +303,7 @@ void idGameLocal::Init( void ) { //Update MSEC and gameFps gameFps = cvarSystem->GetCVarInteger("com_gameHz"); msec = 1000.0f/ cvarSystem->GetCVarFloat("com_gameHz"); + msec *= 0.96f*0.96f; //HACK to emulate OG D3 msec error, in order to have exactly the same game logic speed Printf("msec: %d\n", msec); Printf( "----- Initializing Game -----\n" ); @@ -544,6 +546,8 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteBool( isMultiplayer ); savegame.WriteInt( gameType ); + savegame.WriteFloat( preciseTime ); + savegame.WriteInt( framenum ); savegame.WriteInt( previousTime ); savegame.WriteInt( time ); @@ -928,6 +932,7 @@ void idGameLocal::LoadMap( const char *mapName, int randseed ) { previousTime = 0; time = 0; + preciseTime = 0.0f; framenum = 0; sessionCommand = ""; nextGibTime = 0; @@ -1361,6 +1366,8 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadBool( isMultiplayer ); savegame.ReadInt( (int &)gameType ); + savegame.ReadFloat( preciseTime ); + savegame.ReadInt( framenum ); savegame.ReadInt( previousTime ); savegame.ReadInt( time ); @@ -2211,7 +2218,9 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { // update the game time framenum++; previousTime = time; - time = FRAME_TO_MSEC(framenum); + preciseTime += msec; + time = (int)idMath::Rint(preciseTime); + //time = FRAME_TO_MSEC(framenum); realClientTime = time; #ifdef GAME_DLL diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index ac38c7c97..ec0e5bb56 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -274,6 +274,7 @@ class idGameLocal : public idGame { int time; // in msec float msec; // time since last update in milliseconds int gameFps; //added by Stradex for com_gameHz + float preciseTime; // added by Stradex for cm_gameHz fidelity int vacuumAreaNum; // -1 if level doesn't have any outside areas diff --git a/neo/game/Game_network.cpp b/neo/game/Game_network.cpp index 4d8869f1a..f277c650b 100644 --- a/neo/game/Game_network.cpp +++ b/neo/game/Game_network.cpp @@ -994,6 +994,7 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam // update the game time framenum = gameFrame; time = gameTime; + preciseTime = (float)gameTime; previousTime = time - idMath::Rint(msec); // so that StartSound/StopSound doesn't risk skipping @@ -1492,7 +1493,9 @@ gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clie // update the game time framenum++; previousTime = time; - time = FRAME_TO_MSEC(framenum); + preciseTime += msec; + time = (int)idMath::Rint(preciseTime); + //time = FRAME_TO_MSEC(framenum); // update the real client time and the new frame flag if ( time > realClientTime ) { diff --git a/neo/game/Projectile.cpp b/neo/game/Projectile.cpp index 222219042..ae1f85905 100644 --- a/neo/game/Projectile.cpp +++ b/neo/game/Projectile.cpp @@ -858,7 +858,8 @@ void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) { renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); light_fadetime = spawnArgs.GetFloat( "explode_light_fadetime", "0.5" ); lightStartTime = gameLocal.time; - lightEndTime = MSEC_ALIGN_TO_FRAME(gameLocal.time + SEC2MS( light_fadetime )); + //lightEndTime = MSEC_ALIGN_TO_FRAME(gameLocal.time + SEC2MS( light_fadetime )); + lightEndTime = gameLocal.time + SEC2MS(light_fadetime); BecomeActive( TH_THINK ); } diff --git a/neo/game/physics/Physics.cpp b/neo/game/physics/Physics.cpp index b71880dbe..3a84c82df 100644 --- a/neo/game/physics/Physics.cpp +++ b/neo/game/physics/Physics.cpp @@ -74,5 +74,8 @@ idPhysics::SnapTimeToPhysicsFrame ================ */ int idPhysics::SnapTimeToPhysicsFrame( int t ) { - return MSEC_ALIGN_TO_FRAME(t); + int s; + s = t + gameLocal.GetMSec() - 1; + return (s - s % gameLocal.GetMSec()); + //return MSEC_ALIGN_TO_FRAME(t); }