From 09837e275a3ce5e827fdc432ed1048d44ed6762b Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 10:21:17 +1000 Subject: [PATCH 01/29] Feature add: toggle framelimiter in-game using F4 --- src/extras/debugmenu.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/extras/debugmenu.cpp b/src/extras/debugmenu.cpp index 533b97f5..4b21feb9 100644 --- a/src/extras/debugmenu.cpp +++ b/src/extras/debugmenu.cpp @@ -6,6 +6,7 @@ #include "Timer.h" #include "rtcharse.h" #include "re3_inttypes.h" +#include "Frontend.h" #include "debugmenu.h" #include @@ -1017,6 +1018,8 @@ DebugMenuProcess(void) CPad *pad = CPad::GetPad(0); if(CTRLJUSTDOWN('M')) menuOn = !menuOn; + if (KEYJUSTDOWN(rsF4)) + FrontEndMenuManager.m_PrefsFrameLimiter = !FrontEndMenuManager.m_PrefsFrameLimiter; if(!menuOn) return; @@ -1309,4 +1312,4 @@ DebugMenuEntrySetAddress(MenuEntry *e, void *addr) ((MenuEntry_Float32*)e)->variable = (float*)addr; } } -#endif \ No newline at end of file +#endif -- 2.45.2 From c2fdc79d333c02b74eff4ef1c024243c06945cf1 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 11:53:23 +1000 Subject: [PATCH 02/29] Fix water appearance at high FPS --- src/render/WaterLevel.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index dee60d66..6b169c8e 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -921,16 +921,30 @@ CWaterLevel::RenderWater() if ( !CTimer::GetIsPaused() ) { - TEXTURE_ADDU += windAddUV; - TEXTURE_ADDV += windAddUV; - - _TEXTURE_MASK_ADDU += Sin(fAngle) * 0.0005f + 1.1f * windAddUV; - _TEXTURE_MASK_ADDV -= Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV; - - _TEXTURE_WAKE_ADDU -= Sin(fAngle) * 0.0003f + windAddUV; - _TEXTURE_WAKE_ADDV += Cos(fAngle * 0.7f) * 0.0003f + windAddUV; + #ifdef FIX_BUGS + // Stop the movement of the ocean speeding up at high FPS. + // Should be purely aesthetic, affecting only the texture UVs. + TEXTURE_ADDU += windAddUV * CTimer::GetTimeStepFix(); + TEXTURE_ADDV += windAddUV * CTimer::GetTimeStepFix(); + + _TEXTURE_MASK_ADDU += (Sin(fAngle) * 0.0005f + 1.1f * windAddUV) * CTimer::GetTimeStepFix(); + _TEXTURE_MASK_ADDV -= (Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV) * CTimer::GetTimeStepFix(); + + _TEXTURE_WAKE_ADDU -= (Sin(fAngle) * 0.0003f + windAddUV) * CTimer::GetTimeStepFix(); + _TEXTURE_WAKE_ADDV += (Cos(fAngle * 0.7f) * 0.0003f + windAddUV) * CTimer::GetTimeStepFix(); + #else + TEXTURE_ADDU += windAddUV; + TEXTURE_ADDV += windAddUV; + + _TEXTURE_MASK_ADDU += Sin(fAngle) * 0.0005f + 1.1f * windAddUV; + _TEXTURE_MASK_ADDV -= Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV; + + _TEXTURE_WAKE_ADDU -= Sin(fAngle) * 0.0003f + windAddUV; + _TEXTURE_WAKE_ADDV += Cos(fAngle * 0.7f) * 0.0003f + windAddUV; + #endif } + // What does this code do? Are the above equations sometimes unstable and make big numbers? if ( _TEXTURE_MASK_ADDU >= 1.0f ) _TEXTURE_MASK_ADDU = 0.0f; if ( _TEXTURE_MASK_ADDV >= 1.0f ) -- 2.45.2 From b3cf30be490649b64028dfc14ceee313baa95859 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 12:23:05 +1000 Subject: [PATCH 03/29] Code formatting clarify: ifdef PC_WATER > >= --- src/render/WaterLevel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 6b169c8e..13cfdede 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -1968,7 +1968,7 @@ CWaterLevel::RenderWavyMask(float fX, float fY, float fZ, #ifndef PC_WATER if (maskMorphVerts[base].z >= fMinSparkZ) #else - if ( maskMorphVerts[base].z > fMinSparkZ ) + if (maskMorphVerts[base].z > fMinSparkZ) #endif { switch ( (i + j + randval) & 3 ) -- 2.45.2 From 87595d553702c531d4349899ec32c28e2c7e3fea Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 18:16:32 +1000 Subject: [PATCH 04/29] Fix particle physics & animation at high FPS. Notably fixes: - particles moving too fast, dying too early and spinning too fast - "birds" (actually leaves) spiralling madly in the air above trees - flames coming from exhaust on Cuban - fountains looking solid white - waterdrop-on-screen spam Does NOT fix: - too many particles being genned by many things: cars, boats, etc - fountains "pulsing" (possibly due to hitting particple spawn limit?) - lots of other places particles are created once per frame (spam) --- src/render/Particle.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 461a10a6..8b8bfc58 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -1259,8 +1259,11 @@ void CParticle::Update() } vecPos += vecMoveStep; - +#ifdef FIX_BUGS + if ( psystem->m_Type == PARTICLE_FIREBALL && CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS +#else if ( psystem->m_Type == PARTICLE_FIREBALL ) +#endif { AddParticle(PARTICLE_HEATHAZE, particle->m_vecPosition, CVector(0.0f, 0.0f, 0.0f), nil, particle->m_fSize * 5.0f); @@ -1326,11 +1329,18 @@ void CParticle::Update() fDistToCam = (TheCamera.GetPosition() - vecPos).Magnitude(); } - +#ifdef FIX_BUGS + if ( numWaterDropOnScreen < nMaxDrops && numWaterDropOnScreen < 63 + && fDistToCam < 10.0f + && clearWaterDrop == false + && !CGame::IsInInterior() + && CTimer::GetLogicalFramesPassed()) // Fix waterdrop spam at high FPS +#else if ( numWaterDropOnScreen < nMaxDrops && numWaterDropOnScreen < 63 && fDistToCam < 10.0f && clearWaterDrop == false && !CGame::IsInInterior() ) +#endif { CVector vecWaterdropTarget ( @@ -1411,7 +1421,11 @@ void CParticle::Update() } } +#ifdef FIX_BUGS + if ( !(psystem->Flags & SCREEN_TRAIL) && CTimer::GetLogicalFramesPassed()) // Fix particle over-expansion at high FPS +#else if ( !(psystem->Flags & SCREEN_TRAIL) ) +#endif { float size; @@ -1701,6 +1715,12 @@ void CParticle::Update() } } +#ifdef FIX_BUGS + // Keep particles animating, rotating, fading etc at the right speed + // at high or low FPS. + for (uint32 i=0; im_nFadeToBlackTimer != 0 ) { particle->m_nColorIntensity = Clamp(particle->m_nColorIntensity - particle->m_nFadeToBlackTimer, @@ -1764,6 +1784,7 @@ void CParticle::Update() #else particle->m_nRotation += particle->m_nRotationStep; #endif + } // -- end FPS fix -- if ( particle->m_fCurrentZRadius != 0.0f ) { @@ -1773,6 +1794,16 @@ void CParticle::Update() float fY = (Sin(nSinCosIndex) + Cos(nSinCosIndex)) * particle->m_fCurrentZRadius; +#ifdef FIX_BUGS + // Prevent super-fast movement at high FPS + // We can use GetTimeSetpFix() here instead of GetLogicalFramesPassed() + // so the visual result looks "smooth" on player's screens. We can't + // do this with most of the above Timers because the effects are stored + // as uint16's instead of floats, which means tiny changes each frame + // are often rounded down to zero change each frame. + fX *= CTimer::GetTimeStepFix(); + fY *= CTimer::GetTimeStepFix(); +#endif vecPos -= particle->m_vecParticleMovementOffset; vecPos += CVector(fX, fY, 0.0f); -- 2.45.2 From ea13350238b63eb0c30cfd193304921814f3d36b Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 18:55:08 +1000 Subject: [PATCH 05/29] Fix particle spam from ParticleObject at high FPS. Stops fountains "pulsing". --- src/objects/ParticleObject.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index d8aa3f60..90abb4aa 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -423,6 +423,12 @@ CParticleObject::RemoveObject(void) void CParticleObject::UpdateAll(void) { +#ifdef FIX_BUGS + // Fix particle generation spam at high FPS + if (CTimer::GetLogicalFramesPassed() == 0) + return; +#endif + { CParticleObject *pobj = pCloseListHead; CParticleObject *nextpobj; -- 2.45.2 From ec7ddbae59088524ed21b27d629c9b4f427d8e4f Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 19:22:46 +1000 Subject: [PATCH 06/29] Fix "beastie" particle spam (tree leaves!) at high FPS. --- src/render/Weather.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp index 9f925a8c..2926d280 100644 --- a/src/render/Weather.cpp +++ b/src/render/Weather.cpp @@ -323,6 +323,11 @@ void CWeather::Update(void) void CWeather::AddHeatHaze() { +#ifdef FIX_BUGS + // Fix particle spam at high FPS + if (!CTimer::GetLogicalFramesPassed()) + return; +#endif if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) return; @@ -338,6 +343,11 @@ void CWeather::AddHeatHaze() void CWeather::AddBeastie() { +#ifdef FIX_BUGS + // Fix particle spam at high FPS. Beasties look like tree leaves. + if (!CTimer::GetLogicalFramesPassed()) + return; +#endif if(FindPlayerVehicle() || CTimer::GetFrameCounter()%10 || (CGeneral::GetRandomNumber()&5) == 0) return; CVector pos = TheCamera.GetPosition(); -- 2.45.2 From 4c034ee1d82180ed3368afb50c3cbd77b3c3b097 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 19:24:05 +1000 Subject: [PATCH 07/29] Code doc: what a BEASTIE is --- src/render/ParticleType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/ParticleType.h b/src/render/ParticleType.h index 9578083d..f46526ce 100644 --- a/src/render/ParticleType.h +++ b/src/render/ParticleType.h @@ -81,7 +81,7 @@ enum tParticleType PARTICLE_TEST, PARTICLE_BIRD_FRONT, PARTICLE_SHIP_SIDE, - PARTICLE_BEASTIE, + PARTICLE_BEASTIE, // "Beasties" look like tree leaves circling up at canopy height, but are also used in other places (eg docks) PARTICLE_RAINDROP_2D, PARTICLE_HEATHAZE, PARTICLE_HEATHAZE_IN_DIST, -- 2.45.2 From b61c0c4464fe4c765e973c0e0f653d0aca3efc5f Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 4 Jul 2021 19:25:57 +1000 Subject: [PATCH 08/29] Fix boat particle-spam at high FPS. --- src/vehicles/Boat.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 85a41099..acb0bec9 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -263,9 +263,17 @@ CBoat::ProcessControl(void) } // Damage particles +#ifdef FIX_BUGS + if(m_fHealth <= 460.0f && GetStatus() != STATUS_WRECKED && + Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f && + Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f && + CTimer::GetLogicalFramesPassed() ) // Fix high-FPS particle spam + { +#else if(m_fHealth <= 460.0f && GetStatus() != STATUS_WRECKED && Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f && Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f){ +#endif float speedSq = m_vecMoveSpeed.MagnitudeSqr(); CVector smokeDir = 0.8f*m_vecMoveSpeed; CVector smokePos; @@ -378,7 +386,11 @@ CBoat::ProcessControl(void) // Handle boat moving forward float fwdSpeed = 1.0f; if(Abs(m_fGasPedal) > 0.05f || (fwdSpeed = m_vecMoveSpeed.Magnitude2D()) > 0.01f){ +#ifdef FIX_BUGS + if(bBoatInWater && fwdSpeed > 0.05f && CTimer::GetLogicalFramesPassed()) // Fix super-short wake trail at high FPS +#else if(bBoatInWater && fwdSpeed > 0.05f) +#endif AddWakePoint(GetPosition()); float steerFactor = 1.0f; @@ -433,7 +445,11 @@ CBoat::ProcessControl(void) // Spray some particles CVector jetDir = -0.04f * force; +#ifdef FIX_BUGS + if(m_fGasPedal > 0.0f && CTimer::GetLogicalFramesPassed()){ // Fix high-FPS particle spam +#else if(m_fGasPedal > 0.0f){ +#endif if(GetStatus() == STATUS_PLAYER){ CVector sternPos = GetColModel()->boundingBox.min; sternPos.x = 0.0f; @@ -546,8 +562,15 @@ CBoat::ProcessControl(void) // Splashes float speed = m_vecMoveSpeed.Magnitude(); +#ifdef FIX_BUGS if(speed > 0.05f && GetUp().x > 0.0f && !TheCamera.GetLookingForwardFirstPerson() && IsVisible() && - (AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0)){ + (AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0) && + CTimer::GetLogicalFramesPassed() ) // Fix particle spam at high FPS +#else + if(speed > 0.05f && GetUp().x > 0.0f && !TheCamera.GetLookingForwardFirstPerson() && IsVisible() && + (AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0)) +#endif + { CVector splashPos, splashDir; float splashSize, front, waterLevel; @@ -682,8 +705,14 @@ CBoat::ProcessControl(void) } // Spray waterdrops on screen +#ifdef FIX_BUGS + if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() && + m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20 && CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS +#else if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() && - m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20){ + m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20) +#endif + { CVector dropPos; CVector dropDir(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), CGeneral::GetRandomNumberInRange(1.0f, 0.75f), 0.0f); @@ -714,7 +743,13 @@ CBoat::ProcessControl(void) numWaterDropOnScreen++; } - if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER){ +#ifdef FIX_BUGS + if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER && + CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS +#else + if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER) +#endif + { CVector splashDir(0.0f, 0.0f, 0.25f*speed); CVector splashPos = GetPosition(); float level; -- 2.45.2 From 7ea8d5fec10f0533488a1083c24aae48126fcacb Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Mon, 5 Jul 2021 09:33:05 +1000 Subject: [PATCH 09/29] Fix boat controls ramp rate at high FPS --- src/vehicles/Boat.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index acb0bec9..586fb535 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -808,6 +808,18 @@ CBoat::ProcessControlInputs(uint8 pad) m_fBrake += (CPad::GetPad(pad)->GetBrake()/255.0f - m_fBrake)*0.1f; m_fBrake = Clamp(m_fBrake, 0.0f, 1.0f); +#ifdef FIX_BUGS + // Fix accelerator control and steering control ramp rates at high FPS + if(m_fBrake < 0.05f){ + m_fBrake = 0.0f; + m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f*CTimer::GetTimeStepFix(); + m_fAccelerate = Clamp(m_fAccelerate, 0.0f, 1.0f); + }else + m_fAccelerate = -m_fBrake*0.3f; + + m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f*CTimer::GetTimeStepFix(); + m_fSteeringLeftRight = Clamp(m_fSteeringLeftRight, -1.0f, 1.0f); +#else if(m_fBrake < 0.05f){ m_fBrake = 0.0f; m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f; @@ -817,6 +829,7 @@ CBoat::ProcessControlInputs(uint8 pad) m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f; m_fSteeringLeftRight = Clamp(m_fSteeringLeftRight, -1.0f, 1.0f); +#endif float steeringSq = m_fSteeringLeftRight < 0.0f ? -SQR(m_fSteeringLeftRight) : SQR(m_fSteeringLeftRight); m_fSteerAngle = pHandling->fSteeringLock * DEGTORAD(steeringSq); -- 2.45.2 From 5adafb5cd06888c1a6ecd8970afa559fb36e2ce2 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Mon, 5 Jul 2021 09:34:22 +1000 Subject: [PATCH 10/29] CBoat::ApplyWaterResistance: Incomplete work fixing slow boats at high FPS. Fixed minor mathematical bug with Pow() and Abs(). Added detailed explanation of physics. --- src/vehicles/Boat.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 586fb535..fe998d72 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -841,6 +841,79 @@ float fSeaPlaneWaterResistance = 30.0f; void CBoat::ApplyWaterResistance(void) { +#ifdef FIX_BUGS + // TODO: confirm if the explanation below makes sense + float depthResistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass; + if(GetModelIndex() == MI_SKIMMER) + depthResistance *= fSeaPlaneWaterResistance; + float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward()); + + // Water resistances goes up with the square of boat speed (in real life it goes up by the + // cube? close enough!). An extra 0.05f fudge factor was probably put in to make sure the + // boat still has resistance at low speeds (ie auto-brakes to standstill). + float waterResistance = (SQR(fwdSpeed) + 0.05f) * Abs(depthResistance); // Abs() used defensively, negative numbers stuff things up later + // waterResistance will now be a small number like 0.002 or 0.015 + + // An odd use of Abs() was in the original binary. It's possible that the developers did not + // put this in intentionally, instead the compiler may have silently added it to avoid + // Pow() having to deal with negative numbers to a fractional power (undefined) later. + // Regardless it was done badly, making assumptions like vecMoveRes never accidentally + // being negative, so the use of Abs() has changed a little bit in this FIX_BUGS. In + // real gameplay these corner cases should rarely (never?) be encountered anyway. + + // Our boat has different water resistances when travelling forwards (y axis) versus + // sideways (x axis). Boats tend to find it hard to move sideways. + float rx = Abs(pBoatHandling->vecMoveRes.x/(waterResistance + 1.0f)); // Abs() used defensively, negative numbers stuff things up later + float ry = Abs(pBoatHandling->vecMoveRes.y/(waterResistance + 1.0f)); + float rz = Abs(pBoatHandling->vecMoveRes.z/(waterResistance + 1.0f)); + // These rx, ry, rz resistance numbers will each be something like 0.8 or 0.9 or so + + // Fun fact: the above equations are _approximately_ the same as: + // + // pBoatHandling->vecMoveRes.x * (1.0f - waterResistance) + // + // If you change the equations to this then boating feels about the same in-game. + // Which version makes more sense compared to physics in real life? Probably neither :P + // This second version of the equation is a little more efficient however (no division). + + // Now how do we apply these rx ry rz resistance numbers to the boat speed? + // It's not simple: + // + // - We can't multiply them into the speed once per frame, because then players with + // higher framerates will get a lot more friction when boating (lower top speed). + // + // - We can't linearly modify each r number based off frametime, as higher FPS players + // will still end up with more friction. This is for the same reason why linearly + // reducing your bank account's yearly interest into monthly amounts but then + // compounding it monthly will yield you more money than just compounding it yearly. + // + // - We could try compounding each r number based off how many fixed units of time have + // passed (eg multiply itself by itself for every 1ms elapsed this frame). This will + // work fairly regardless of framerate. + // + // We don't actually have to limit ourselves to a fixed time unit (like 1ms chunks), + // instead we can raise the resistance to some power of time using Pow(). + float rrx = Pow(rx, 0.5f*CTimer::GetTimeStep()); // Why 0.5f? Taste? + float rry = Pow(ry, 0.5f*CTimer::GetTimeStep()); + float rrz = Pow(rz, 0.5f*CTimer::GetTimeStep()); + + m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // convert velocities to boat-local space (y = boat forwards, x = sideways, z = up/down) + m_vecMoveSpeed.x *= rrx; + m_vecMoveSpeed.y *= rry; + m_vecMoveSpeed.z *= rrz; + float force = (rry - 1.0f) * m_vecMoveSpeed.y * m_fMass; + m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed); // back to world space + + // Is this for "flipping the boat over"? Seems to have almost zero effect normally? + ApplyTurnForce(force*GetForward(), -GetUp()); + + // What the hell? Why arbitrarily compound in one more factor of rrz? + // This is framerate dependent! Bah! + if(m_vecMoveSpeed.z > 0.0f) + m_vecMoveSpeed.z *= rrz; + else + m_vecMoveSpeed.z *= (1.0f - rrz)*0.5f + rrz; +#else // TODO: figure out how this works float resistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass; if(GetModelIndex() == MI_SKIMMER) @@ -865,6 +938,7 @@ CBoat::ApplyWaterResistance(void) m_vecMoveSpeed.z *= fz; else m_vecMoveSpeed.z *= (1.0f - fz)*0.5f + fz; +#endif } RwObject* -- 2.45.2 From 7c4a66a28dce5bd49b21c3c1735eb28a5bed32ce Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Thu, 8 Jul 2021 21:20:13 +1000 Subject: [PATCH 11/29] Make burst tires wiggle the vehicle at about the same frequency regardless of framerate. --- src/vehicles/Vehicle.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index a41e0fa0..2839a433 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -820,7 +820,12 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon if(wheelStatus == WHEEL_STATUS_BURST){ float fwdspeed = Min(contactSpeedFwd, fBurstSpeedMax); +#ifdef FIX_BUGS + // Keep the effect running at the same frequency even when the game is at high FPS + right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstTyreMod, fBurstTyreMod) * CTimer::GetLogicalFramesPassed(); +#else right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstTyreMod, fBurstTyreMod); +#endif } } -- 2.45.2 From 179450ca03248ca1683c355303b58bb709544e61 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Thu, 8 Jul 2021 21:21:22 +1000 Subject: [PATCH 12/29] Fix vehicle turning circle at high FPS. Likely to fix some rotation speed problems with other entities. Does not fix the fact it's harder to enter a skid at high FPS. --- src/entities/Physical.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 890e7876..f6c44cb0 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -1830,9 +1830,16 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) A->GetStatus() == STATUS_PLAYER && A->IsVehicle() && Abs(A->m_vecMoveSpeed.x) > 0.2f && Abs(A->m_vecMoveSpeed.y) > 0.2f){ +#ifdef FIX_BUGS + // Fix vehicles having lower turning circles at high FPS + A->m_vecMoveFriction.x += CTimer::GetTimeStepFix() * moveSpeed.x * -0.3f / numCollisions; + A->m_vecMoveFriction.y += CTimer::GetTimeStepFix() * moveSpeed.y * -0.3f / numCollisions; + A->m_vecTurnFriction += CTimer::GetTimeStepFix() * turnSpeed * -0.3f / numCollisions; +#else A->m_vecMoveFriction.x += moveSpeed.x * -0.3f / numCollisions; A->m_vecMoveFriction.y += moveSpeed.y * -0.3f / numCollisions; A->m_vecTurnFriction += turnSpeed * -0.3f / numCollisions; +#endif } if(B->IsObject() && Bobj->m_nCollisionDamageEffect && maxImpulseA > 20.0f) -- 2.45.2 From d8e8f1cae8572dfca781857f771fd1e4a6d60421 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Thu, 8 Jul 2021 21:24:36 +1000 Subject: [PATCH 13/29] Make burst tires wiggle BIKES at about the same frequency regardless of framerate. --- src/vehicles/Vehicle.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 2839a433..c9895e80 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -985,8 +985,13 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee #endif if(wheelStatus == WHEEL_STATUS_BURST){ - float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax); + float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax); +#ifdef FIX_BUGS + // Keep the effect running at the same frequency even when the game is at high FPS + right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod) * CTimer::GetLogicalFramesPassed(); +#else right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod); +#endif } } -- 2.45.2 From 879280bcf7abb2f21c6d4886bbb89ce640e478ae Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Fri, 23 Jul 2021 18:18:29 +1000 Subject: [PATCH 14/29] Add comment about cause of throttle pulsing when reversing. --- src/vehicles/Transmission.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp index 1aeabfe0..1dff2b30 100644 --- a/src/vehicles/Transmission.cpp +++ b/src/vehicles/Transmission.cpp @@ -55,6 +55,8 @@ cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear) } } +/* This function causes 'pulsing' of throttle when reversing at max speed. You + * can most easily observe this when the framelimiter is enabled.*/ float cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat) { -- 2.45.2 From ba832f93e80fdff79556b8e5efd4ee088e8f5a18 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Fri, 23 Jul 2021 22:45:34 +1000 Subject: [PATCH 15/29] Fix all(?) vehicle handling problems at high FPS. Refactor FIX_BUGS in ProcessWheel() to be much simpler. --- src/entities/Physical.cpp | 27 +++++++++++ src/vehicles/Automobile.cpp | 16 ++++--- src/vehicles/Transmission.cpp | 5 ++ src/vehicles/Vehicle.cpp | 88 +++++++++++++++++------------------ 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 1e0b33de..79311aad 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -590,7 +590,12 @@ CPhysical::ApplyAirResistance(void) }else if(GetStatus() != STATUS_GHOST){ float f = Pow(1.0f/Abs(1.0f + m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr()), CTimer::GetTimeStep()); m_vecMoveSpeed *= f; +#ifdef FIX_BUGS + // Fix too much friction at high FPS (evil cause of bad vehicle handling, rear tires unable to lose traction, etc!) + m_vecTurnSpeed *= Pow(0.99f, CTimer::GetTimeStepFix()); +#else m_vecTurnSpeed *= 0.99f; +#endif } } @@ -1071,6 +1076,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) if(fOtherSpeedA > speedSum){ impulseA = (speedSum - fOtherSpeedA) * A->m_fMass; impulseB = (speedSum - fOtherSpeedB) * B->m_fMass; +#ifdef FIX_BUGS + impulseA *= CTimer::GetTimeStepFix(); + impulseB *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); if(impulseA < -impulseLimit) impulseA = -impulseLimit; #ifdef FIX_BUGS @@ -1107,6 +1116,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) if(fOtherSpeedA > speedSum){ impulseA = (speedSum - fOtherSpeedA) * A->m_fMass; impulseB = (speedSum - fOtherSpeedB) * massB; +#ifdef FIX_BUGS + impulseA *= CTimer::GetTimeStepFix(); + impulseB *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); if(impulseA < -impulseLimit) impulseA = -impulseLimit; if(impulseB > impulseLimit) impulseB = impulseLimit; @@ -1140,6 +1153,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) if(fOtherSpeedA > speedSum){ impulseA = (speedSum - fOtherSpeedA) * massA; impulseB = (speedSum - fOtherSpeedB) * B->m_fMass; +#ifdef FIX_BUGS + impulseA *= CTimer::GetTimeStepFix(); + impulseB *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); if(impulseA < -impulseLimit) impulseA = -impulseLimit; if(impulseB > impulseLimit) impulseB = impulseLimit; @@ -1174,6 +1191,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) if(fOtherSpeedA > speedSum){ impulseA = (speedSum - fOtherSpeedA) * massA; impulseB = (speedSum - fOtherSpeedB) * massB; +#ifdef FIX_BUGS + impulseA *= CTimer::GetTimeStepFix(); + impulseB *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); if(impulseA < -impulseLimit) impulseA = -impulseLimit; if(impulseB > impulseLimit) impulseB = impulseLimit; @@ -1214,6 +1235,9 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) // not really impulse but speed // maybe use ApplyFrictionMoveForce instead? fImpulse = -fOtherSpeed; +#ifdef FIX_BUGS + fImpulse *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep() / m_fMass; if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; CVector vImpulse = frictionDir*fImpulse; @@ -1235,6 +1259,9 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); #endif fImpulse = -fOtherSpeed * m_fMass; +#ifdef FIX_BUGS + fImpulse *= CTimer::GetTimeStepFix(); +#endif impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5; if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; ApplyFrictionMoveForce(frictionDir*fImpulse); diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 5e2b0c10..0a577c0c 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -857,8 +857,12 @@ CAutomobile::ProcessControl(void) (m_aSuspensionSpringRatio[1] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f)) ApplyTurnForce(-GRAVITY*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward()); } - +#ifdef FIX_BUGS + // Keep brake non-timestepped (so the later ProcessWheel() takes only non-timestepped inputs) + brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetDefaultTimeStep(); +#else brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep(); +#endif bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING); float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias; float brakeBiasRear = neutralHandling ? 1.0f : 2.0f-pHandling->fBrakeBias; // looks like a bug, but it was correct in III... @@ -1058,12 +1062,7 @@ CAutomobile::ProcessControl(void) float rearBrake = brake; float rearTraction = traction; if(bIsHandbrakeOn){ -#ifdef FIX_BUGS - // Not sure if this is needed, but brake usually has timestep as a factor - rearBrake = 20000.0f * CTimer::GetTimeStepFix(); -#else rearBrake = 20000.0f; -#endif if(fwdSpeed > 0.1f && pHandling->Flags & HANDLING_HANDBRAKE_TYRE){ m_fTireTemperature += 0.005*CTimer::GetTimeStep(); if(m_fTireTemperature > 2.0f) @@ -1072,8 +1071,11 @@ CAutomobile::ProcessControl(void) }else if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)){ rearBrake = 0.0f; rearTraction = 0.0f; - // BUG: missing timestep +#ifdef FIX_BUGS + ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight()*CTimer::GetTimeStepFix()); +#else ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight()); +#endif }else if(m_fTireTemperature > 1.0f){ rearTraction *= m_fTireTemperature; } diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp index 1dff2b30..9ad00a09 100644 --- a/src/vehicles/Transmission.cpp +++ b/src/vehicles/Transmission.cpp @@ -125,7 +125,12 @@ cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, fl float targetVelocity = Gears[gear].fMaxVelocity*speedMul*fCheat; float accel = (targetVelocity - fVelocity) * (fEngineAcceleration*accelMul) / Abs(targetVelocity); if(Abs(fVelocity) < Abs(Gears[gear].fMaxVelocity*fCheat)) +#ifdef FIX_BUGS + // The acceleration provided by a transmission+engine should not depend on framelength. + fAcceleration = gasPedal * accel; +#else fAcceleration = gasPedal * accel * CTimer::GetTimeStep(); +#endif else fAcceleration = 0.0f; return fAcceleration; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index d891e1e4..6dcca5e7 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -788,7 +788,14 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon bAlreadySkidding = false; #endif - // how much force we want to apply in these axes + // Velocity impulses fwd and right. Units are like meters per second. + // This function was written assuming a fixed FPS, so a correction is made + // right at the end before actually applying these impulses. + // + // Note that many functions in this engine deal with "force impulses" rather + // than "velocity impulses". They are directly related: F=ma. It is + // possible that the original devs actually used force impulses here but + // an optimising compiler re-arranged their maths. float fwd = 0.0f; float right = 0.0f; @@ -804,7 +811,12 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon bAlreadySkidding = true; *wheelState = WHEEL_STATE_NORMAL; +#ifdef FIX_BUGS + // Everything else here is timestep independent, let's stay with this theme to keep the rest of the FPS bugfixes simpler. + adhesion *= CTimer::GetDefaultTimeStep(); +#else adhesion *= CTimer::GetTimeStep(); +#endif if(bAlreadySkidding) adhesion *= pHandling->fTractionLoss; @@ -812,28 +824,17 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon if(contactSpeedRight != 0.0f){ // exert opposing force right = -contactSpeedRight/wheelsOnGround; - // BUG? - // contactSpeedRight is independent of framerate but right has timestep as a factor - // so we probably have to fix this - // fixing this causes jittery cars at 15fps, and causes the car to move backwards slowly at 18fps - // at 19fps, the effects are gone ... - //right *= CTimer::GetTimeStepFix(); if(wheelStatus == WHEEL_STATUS_BURST){ float fwdspeed = Min(contactSpeedFwd, fBurstSpeedMax); -#ifdef FIX_BUGS - // Keep the effect running at the same frequency even when the game is at high FPS - right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstTyreMod, fBurstTyreMod) * CTimer::GetLogicalFramesPassed(); -#else right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstTyreMod, fBurstTyreMod); -#endif } } if(bDriving){ fwd = thrust; - // limit sideways force (why?) + // Limit sideways forces applied by the tires to the max the tires can possibly do. if(right > 0.0f){ if(right > adhesion) right = adhesion; @@ -843,11 +844,6 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon } }else if(contactSpeedFwd != 0.0f){ fwd = -contactSpeedFwd/wheelsOnGround; -#ifdef FIX_BUGS - // contactSpeedFwd is independent of framerate but fwd has timestep as a factor - // so we probably have to fix this - fwd *= CTimer::GetTimeStepFix(); -#endif if(!bBraking){ if(m_fGasPedal < 0.01f){ @@ -859,9 +855,6 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->fMass; else brake = mod_HandlingManager.fWheelFriction / pHandling->fMass; -#ifdef FIX_BUGS - brake *= CTimer::GetTimeStepFix(); -#endif } } @@ -888,10 +881,10 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon *wheelState = WHEEL_STATE_SKIDDING; } - float l = Sqrt(speedSq); + float speed = Sqrt(speedSq); float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss; - right *= adhesion * tractionLoss / l; - fwd *= adhesion * tractionLoss / l; + right *= adhesion * tractionLoss / speed; + fwd *= adhesion * tractionLoss / speed; } if(fwd != 0.0f || right != 0.0f){ @@ -923,9 +916,19 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon else turnDirection = direction; + + // Curious: there is a perfectly good ApplyMoveSpeed() function that + // takes "velocity impulses", but instead we use the ApplyMoveForce() + // function which takes a "force impulse" instead and then fix up the + // difference by multiplying in the vehicle mass (F=ma). Possibly + // evidence that an optimising compiler re-arranged the arithmetic? float impulse = speed*m_fMass; float turnImpulse = turnSpeed*GetMass(wheelContactPoint, turnDirection); +#ifdef FIX_BUGS + impulse = impulse * CTimer::GetTimeStepFix(); + turnImpulse = turnImpulse * CTimer::GetTimeStepFix(); +#endif ApplyMoveForce(impulse * direction); ApplyTurnForce(turnImpulse * turnDirection, wheelContactPoint); } @@ -949,7 +952,14 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee bAlreadySkidding = false; #endif - // how much force we want to apply in these axes + // Velocity impulses fwd and right. Units are like meters per second. + // This function was written assuming a fixed FPS, so a correction is made + // right at the end before actually applying these impulses. + // + // Note that many functions in this engine deal with "force impulses" rather + // than "velocity impulses". They are directly related: F=ma. It is + // possible that the original devs actually used force impulses here but + // an optimising compiler re-arranged their maths. float fwd = 0.0f; float right = 0.0f; @@ -966,7 +976,12 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee bAlreadySkidding = true; *wheelState = WHEEL_STATE_NORMAL; +#ifdef FIX_BUGS + // Everything else here is timestep independent, let's stay with this theme to keep the rest of the FPS bugfixes simpler. + adhesion *= CTimer::GetDefaultTimeStep(); +#else adhesion *= CTimer::GetTimeStep(); +#endif if(bAlreadySkidding) adhesion *= pHandling->fTractionLoss; @@ -979,20 +994,10 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee if(contactSpeedRight != 0.0f){ // exert opposing force right = -contactSpeedRight/wheelsOnGround; -#ifdef FIX_BUGS - // contactSpeedRight is independent of framerate but right has timestep as a factor - // so we probably have to fix this - right *= CTimer::GetTimeStepFix(); -#endif if(wheelStatus == WHEEL_STATUS_BURST){ float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax); -#ifdef FIX_BUGS - // Keep the effect running at the same frequency even when the game is at high FPS - right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod) * CTimer::GetLogicalFramesPassed(); -#else right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod); -#endif } } @@ -1009,12 +1014,6 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee } }else if(contactSpeedFwd != 0.0f){ fwd = -contactSpeedFwd/wheelsOnGround; -#ifdef FIX_BUGS - // contactSpeedFwd is independent of framerate but fwd has timestep as a factor - // so we probably have to fix this - fwd *= CTimer::GetTimeStepFix(); -#endif - if(!bBraking){ if(m_fGasPedal < 0.01f){ if(IsBike()) @@ -1025,9 +1024,6 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass; else brake = mod_HandlingManager.fWheelFriction / m_fMass; -#ifdef FIX_BUGS - brake *= CTimer::GetTimeStepFix(); -#endif } } @@ -1078,6 +1074,10 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee float impulse = speed*m_fMass; float turnImpulse = speed*GetMass(wheelContactPoint, direction); +#ifdef FIX_BUGS + impulse = impulse * CTimer::GetTimeStepFix(); + turnImpulse = turnImpulse * CTimer::GetTimeStepFix(); +#endif CVector vTurnImpulse = turnImpulse * direction; ApplyMoveForce(impulse * direction); -- 2.45.2 From 763337c25508e5c4eb91c87166a346a5141cd6af Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 10:13:52 +1000 Subject: [PATCH 16/29] Fix weak bike brakes at high FPS (possibly caused by ba832f93e80fdff79556b8e5efd4ee088e8f5a18 ) --- src/vehicles/Bike.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp index a65b64d2..f1ca7ac9 100644 --- a/src/vehicles/Bike.cpp +++ b/src/vehicles/Bike.cpp @@ -722,7 +722,12 @@ CBike::ProcessControl(void) acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat); acceleration /= m_fForceMultiplier; +#ifdef FIX_BUGS + // Keep timestep out of this, it gets added properly inside ProcessWheel() later. Fixes weak brakes at high FPS. + brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetDefaultTimeStep(); +#else brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep(); +#endif bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING); float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias; float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias); -- 2.45.2 From cae0a3f4022400d44e1768551f48c5cb3ed9cd08 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 10:23:05 +1000 Subject: [PATCH 17/29] More bike brake fixes for high FPS --- src/vehicles/Bike.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp index f1ca7ac9..6af3e131 100644 --- a/src/vehicles/Bike.cpp +++ b/src/vehicles/Bike.cpp @@ -887,12 +887,7 @@ CBike::ProcessControl(void) wheelRight.Normalise(); if(bIsHandbrakeOn){ -#ifdef FIX_BUGS - // Not sure if this is needed, but brake usually has timestep as a factor - rearBrake = 20000.0f * CTimer::GetTimeStepFix(); -#else rearBrake = 20000.0f; -#endif m_fTireTemperature = 1.0f; }else if(m_doingBurnout){ rearBrake = 0.0f; -- 2.45.2 From 613f0964bb646fabd6860d9da797e107e70e1741 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 10:45:57 +1000 Subject: [PATCH 18/29] Partially fix boat physics at high FPS. --- src/vehicles/Boat.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index b0e9b859..f4d00765 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -533,6 +533,10 @@ CBoat::ProcessControl(void) m_vecTurnSpeed.y *= fy; m_vecTurnSpeed.z *= fz; float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass; +#ifdef FIX_BUGS + // Partly fixes boat perf at high FPS + forceUp *= CTimer::GetTimeStepFix(); +#endif m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); ApplyTurnForce(forceUp*GetUp(), com + GetForward()); -- 2.45.2 From e0dfa8b9717f537bd74611ef665d008c2b092715 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 13:50:14 +1000 Subject: [PATCH 19/29] Revert "Partially fix boat physics at high FPS" - changes were incorrect, factors of time were already included. This reverts commit 613f0964bb646fabd6860d9da797e107e70e1741. --- src/vehicles/Boat.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index f4d00765..b0e9b859 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -533,10 +533,6 @@ CBoat::ProcessControl(void) m_vecTurnSpeed.y *= fy; m_vecTurnSpeed.z *= fz; float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass; -#ifdef FIX_BUGS - // Partly fixes boat perf at high FPS - forceUp *= CTimer::GetTimeStepFix(); -#endif m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); ApplyTurnForce(forceUp*GetUp(), com + GetForward()); -- 2.45.2 From 6f8ba21552d8a8486d2492048ea8c37e83d4a72d Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 21:49:34 +1000 Subject: [PATCH 20/29] Fix many boat performance issues at high FPS, but cornering/handling still not perfect. --- src/vehicles/Boat.cpp | 74 ++++++++++++++++++++++++++++++++-------- src/vehicles/Floater.cpp | 11 ++++++ 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index b0e9b859..92e9e687 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -343,6 +343,7 @@ CBoat::ProcessControl(void) bIsDrowning = false; } + // Apply buoyancy impulse the first time (why twice?) m_fVolumeUnderWater = mod_Buoyancy.m_volumeUnderWater; m_vecBuoyancePoint = buoyancePoint; if(GetModelIndex() == MI_SKIMMER && GetUp().z < -0.5f && Abs(m_vecMoveSpeed.x) < 0.2f && Abs(m_vecMoveSpeed.y) < 0.2f) @@ -352,13 +353,17 @@ CBoat::ProcessControl(void) if(bSeparateTurnForce) ApplyTurnForce(0.4f*buoyanceImpulse, buoyancePoint); - // TODO: what is this? if(GetModelIndex() == MI_SKIMMER) if(m_skimmerThingTimer != 0.0f || GetForward().z < -0.5f && GetUp().z > -0.5f && m_vecMoveSpeed.z < -0.15f && buoyanceImpulse.z > 0.01f*m_fMass * GRAVITY*CTimer::GetTimeStep() && buoyanceImpulse.z < 0.4f*m_fMass * GRAVITY*CTimer::GetTimeStep()){ +#ifdef FIX_BUGS + // buoyanceImpulse already has a factor of timestep in it + float turnImpulse = -0.00017f*GetForward().z*buoyanceImpulse.z * m_fMass*CTimer::GetDefaultTimeStep(); +#else float turnImpulse = -0.00017f*GetForward().z*buoyanceImpulse.z * m_fMass*CTimer::GetTimeStep(); +#endif ApplyTurnForce(turnImpulse*GetForward(), GetUp()); bBoatInWater = false; //BUG? aren't we forgetting the timestep here? @@ -370,15 +375,21 @@ CBoat::ProcessControl(void) m_skimmerThingTimer = 0.0f; } + // Apply buoyancy impulse the second time (why twice?) if(!onLand && bBoatInWater && GetUp().z > 0.0f){ +#ifdef FIX_BUGS + // buoyanceImpulse already has a factor of timestep in it + float impulse = m_vecMoveSpeed.MagnitudeSqr()*pBoatHandling->fAqPlaneForce*buoyanceImpulse.z*CTimer::GetDefaultTimeStep()*0.5f; +#else float impulse = m_vecMoveSpeed.MagnitudeSqr()*pBoatHandling->fAqPlaneForce*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f; +#endif if(GetModelIndex() == MI_SKIMMER) impulse *= 1.0f + m_fGasPedal; else if(m_fGasPedal > 0.05f) impulse *= m_fGasPedal; else impulse = 0.0f; - impulse = Min(impulse, GRAVITY*pBoatHandling->fAqPlaneLimit*m_fMass*CTimer::GetTimeStep()); + impulse = Min(impulse, GRAVITY*pBoatHandling->fAqPlaneLimit*m_fMass*CTimer::GetTimeStep()); // Both sides have a factor of TimeStep, therefore this Min() is not a problem at high FPS ApplyMoveForce(impulse*GetUp()); ApplyTurnForce(impulse*GetUp(), buoyancePoint - pBoatHandling->fAqPlaneOffset*GetForward()); } @@ -491,7 +502,11 @@ CBoat::ProcessControl(void) CVector propellerForce = propellerDepth * Multiply3x3(GetMatrix(), force*CVector(-steerSin, 0.0f, 0.0f)); ApplyMoveForce(propellerForce * CTimer::GetTimeStep()); ApplyTurnForce(propellerForce * CTimer::GetTimeStep(), propeller); +#ifdef FIX_BUGS + float rightForce = -steerSin * force * 0.75f/steerFactor * CTimer::GetTimeStep(); +#else float rightForce = -steerSin * force * 0.75f/steerFactor * Max(CTimer::GetTimeStep(), 0.01f); +#endif ApplyTurnForce(GetRight() * rightForce, GetUp()); } }else @@ -501,7 +516,12 @@ CBoat::ProcessControl(void) CVector right = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f)); float rightSpeed = DotProduct(m_vecMoveSpeed, right); float impulse = 0.1f*pHandling->fSuspensionBias * m_fMass * m_fVolumeUnderWater * rightSpeed * CTimer::GetTimeStep(); - ApplyMoveForce(right - impulse * 0.3f * CVector(-right.y, right.x, 0.0f)); +#ifdef FIX_BUGS + // Fix boat perf at high FPS: ensure both terms have a (correct) factor of timestep before doing subtraction + ApplyMoveForce(right * CTimer::GetTimeStepFix() - impulse * 0.3f * CVector(-right.y, right.x, 0.0f)); +#else + ApplyMoveForce(right - impulse * 0.3f * CVector(-right.y, right.x, 0.0f)); +#endif } if(GetStatus() == STATUS_PLAYER && CPad::GetPad(0)->GetHandBrake()){ @@ -519,25 +539,45 @@ CBoat::ProcessControl(void) m_vecMoveSpeed.y = Min(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MAX_Y-100.0f))*0.01f); // north m_vecMoveSpeed.y = Max(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MIN_Y+100.0f))*0.01f); // south + // Apply water resistance to linear movement if(!onLand && bBoatInWater && !bSeparateTurnForce) ApplyWaterResistance(); + // Apply water resistance to rotation if((GetModelIndex() != MI_SKIMMER || m_skimmerThingTimer == 0.0f) && !bSeparateTurnForce){ - // No idea what exactly is going on here besides drag in YZ +#ifdef FIX_BUGS + // Rockstar's attempts to make this framerate independent are totally wrong. + // Rules of thumb: + // - use Pow(x,time) if you multiply the result into the velocity + // - use x*time if you add the result into the velocity + // We have to disable one of these Pow() methods and then add our own correction at the end. + float fxfake = Pow(pBoatHandling->vecTurnRes.x, CTimer::GetDefaultTimeStep()); + float fy = Pow(pBoatHandling->vecTurnRes.y, CTimer::GetTimeStep()); + float fz = Pow(pBoatHandling->vecTurnRes.z, CTimer::GetTimeStep()); + m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space + float drag = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fxfake; + m_vecTurnSpeed.y *= fy; + m_vecTurnSpeed.z *= fz; + float forceUp = -(1.0f - drag) * m_vecTurnSpeed.x * m_fTurnMass; + m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world + CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); + ApplyTurnForce(forceUp*GetUp() * CTimer::GetTimeStepFix(), com + GetForward()); +#else float fx = Pow(pBoatHandling->vecTurnRes.x, CTimer::GetTimeStep()); float fy = Pow(pBoatHandling->vecTurnRes.y, CTimer::GetTimeStep()); float fz = Pow(pBoatHandling->vecTurnRes.z, CTimer::GetTimeStep()); m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space - // TODO: figure this out - float magic = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx; + float drag = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx; m_vecTurnSpeed.y *= fy; m_vecTurnSpeed.z *= fz; - float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass; + float forceUp = (drag - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass; m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); ApplyTurnForce(forceUp*GetUp(), com + GetForward()); +#endif } + m_nDeltaVolumeUnderWater = (m_fVolumeUnderWater-m_fPrevVolumeUnderWater)*10000; // Falling into water @@ -555,6 +595,9 @@ CBoat::ProcessControl(void) speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fBrakeBias; CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp); CVector splashImpulse = speed * m_fMass; +#ifdef FIX_BUGS + splashImpulse *= CTimer::GetTimeStepFix(); +#endif ApplyMoveForce(splashImpulse); ApplyTurnForce(splashImpulse, buoyancePoint); } @@ -893,26 +936,29 @@ CBoat::ApplyWaterResistance(void) // // We don't actually have to limit ourselves to a fixed time unit (like 1ms chunks), // instead we can raise the resistance to some power of time using Pow(). - float rrx = Pow(rx, 0.5f*CTimer::GetTimeStep()); // Why 0.5f? Taste? - float rry = Pow(ry, 0.5f*CTimer::GetTimeStep()); - float rrz = Pow(rz, 0.5f*CTimer::GetTimeStep()); + float rrx = Pow(rx, 0.5f*CTimer::GetTimeStep()); // Why 0.5f? Taste? + float rry = Pow(ry, 0.5f*CTimer::GetTimeStep()); + float rrz = Pow(rz, 0.5f*CTimer::GetTimeStep()); + float rryfake = Pow(ry, 0.5f*CTimer::GetDefaultTimeStep()); // Fudge factor needed for other equations to make sense at high FPS m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // convert velocities to boat-local space (y = boat forwards, x = sideways, z = up/down) m_vecMoveSpeed.x *= rrx; m_vecMoveSpeed.y *= rry; m_vecMoveSpeed.z *= rrz; - float force = (rry - 1.0f) * m_vecMoveSpeed.y * m_fMass; + float force = (rryfake - 1.0f) * m_vecMoveSpeed.y * m_fMass; m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed); // back to world space - // Is this for "flipping the boat over"? Seems to have almost zero effect normally? - ApplyTurnForce(force*GetForward(), -GetUp()); + // WTH is this for? + ApplyTurnForce(force*GetForward()*CTimer::GetTimeStepFix(), -GetUp()); // What the hell? Why arbitrarily compound in one more factor of rrz? - // This is framerate dependent! Bah! + // This is framerate dependent! Bah! I suspect it has very little effect. + /* if(m_vecMoveSpeed.z > 0.0f) m_vecMoveSpeed.z *= rrz; else m_vecMoveSpeed.z *= (1.0f - rrz)*0.5f + rrz; + */ #else // TODO: figure out how this works float resistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass; diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp index 08688a3c..ed1ab057 100644 --- a/src/vehicles/Floater.cpp +++ b/src/vehicles/Floater.cpp @@ -109,6 +109,17 @@ cBuoyancy::ProcessBuoyancyBoat(CVehicle *veh, float buoyancy, CVector *point, CV float volume = SimpleSumBuoyancyData(waterLevel, waterPosition); float upImpulse = volume * volDiv * buoyancy * CTimer::GetTimeStep(); CVector speed = veh->GetSpeed(Multiply3x3(veh->GetMatrix(), CVector(x, y, 0.0f))); +#ifdef FIX_BUGS + // "GetSpeed" seems to depend on framerate (bad). + // This ruins boat performance at high FPS. Approximate sequence of events: + // - "speed" goes tiny at high FPS + // - "damp" goes high as a result + // - high dampening reduces the buoyancy forces that keep the boat above the water + // - boats sit _slightly_ lower in water (you have to disable ALL waves to see this, it's a very small change) + // - all of boat handling performance changes because a different amount of the boat is underwater + // Finding this was a PITA! + speed /= CTimer::GetTimeStepFix(); +#endif float damp = 1.0f - DotProduct(speed, waterNormal)*veh->pHandling->fSuspensionDampingLevel; float finalImpulse = upImpulse*Max(damp, 0.0f); impulse->z += finalImpulse; -- 2.45.2 From 2d3f93e60e876083cb5c049c018ed8b3bd7b1915 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sat, 24 Jul 2021 22:38:33 +1000 Subject: [PATCH 21/29] Fix car fake/cruise top gear SFX at high FPS. --- src/audio/AudioLogic.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 6c53eb10..34d58cb2 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1977,11 +1977,18 @@ PlayCruising: SampleManager.StopChannel(CHANNEL_PLAYER_VEHICLE_ENGINE); if (isMoped || accelerateState >= 150 && wheelsOnGround && brakeState <= 0 && !params.m_pVehicle->bIsHandbrakeOn && !lostTraction && currentGear >= params.m_pTransmission->nNumberOfGears - 1) { - if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { - if (nCruising < 800) - ++nCruising; - } else if (nCruising > 3) { - --nCruising; + +#ifdef FIX_BUGS + // Stop the fake top ("cruise") gear rising in pitch too quickly at high FPS. + if (CTimer::GetLogicalFramesPassed()) +#endif + { + if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { + if (nCruising < 800) + ++nCruising; + } else if (nCruising > 3) { + --nCruising; + } } freq = 27 * nCruising + freqModifier + 22050; if (engineSoundType == SFX_BANK_TRUCK) -- 2.45.2 From 65b12c21044b2637cfabac3b5b56441653f327cd Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Thu, 29 Jul 2021 22:41:13 +1000 Subject: [PATCH 22/29] Fix world-rain and lightning spam at high FPS --- src/renderer/Weather.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/renderer/Weather.cpp b/src/renderer/Weather.cpp index 2926d280..cae2e677 100644 --- a/src/renderer/Weather.cpp +++ b/src/renderer/Weather.cpp @@ -169,7 +169,11 @@ void CWeather::Update(void) LightningFlash = false; LightningBurst = false; } +#ifdef FIX_BUGS + else if (CTimer::GetLogicalFramesPassed()) { +#else else{ +#endif if (LightningBurst) { if ((CGeneral::GetRandomNumber() & 255) >= 32) { // 0.875 probability @@ -303,7 +307,11 @@ void CWeather::Update(void) TrafficLightBrightness = Max(Foggyness, TrafficLightBrightness); TrafficLightBrightness = Max(Rain, TrafficLightBrightness); +#ifdef FIX_BUGS + if (CTimer::GetLogicalFramesPassed()) AddRain(); +#else AddRain(); +#endif if ((NewWeatherType == WEATHER_SUNNY || NewWeatherType == WEATHER_EXTRA_SUNNY) && !CGame::IsInInterior() && !CCutsceneMgr::IsRunning() && (CTimer::GetFrameCounter() & 7) == 0) { -- 2.45.2 From 606977688e4a7dc7da5dc5ddae5f1d5a4b19d40f Mon Sep 17 00:00:00 2001 From: Magnus Larsen Date: Sat, 10 Jul 2021 10:48:00 -0700 Subject: [PATCH 23/29] Fix debug camera being framerate dependant (cherry-pick nopey) --- src/core/Cam.cpp | 24 +++++++++++++++--------- src/extras/debugmenu.cpp | 2 ++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index cafbd340..7428e897 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -3895,10 +3895,17 @@ CCam::Process_Debug(const CVector&, float, float, float) if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); else if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f); +#ifdef FIX_BUGS + // Time factor makes debug camera usable even at 400FPS + const float Time = CTimer::GetTimeStepNonClipped(); +#else + const float Time = 1.0f; +#endif + if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W')) - Speed += 0.1f; + Speed += 0.1f * Time; else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S')) - Speed -= 0.1f; + Speed -= 0.1f * Time; else Speed = 0.0f; if(Speed > 70.0f) Speed = 70.0f; @@ -3906,9 +3913,9 @@ CCam::Process_Debug(const CVector&, float, float, float) if(KEYDOWN(rsRIGHT) || KEYDOWN('D')) - PanSpeedX += 0.1f; + PanSpeedX += 0.1f * Time; else if(KEYDOWN(rsLEFT) || KEYDOWN('A')) - PanSpeedX -= 0.1f; + PanSpeedX -= 0.1f * Time; else PanSpeedX = 0.0f; if(PanSpeedX > 70.0f) PanSpeedX = 70.0f; @@ -3916,23 +3923,22 @@ CCam::Process_Debug(const CVector&, float, float, float) if(KEYDOWN(rsUP)) - PanSpeedY += 0.1f; + PanSpeedY += 0.1f * Time; else if(KEYDOWN(rsDOWN)) - PanSpeedY -= 0.1f; + PanSpeedY -= 0.1f * Time; else PanSpeedY = 0.0f; if(PanSpeedY > 70.0f) PanSpeedY = 70.0f; if(PanSpeedY < -70.0f) PanSpeedY = -70.0f; - Front = TargetCoors - Source; Front.Normalise(); - Source = Source + Front*Speed; + Source = Source + Front * Speed * Time; Up = CVector{ 0.0f, 0.0f, 1.0f }; CVector Right = CrossProduct(Front, Up); Up = CrossProduct(Right, Front); - Source = Source + Up*PanSpeedY + Right*PanSpeedX; + Source = Source + Up * PanSpeedY * Time + Right * PanSpeedX * Time; if(Source.z < -450.0f) Source.z = -450.0f; diff --git a/src/extras/debugmenu.cpp b/src/extras/debugmenu.cpp index 4b21feb9..078f7a96 100644 --- a/src/extras/debugmenu.cpp +++ b/src/extras/debugmenu.cpp @@ -1020,6 +1020,8 @@ DebugMenuProcess(void) menuOn = !menuOn; if (KEYJUSTDOWN(rsF4)) FrontEndMenuManager.m_PrefsFrameLimiter = !FrontEndMenuManager.m_PrefsFrameLimiter; + if(CTRLJUSTDOWN('M')) menuOn = !menuOn; + if(KEYJUSTDOWN(rsESC)) menuOn = false; if(!menuOn) return; -- 2.45.2 From 07363047952a65d413c3771ba011aecc2f36b2c7 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Thu, 29 Jul 2021 23:07:54 +1000 Subject: [PATCH 24/29] IFDEF tidyup: remove FIX_BUGS inside IMPROVED_CAMERA --- src/core/Cam.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 7428e897..b9cee255 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -3895,17 +3895,12 @@ CCam::Process_Debug(const CVector&, float, float, float) if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); else if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f); -#ifdef FIX_BUGS - // Time factor makes debug camera usable even at 400FPS - const float Time = CTimer::GetTimeStepNonClipped(); -#else - const float Time = 1.0f; -#endif + const float TimeStep = CTimer::GetTimeStepNonClipped(); if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W')) - Speed += 0.1f * Time; + Speed += 0.1f * TimeStep; else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S')) - Speed -= 0.1f * Time; + Speed -= 0.1f * TimeStep; else Speed = 0.0f; if(Speed > 70.0f) Speed = 70.0f; @@ -3913,9 +3908,9 @@ CCam::Process_Debug(const CVector&, float, float, float) if(KEYDOWN(rsRIGHT) || KEYDOWN('D')) - PanSpeedX += 0.1f * Time; + PanSpeedX += 0.1f * TimeStep; else if(KEYDOWN(rsLEFT) || KEYDOWN('A')) - PanSpeedX -= 0.1f * Time; + PanSpeedX -= 0.1f * TimeStep; else PanSpeedX = 0.0f; if(PanSpeedX > 70.0f) PanSpeedX = 70.0f; @@ -3923,9 +3918,9 @@ CCam::Process_Debug(const CVector&, float, float, float) if(KEYDOWN(rsUP)) - PanSpeedY += 0.1f * Time; + PanSpeedY += 0.1f * TimeStep; else if(KEYDOWN(rsDOWN)) - PanSpeedY -= 0.1f * Time; + PanSpeedY -= 0.1f * TimeStep; else PanSpeedY = 0.0f; if(PanSpeedY > 70.0f) PanSpeedY = 70.0f; @@ -3933,12 +3928,12 @@ CCam::Process_Debug(const CVector&, float, float, float) Front = TargetCoors - Source; Front.Normalise(); - Source = Source + Front * Speed * Time; + Source = Source + Front * Speed * TimeStep; Up = CVector{ 0.0f, 0.0f, 1.0f }; CVector Right = CrossProduct(Front, Up); Up = CrossProduct(Right, Front); - Source = Source + Up * PanSpeedY * Time + Right * PanSpeedX * Time; + Source = Source + Up * PanSpeedY * TimeStep + Right * PanSpeedX * TimeStep; if(Source.z < -450.0f) Source.z = -450.0f; @@ -3961,11 +3956,7 @@ CCam::Process_Debug(const CVector&, float, float, float) Source.y += 1.0f; GetVectorsReadyForRW(); -#ifdef FIX_BUGS CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_CAMERA); -#else - CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_CAMERA; -#endif if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn) CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source, -- 2.45.2 From 861da4b3676e5013033aee8d804cf9410dba4f16 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 1 Aug 2021 15:01:52 +1000 Subject: [PATCH 25/29] Revert "Fix car fake/cruise top gear SFX at high FPS.", to make merging main miami branch easier. Will-reimplement This reverts commit 2d3f93e60e876083cb5c049c018ed8b3bd7b1915. --- src/audio/AudioLogic.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 34d58cb2..6c53eb10 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1977,18 +1977,11 @@ PlayCruising: SampleManager.StopChannel(CHANNEL_PLAYER_VEHICLE_ENGINE); if (isMoped || accelerateState >= 150 && wheelsOnGround && brakeState <= 0 && !params.m_pVehicle->bIsHandbrakeOn && !lostTraction && currentGear >= params.m_pTransmission->nNumberOfGears - 1) { - -#ifdef FIX_BUGS - // Stop the fake top ("cruise") gear rising in pitch too quickly at high FPS. - if (CTimer::GetLogicalFramesPassed()) -#endif - { - if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { - if (nCruising < 800) - ++nCruising; - } else if (nCruising > 3) { - --nCruising; - } + if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { + if (nCruising < 800) + ++nCruising; + } else if (nCruising > 3) { + --nCruising; } freq = 27 * nCruising + freqModifier + 22050; if (engineSoundType == SFX_BANK_TRUCK) -- 2.45.2 From 5d19085dfe330602d6d66573b5ca619ccb210a56 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 1 Aug 2021 15:14:32 +1000 Subject: [PATCH 26/29] Fix car fake/cruise top gear SFX at high FPS. Re-implements 2d3f93e60e876083cb5c049c018ed8b3bd7b1915 --- src/audio/AudioLogic.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 56463be0..7b686654 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -2347,11 +2347,17 @@ PlayCruising: SampleManager.StopChannel(CHANNEL_PLAYER_VEHICLE_ENGINE); if (isMoped || accelerateState >= 150 && wheelsOnGround && brakeState <= 0 && !params.m_pVehicle->bIsHandbrakeOn && !lostTraction && currentGear >= params.m_pTransmission->nNumberOfGears - 1) { - if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { - if (nCruising < 800) - ++nCruising; - } else if (nCruising > 3) { - --nCruising; +#ifdef FIX_BUGS + // Prevent the fake top gear ("cruise gear") rising in pitch too quickly at high FPS. + if (CTimer::GetLogicalFramesPassed()) +#endif + { + if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) { + if (nCruising < 800) + ++nCruising; + } else if (nCruising > 3) { + --nCruising; + } } freq = 27 * nCruising + freqModifier + 22050; if (engineSoundType == SFX_BANK_TRUCK) -- 2.45.2 From 9282db1e8f12a8f3a10be48da353a1a5c2854f93 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 1 Aug 2021 15:18:54 +1000 Subject: [PATCH 27/29] Fix AI-driver horn SFX length at high FPS --- src/vehicles/Automobile.cpp | 6 ++++++ src/vehicles/Bike.cpp | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 0a577c0c..44b596a1 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -5740,8 +5740,14 @@ CAutomobile::ShowAllComps(void) void CAutomobile::ReduceHornCounter(void) { +#ifdef FIX_BUGS + // Make horns last longer (only used by AI drivers?) + if(m_nCarHornTimer != 0 && CTimer::GetLogicalFramesPassed()) + m_nCarHornTimer--; +#else if(m_nCarHornTimer != 0) m_nCarHornTimer--; +#endif } void diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp index 6af3e131..474797e8 100644 --- a/src/vehicles/Bike.cpp +++ b/src/vehicles/Bike.cpp @@ -2941,8 +2941,14 @@ CBike::SetupModelNodes(void) void CBike::ReduceHornCounter(void) { - if(m_nCarHornTimer != 0) + #ifdef FIX_BUGS + // Make horns last longer (only used by AI drivers?) + if(m_nCarHornTimer != 0 && CTimer::GetLogicalFramesPassed()) m_nCarHornTimer--; + #else + if(m_nCarHornTimer != 0) + m_nCarHornTimer--; + #endif } #ifdef COMPATIBLE_SAVES -- 2.45.2 From 882a977c66db02c5a772aef680e8cf3a22057de9 Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 1 Aug 2021 15:58:42 +1000 Subject: [PATCH 28/29] Fix toggling siren at high FPS --- src/vehicles/Automobile.cpp | 45 +++++++++++++++++++++++++++++++++---- src/vehicles/Vehicle.cpp | 3 +++ src/vehicles/Vehicle.h | 3 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 44b596a1..159b9342 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -235,6 +235,12 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) bExplosionProof = true; bBulletProof = true; } + +#ifdef FIX_BUGS + // Probably not neccesary to zero these + m_nCarHornTimer = 0; + m_fCarHornTimeButtonLastHit = 0.0f; +#endif } void @@ -1366,18 +1372,49 @@ CAutomobile::ProcessControl(void) ReduceHornCounter(); }else{ if(UsesSiren()){ +#ifdef FIX_BUGS + // Allow sirens to be toggled at high FPS + const float minPressTime = 100.0f; // milli-seconds + bool currentButtonState = Pads[0].bHornHistory[(CPad::HORNHISTORY_SIZE + Pads[0].iCurrHornHistory - 0) % CPad::HORNHISTORY_SIZE]; + bool lastButtonState = Pads[0].bHornHistory[(CPad::HORNHISTORY_SIZE + Pads[0].iCurrHornHistory - 1) % CPad::HORNHISTORY_SIZE]; // Extra addition of CPad::HORNHISTORY_SIZE avoids modulo of negative numbers + + if (currentButtonState && !lastButtonState) + { + // Horn button has just been hit + m_fCarHornTimeButtonLastHit = CTimer::GetTimeInMilliseconds(); + } + else if (currentButtonState && lastButtonState) + { + // Horn button is being held down + if (CTimer::GetTimeInMilliseconds() - m_fCarHornTimeButtonLastHit >= minPressTime) + m_nCarHornTimer = 1; // enable horn + } + else if (!currentButtonState && lastButtonState) + { + // Horn button has just been released + m_nCarHornTimer = 0; + if (CTimer::GetTimeInMilliseconds() - m_fCarHornTimeButtonLastHit < minPressTime) + m_bSirenOrAlarm = !m_bSirenOrAlarm; // Toggle siren-like-feature + } + else + { + // Nothing pressed + m_nCarHornTimer = 0; // Should not be neccesary, but may as well keep in + } +#else if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){ - if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] && - Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5]) + if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % CPad::HORNHISTORY_SIZE] && + Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % CPad::HORNHISTORY_SIZE]) m_nCarHornTimer = 1; else m_nCarHornTimer = 0; - }else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] && - !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % 5]){ + }else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % CPad::HORNHISTORY_SIZE] && + !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % CPad::HORNHISTORY_SIZE]){ m_nCarHornTimer = 0; m_bSirenOrAlarm = !m_bSirenOrAlarm; }else m_nCarHornTimer = 0; +#endif }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3 && !carHasNitro){ if(!IsAlarmOn()){ if(Pads[0].GetHorn()) diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 6dcca5e7..84ee5628 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -126,6 +126,9 @@ CVehicle::CVehicle(uint8 CreatedBy) m_nCarHornTimer = 0; m_nCarHornPattern = 0; m_nCarHornDelay = 0; +#ifdef FIX_BUGS + m_fCarHornTimeButtonLastHit = 0.0f; +#endif bPartOfConvoy = false; bHeliMinimumTilt = false; bAudioChangingGear = false; diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 31b52138..8aac81da 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -273,6 +273,9 @@ public: uint8 m_nCarHornPattern; bool m_bSirenOrAlarm; uint8 m_nCarHornDelay; +#ifdef FIX_BUGS + float m_fCarHornTimeButtonLastHit; +#endif int8 m_comedyControlState; CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car float m_fSteerInput; -- 2.45.2 From 8cabe529bf2f6f1d116c2d1e80e11de2dedefabe Mon Sep 17 00:00:00 2001 From: Veyrdite Date: Sun, 1 Aug 2021 16:09:04 +1000 Subject: [PATCH 29/29] Fix debug menu not opening (bug introduced in 606977688e4a7dc7da5dc5ddae5f1d5a4b19d40f) --- src/extras/debugmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extras/debugmenu.cpp b/src/extras/debugmenu.cpp index 078f7a96..a1f8af4e 100644 --- a/src/extras/debugmenu.cpp +++ b/src/extras/debugmenu.cpp @@ -1020,8 +1020,8 @@ DebugMenuProcess(void) menuOn = !menuOn; if (KEYJUSTDOWN(rsF4)) FrontEndMenuManager.m_PrefsFrameLimiter = !FrontEndMenuManager.m_PrefsFrameLimiter; - if(CTRLJUSTDOWN('M')) menuOn = !menuOn; - if(KEYJUSTDOWN(rsESC)) menuOn = false; + if(KEYJUSTDOWN(rsESC)) + menuOn = false; if(!menuOn) return; -- 2.45.2