From d6caed016e5bacca33ab68d11a4dce7bef810d06 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 18 Mar 2024 23:56:40 +0100 Subject: [PATCH] Fix renderlights loaded from savegames aliasing other lights Some entities wrote the handle from gameRenderWorld->AddLightDef() into savegames and reused it after restoring it. That's a bad idea, because at that point the handle most likely belongs to something else (likely some idLight). The most visible issue this can create is that the flashlight may not work correctly after loading a savegame with flashlight on, when it happens to alias a light that's updated each frame to (mostly) being off.. The correct way to handle this (THAT FOR SOME REASON WAS ALREADY IMPLEMENTED IN D3XP BUT NOT THE BASE GAME - WHY?!) is to get a fresh handle with AddLightDef() when restoring a savegame - unless the handle was -1, which means that the light didn't exist when saving. fixes #495 --- game/Moveable.cpp | 9 +++++++++ game/Projectile.cpp | 5 +++++ game/Weapon.cpp | 14 +++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/game/Moveable.cpp b/game/Moveable.cpp index ce7c949..e5e58cb 100644 --- a/game/Moveable.cpp +++ b/game/Moveable.cpp @@ -919,6 +919,15 @@ void idExplodingBarrel::Restore( idRestoreGame *savefile ) { //REV GRAB savefile->ReadBool( isStable ); //REV GRAB + + // DG: enforce getting fresh handle, else this may be tied to an unrelated light! + if ( lightDefHandle != -1 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &light ); + } + // DG: same for render entity + if ( particleModelDefHandle != -1 ) { + particleModelDefHandle = gameRenderWorld->AddEntityDef( &particleRenderEntity ); + } } /* diff --git a/game/Projectile.cpp b/game/Projectile.cpp index 51cddc0..03abf0d 100644 --- a/game/Projectile.cpp +++ b/game/Projectile.cpp @@ -174,6 +174,11 @@ void idProjectile::Restore( idRestoreGame *savefile ) { savefile->ReadRenderLight( renderLight ); savefile->ReadInt( (int &)lightDefHandle ); + // DG: enforce getting fresh handle, else this may be tied to an unrelated light! + if ( lightDefHandle != -1 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); + } + savefile->ReadVec3( lightOffset ); savefile->ReadInt( lightStartTime ); savefile->ReadInt( lightEndTime ); diff --git a/game/Weapon.cpp b/game/Weapon.cpp index 5521b57..8b2d683 100644 --- a/game/Weapon.cpp +++ b/game/Weapon.cpp @@ -662,13 +662,22 @@ void idWeapon::Restore( idRestoreGame *savefile ) { /* savefile->ReadInt( guiLightHandle ); savefile->ReadRenderLight( guiLight ); - + // DG: we need to get a fresh handle, otherwise this will be tied to a completely unrelated light! + if ( guiLightHandle != -1 ) { + guiLightHandle = gameRenderWorld->AddLightDef( &guiLight ); + } savefile->ReadInt( muzzleFlashHandle ); savefile->ReadRenderLight( muzzleFlash ); + if ( muzzleFlashHandle != -1 ) { // DG: enforce getting fresh handle + muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash ); + } */ savefile->ReadInt( worldMuzzleFlashHandle ); savefile->ReadRenderLight( worldMuzzleFlash ); + if ( worldMuzzleFlashHandle != -1 ) { // DG: enforce getting fresh handle + worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); + } savefile->ReadVec3( flashColor ); savefile->ReadInt( muzzleFlashEnd ); @@ -765,6 +774,9 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadInt( nozzleGlowHandle ); savefile->ReadRenderLight( nozzleGlow ); + if ( nozzleGlowHandle != -1 ) { // DG: enforce getting fresh handle + nozzleGlowHandle = gameRenderWorld->AddLightDef( &nozzleGlow ); + } savefile->ReadVec3( nozzleGlowColor ); savefile->ReadMaterial( nozzleGlowShader );