diff --git a/SilentPatchSA/GeneralSA.cpp b/SilentPatchSA/GeneralSA.cpp index 762da4c..cedbf33 100644 --- a/SilentPatchSA/GeneralSA.cpp +++ b/SilentPatchSA/GeneralSA.cpp @@ -3,11 +3,15 @@ #include "PedSA.h" #include "ModelInfoSA.h" +#include "PoolsSA.h" // Wrappers static void* EntityRender = AddressByVersion(0x534310, 0x5347B0, 0x545B30); WRAPPER void CEntity::Render() { VARJMP(EntityRender); } +static void* varEntityIsVisible = AddressByVersion( 0x536BC0, 0, 0 ); // TODO +WRAPPER bool CEntity::IsVisible() { VARJMP(varEntityIsVisible); } + static void* varInvertRaster = AddressByVersion(0x705660, 0x705E90, 0x7497A0); WRAPPER void CShadowCamera::InvertRaster() { VARJMP(varInvertRaster); } @@ -53,7 +57,7 @@ void CObject::Render() std::pair materialRestoreData[16]; const int32_t carPartModelIndex = FLAUtils::GetExtendedID( &m_wCarPartModelIndex ); - if ( carPartModelIndex != -1 && m_nObjectType == 3 && bObjectFlag7 && RwObjectGetType(m_pRwObject) == rpATOMIC ) + if ( carPartModelIndex != -1 && m_objectCreatedBy == TEMP_OBJECT && bObjectFlag7 && RwObjectGetType(m_pRwObject) == rpATOMIC ) { auto* pData = materialRestoreData; @@ -87,6 +91,45 @@ void CObject::Render() } } +extern void (*WorldRemove)(CEntity*); +void CObject::TryToFreeUpTempObjects_SilentPatch( int numObjects ) +{ + int numProcessed, numFreed; + std::tie( numProcessed, numFreed ) = TryOrFreeUpTempObjects( numObjects, false ); + if ( numProcessed >= numObjects && numObjects > numFreed ) + { + TryOrFreeUpTempObjects( numObjects - numFreed, true ); + } +} + +std::tuple CObject::TryOrFreeUpTempObjects( int numObjects, bool force ) +{ + int numProcessed = 0, numFreed = 0; + + auto& pool = CPools::GetObjectPool(); + for ( auto& obj : pool ) + { + if ( numFreed >= numObjects ) break; + + CObject* const objPtr = &obj; + if ( pool.IsValidPtr( objPtr ) ) + { + if ( objPtr->m_objectCreatedBy == TEMP_OBJECT ) + { + numProcessed++; + if ( force || !objPtr->IsVisible() ) + { + numFreed++; + WorldRemove( objPtr ); + delete objPtr; + } + } + } + } + + return std::make_tuple( numProcessed, numFreed ); +} + RwCamera* CShadowCamera::Update(CEntity* pEntity) { RwRGBA ClearColour = { 255, 255, 255, 0 }; diff --git a/SilentPatchSA/GeneralSA.h b/SilentPatchSA/GeneralSA.h index cd35096..fde3d95 100644 --- a/SilentPatchSA/GeneralSA.h +++ b/SilentPatchSA/GeneralSA.h @@ -180,9 +180,7 @@ public: //********* END CEntityInfo ************// public: - void UpdateRW(); - void RegisterReference(CEntity** pAddress); - void CleanUpOldReference(CEntity** pAddress); + bool IsVisible(); }; class NOVMT CPhysical : public CEntity @@ -263,11 +261,19 @@ private: BYTE pad3a[4]; // 0x134 }; +enum // m_objectCreatedBy +{ + GAME_OBJECT = 1, + MISSION_OBJECT = 2, + TEMP_OBJECT = 3, + MISSION_BRAIN_OBJECT = 6, +}; + class NOVMT CObject : public CPhysical { public: void* m_pObjectList; - unsigned char m_nObjectType; + uint8_t m_objectCreatedBy; __int8 field_13D; __int16 field_13E; bool bObjectFlag0 : 1; @@ -334,6 +340,9 @@ public: { CObject::Render(); } virtual void Render() override; + + static void TryToFreeUpTempObjects_SilentPatch( int numObjects ); + static std::tuple TryOrFreeUpTempObjects( int numObjects, bool force ); }; class CZoneInfo diff --git a/SilentPatchSA/PoolsSA.cpp b/SilentPatchSA/PoolsSA.cpp new file mode 100644 index 0000000..17f4c27 --- /dev/null +++ b/SilentPatchSA/PoolsSA.cpp @@ -0,0 +1,4 @@ +#include "StdAfxSA.h" +#include "PoolsSA.h" + +CObjectPool*& CPools::ms_pObjectPool = **AddressByVersion(0x5A18B2 + 2, 0, 0); // TODO \ No newline at end of file diff --git a/SilentPatchSA/PoolsSA.h b/SilentPatchSA/PoolsSA.h new file mode 100644 index 0000000..7774e37 --- /dev/null +++ b/SilentPatchSA/PoolsSA.h @@ -0,0 +1,106 @@ +#ifndef __POOLS +#define __POOLS + +#include +#include + +template +class CPool +{ +public: + typedef T ReturnType; + typedef uint8_t StorageType[sizeof(U)]; + +private: + StorageType* m_pSlots; + union tSlotInfos + { + struct + { + unsigned char m_uID : 7; + bool m_bFree : 1; + } a; + signed char b; + }* m_pSlotInfos; + int m_nNumSlots; + int m_nFirstFree; + bool m_bOwnsAllocations; + bool m_bDealWithNoMemory; + +public: + ReturnType* GetSlot( int32_t index ) + { + return !m_pSlotInfos[index].a.m_bFree ? reinterpret_cast(&m_pSlots[index]) : nullptr; + } + + ReturnType* GetAt( int32_t index ) + { + const int ID = index >> 8; + return m_pSlotInfos[ID].b == (index && 0xFF) ? reinterpret_cast(&m_pSlots[ID]) : nullptr; + } + + static size_t GetStorageSize() { return sizeof(StorageType); } + int GetSize() const { return m_nNumSlots; } + int GetFreeIndex() const { return m_nFirstFree; } + bool GetIsFree( int32_t index ) const { return m_pSlotInfos[index].a.m_bFree; } + + bool IsValidPtr( T* ptr ) const + { + const ptrdiff_t index = reinterpret_cast(ptr) - &m_pSlots[0]; + if( index < 0 || index >= m_nNumSlots ) + return false; + + return !GetIsFree( index ); + } + + class iterator : public std::iterator + { + public: + iterator() : m_ptr(nullptr) + { + } + + explicit iterator( T* ptr ) : m_ptr( reinterpret_cast(ptr) ) + { + } + + reference operator* () const { return *reinterpret_cast(m_ptr); } + pointer operator->() const { return reinterpret_cast(m_ptr); } + + iterator& operator ++ () { ++m_ptr; return *this; } + bool operator == ( const iterator& rhs ) const { return m_ptr == rhs.m_ptr; } + bool operator != ( const iterator& rhs ) const { return m_ptr != rhs.m_ptr; } + + private: + StorageType* m_ptr; + }; + + iterator begin() + { + return iterator( reinterpret_cast(&m_pSlots[0]) ); + } + + iterator end() + { + return iterator( reinterpret_cast(&m_pSlots[m_nNumSlots]) ); + } + +}; + +// Type definitions for specific pool types +#include "General.h" + +typedef CPool CObjectPool; + +class CPools +{ +private: + static CObjectPool*& ms_pObjectPool; + +public: + static CObjectPool& GetObjectPool() { return *ms_pObjectPool; } +}; + +static_assert(sizeof(CPool) == 0x14, "Wrong size: CPool"); + +#endif \ No newline at end of file diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index 493cbbe..be14f57 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -3443,6 +3443,10 @@ void Patch_SA_10() // Stop BF Injection/Bandito/Hotknife rotating engine components when engine is off Patch(0x6AC2BE + 2, &CAutomobile::ms_engineCompSpeed); Patch(0x6ACB91 + 2, &CAutomobile::ms_engineCompSpeed); + + + // Make freeing temp objects more aggressive to fix vending crash + InjectHook( 0x5A1840, CObject::TryToFreeUpTempObjects_SilentPatch, PATCH_JUMP ); } void Patch_SA_11() diff --git a/SilentPatchSA/SilentPatchSA.vcxproj b/SilentPatchSA/SilentPatchSA.vcxproj index 2daf66f..3f4d516 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj +++ b/SilentPatchSA/SilentPatchSA.vcxproj @@ -138,6 +138,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + @@ -185,6 +186,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + diff --git a/SilentPatchSA/SilentPatchSA.vcxproj.filters b/SilentPatchSA/SilentPatchSA.vcxproj.filters index 7bee1c6..343a80c 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj.filters +++ b/SilentPatchSA/SilentPatchSA.vcxproj.filters @@ -66,6 +66,9 @@ Source Files + + Source Files + @@ -146,6 +149,9 @@ Header Files + + Header Files +