diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index 2d02755..c59a109 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -1464,6 +1464,12 @@ namespace VariableResets namespace LightbeamFix { + static CVehicle* currentHeadLightBeamVehicle; + void SetCurrentVehicle( CVehicle* vehicle ) + { + currentHeadLightBeamVehicle = vehicle; + } + template class RenderStateWrapper { @@ -1478,10 +1484,21 @@ namespace LightbeamFix } static inline const auto pPushState = &PushState; - static void PopState( RwRenderState state, void* ) + static void PopState( RwRenderState state, void* value ) { assert( State == state ); - RwRenderStateSet( state, SavedState ); + + void* valueToRestore = SavedState; + if constexpr ( State == rwRENDERSTATECULLMODE ) + { + assert( currentHeadLightBeamVehicle != nullptr ); + if ( currentHeadLightBeamVehicle != nullptr && currentHeadLightBeamVehicle->IgnoresLightbeamFix() ) + { + valueToRestore = value; + } + } + + RwRenderStateSet( state, valueToRestore ); // Restore states R* did not restore after changing them if constexpr ( State == rwRENDERSTATEDESTBLEND ) @@ -2349,6 +2366,7 @@ BOOL InjectDelayedPatches_10() const HMODULE modloaderModule = moduleList.Get( L"modloader" ); ReadRotorFixExceptions(wcModulePath); + ReadLightbeamFixExceptions(wcModulePath); const bool bHookDoubleRwheels = ReadDoubleRearWheels(wcModulePath); const bool bHasDebugMenu = DebugMenuLoad(); @@ -2668,6 +2686,14 @@ BOOL InjectDelayedPatches_10() Patch( 0x590042 + 2, &currDisplayedSplash_ForLastSplash ); } + // Lightbeam fix debug menu + if ( bHasDebugMenu ) + { + static const char * const str[] = { "Off", "Default", "On" }; + DebugMenuEntry *e = DebugMenuAddVar( "SilentPatch", "Lightbeam fix", &CVehicle::ms_lightbeamFixOverride, nullptr, 1, -1, 1, str); + DebugMenuEntrySetWrap(e, true); + } + #ifndef NDEBUG if ( const int QPCDays = GetPrivateProfileIntW(L"Debug", L"AddDaysToQPC", 0, wcModulePath); QPCDays != 0 ) { @@ -3189,6 +3215,11 @@ void Patch_SA_10() { using namespace LightbeamFix; + ReadCall( 0x6A2EDA, CVehicle::orgDoHeadLightBeam ); + InjectHook( 0x6A2EDA, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj ); + InjectHook( 0x6A2EF2, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj ); + InjectHook( 0x6BDE80, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj ); + Patch( 0x6E0F37 + 2, &RenderStateWrapper::PushStatePPtr ); Patch( 0x6E0F63 + 1, &RenderStateWrapper::PushStatePPtr ); Patch( 0x6E0F6F + 2, &RenderStateWrapper::PushStatePPtr ); @@ -3207,6 +3238,8 @@ void Patch_SA_10() Patch( 0x6E1406 + 2, &RenderStateWrapper::PopStatePPtr ); Patch( 0x6E1413 + 2, &RenderStateWrapper::PopStatePPtr ); Patch( 0x6E141F + 1, &RenderStateWrapper::PopStatePPtr ); + + // Debug override registered in delayed patches } // PS2 SUN!!!!!!!!!!!!!!!!! diff --git a/SilentPatchSA/VehicleSA.cpp b/SilentPatchSA/VehicleSA.cpp index 4f06653..f06a837 100644 --- a/SilentPatchSA/VehicleSA.cpp +++ b/SilentPatchSA/VehicleSA.cpp @@ -41,6 +41,7 @@ namespace SVF { // Internal SP use only, formerly "rotor exceptions" // Unreachable from RegisterSpecialVehicleFeature NO_ROTOR_FADE, + NO_LIGHTBEAM_BFC_FIX, FORCE_DOUBLE_RWHEELS_OFF, FORCE_DOUBLE_RWHEELS_ON, }; @@ -340,6 +341,20 @@ void ReadRotorFixExceptions(const wchar_t* pPath) } } +void ReadLightbeamFixExceptions(const wchar_t* pPath) +{ + constexpr size_t SCRATCH_PAD_SIZE = 32767; + WideDelimStringReader reader( SCRATCH_PAD_SIZE ); + + GetPrivateProfileSectionW( L"LightbeamFixExceptions", reader.GetBuffer(), reader.GetSize(), pPath ); + while ( const wchar_t* str = reader.GetString() ) + { + int32_t toList = wcstol( str, nullptr, 0 ); + if ( toList > 0 ) + SVF::RegisterFeature( toList, SVF::Feature::NO_LIGHTBEAM_BFC_FIX ); + } +} + bool CVehicle::HasFirelaLadder() const { return SVF::ModelHasFeature( m_nModelIndex.Get(), SVF::Feature::FIRELA_LADDER ); @@ -370,6 +385,23 @@ void CVehicle::SetComponentAtomicAlpha(RpAtomic* pAtomic, int nAlpha) } ); } +bool CVehicle::IgnoresLightbeamFix() const +{ + if ( ms_lightbeamFixOverride != 0 ) + { + return ms_lightbeamFixOverride < 0; + } + return SVF::ModelHasFeature( m_nModelIndex.Get(), SVF::Feature::NO_LIGHTBEAM_BFC_FIX ); +} + + +void CVehicle::DoHeadLightBeam_LightBeamFixSaveObj(int type, CMatrix& m, bool right) +{ + LightbeamFix::SetCurrentVehicle( this ); + DoHeadLightBeam( type, m, right ); + LightbeamFix::SetCurrentVehicle( nullptr ); +} + bool CVehicle::CustomCarPlate_TextureCreate(CVehicleModelInfo* pModelInfo) { char PlateText[CVehicleModelInfo::PLATE_TEXT_LEN+1]; diff --git a/SilentPatchSA/VehicleSA.h b/SilentPatchSA/VehicleSA.h index b22ffd7..d38fa04 100644 --- a/SilentPatchSA/VehicleSA.h +++ b/SilentPatchSA/VehicleSA.h @@ -268,6 +268,18 @@ public: static void SetComponentRotation( RwFrame* component, eRotAxis axis, float angle, bool absolute = true ); static void SetComponentAtomicAlpha(RpAtomic* pAtomic, int nAlpha); + + static inline void (CVehicle::*orgDoHeadLightBeam)( int type, CMatrix& m, bool right ); + + static inline int8_t ms_lightbeamFixOverride = 0; // 0 - normal, 1 - always on, -1 - always off + bool IgnoresLightbeamFix() const; + + void DoHeadLightBeam( int type, CMatrix& m, bool right ) + { + std::invoke( orgDoHeadLightBeam, this, type, m, right ); + } + + void DoHeadLightBeam_LightBeamFixSaveObj( int type, CMatrix& m, bool right ); }; class NOVMT CAutomobile : public CVehicle @@ -385,6 +397,12 @@ public: }; void ReadRotorFixExceptions(const wchar_t* pPath); +void ReadLightbeamFixExceptions(const wchar_t* pPath); + +namespace LightbeamFix +{ + void SetCurrentVehicle( CVehicle* vehicle ); +} static_assert(sizeof(CDoor) == 0x18, "Wrong size: CDoor"); static_assert(sizeof(CBouncingPanel) == 0x20, "Wrong size: CBouncingPanel");