From 2b592605ab043be56b5bbbf1ac06f223400dd2ef Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 6 Jul 2019 12:27:21 +0200 Subject: [PATCH] misc classes finished --- src/References.cpp | 43 ++++++++ src/References.h | 3 + src/SurfaceTable.cpp | 53 ++++++++++ src/SurfaceTable.h | 1 + src/Zones.cpp | 225 +++++++++++++++++++++++++++++++++++++++- src/Zones.h | 5 +- src/config.h | 3 + src/entities/Object.cpp | 22 ++++ src/entities/Object.h | 2 + src/render/Clouds.cpp | 12 ++- src/render/Clouds.h | 1 + src/render/Renderer.cpp | 7 ++ src/render/Renderer.h | 1 + 13 files changed, 374 insertions(+), 4 deletions(-) diff --git a/src/References.cpp b/src/References.cpp index 187f4ffa..e87f0fd5 100644 --- a/src/References.cpp +++ b/src/References.cpp @@ -1,5 +1,9 @@ #include "common.h" #include "patcher.h" +#include "World.h" +#include "Vehicle.h" +#include "PlayerPed.h" +#include "Pools.h" #include "References.h" CReference *CReferences::aRefs = (CReference*)0x70BBE0; //[NUMREFERENCES]; @@ -17,6 +21,45 @@ CReferences::Init(void) aRefs[NUMREFERENCES-1].next = nil; } +void +CReferences::RemoveReferencesToPlayer(void) +{ + if(FindPlayerVehicle()) + FindPlayerVehicle()->ResolveReferences(); + if(FindPlayerPed()) + FindPlayerPed()->ResolveReferences(); +} + +void +CReferences::PruneAllReferencesInWorld(void) +{ + int i; + CEntity *e; + + i = CPools::GetPedPool()->GetSize(); + while(--i >= 0){ + e = CPools::GetPedPool()->GetSlot(i); + if(e) + e->PruneReferences(); + } + + i = CPools::GetVehiclePool()->GetSize(); + while(--i >= 0){ + e = CPools::GetVehiclePool()->GetSlot(i); + if(e) + e->PruneReferences(); + } + + i = CPools::GetObjectPool()->GetSize(); + while(--i >= 0){ + e = CPools::GetObjectPool()->GetSlot(i); + if(e) + e->PruneReferences(); + } +} + STARTPATCHES InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP); + InjectHook(0x4A7570, CReferences::RemoveReferencesToPlayer, PATCH_JUMP); + InjectHook(0x4A75A0, CReferences::PruneAllReferencesInWorld, PATCH_JUMP); ENDPATCHES diff --git a/src/References.h b/src/References.h index c8017c0d..6476e243 100644 --- a/src/References.h +++ b/src/References.h @@ -13,5 +13,8 @@ class CReferences public: static CReference *aRefs; //[NUMREFERENCES]; static CReference *&pEmptyList; + static void Init(void); + static void RemoveReferencesToPlayer(void); + static void PruneAllReferencesInWorld(void); }; diff --git a/src/SurfaceTable.cpp b/src/SurfaceTable.cpp index 107734e4..2ba884b1 100644 --- a/src/SurfaceTable.cpp +++ b/src/SurfaceTable.cpp @@ -1,11 +1,57 @@ #include "common.h" #include "patcher.h" +#include "main.h" +#include "FileMgr.h" #include "Weather.h" #include "Collision.h" #include "SurfaceTable.h" float (*CSurfaceTable::ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS] = (float (*)[NUMADHESIVEGROUPS])0x8E29D4; +void +CSurfaceTable::Initialise(char *filename) +{ + int lineno, fieldno; + char *line; + char surfname[256]; + float adhesiveLimit; + + CFileMgr::SetDir(""); + CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r"); + + line = (char*)work_buff; + for(lineno = 0; lineno < NUMADHESIVEGROUPS; lineno++){ + // skip white space and comments + while(*line == ' ' || *line == '\t' || *line == '\n' || *line == '\r' || *line == ';'){ + if(*line == ';'){ + while(*line != '\n' && *line != '\r') + line++; + }else + line++; + } + + sscanf(line, "%s", surfname); + // skip what we just read + while(!(*line == ' ' || *line == '\t' || *line == ',')) + line++; + + for(fieldno = 0; fieldno <= lineno; fieldno++){ + // skip white space + while(*line == ' ' || *line == '\t' || *line == ',') + line++; + adhesiveLimit = 0.0f; + if(*line != '-') + sscanf(line, "%f", &adhesiveLimit); + // skip what we just read + while(!(*line == ' ' || *line == '\t' || *line == ',' || *line == '\n')) + line++; + + ms_aAdhesiveLimitTable[lineno][fieldno] = adhesiveLimit; + ms_aAdhesiveLimitTable[fieldno][lineno] = adhesiveLimit; + } + } +} + int CSurfaceTable::GetAdhesionGroup(uint8 surfaceType) { @@ -95,3 +141,10 @@ CSurfaceTable::GetAdhesiveLimit(CColPoint &colpoint) { return ms_aAdhesiveLimitTable[GetAdhesionGroup(colpoint.surfaceB)][GetAdhesionGroup(colpoint.surfaceA)]; } + +STARTPATCHES + InjectHook(0x4AB8F0, CSurfaceTable::Initialise, PATCH_JUMP); + InjectHook(0x4ABA60, CSurfaceTable::GetAdhesionGroup, PATCH_JUMP); + InjectHook(0x4ABAA0, CSurfaceTable::GetWetMultiplier, PATCH_JUMP); + InjectHook(0x4ABA30, CSurfaceTable::GetAdhesiveLimit, PATCH_JUMP); +ENDPATCHES diff --git a/src/SurfaceTable.h b/src/SurfaceTable.h index e61f5026..e1882e69 100644 --- a/src/SurfaceTable.h +++ b/src/SurfaceTable.h @@ -99,6 +99,7 @@ class CSurfaceTable // static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS]; static float (*ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS]; public: + static void Initialise(char *filename); static int GetAdhesionGroup(uint8 surfaceType); static float GetWetMultiplier(uint8 surfaceType); static float GetAdhesiveLimit(CColPoint &colpoint); diff --git a/src/Zones.cpp b/src/Zones.cpp index 4d2d9e5d..363fc3d9 100644 --- a/src/Zones.cpp +++ b/src/Zones.cpp @@ -43,7 +43,9 @@ CheckZoneInfo(CZoneInfo *info) assert(info->gangThreshold[7] <= info->gangThreshold[8]); } -wchar* CZone::GetTranslatedName() { +wchar* +CZone::GetTranslatedName(void) +{ return TheText.Get(name); } @@ -621,6 +623,224 @@ CTheZones::InitialiseAudioZoneArray(void) } } +void +CTheZones::SaveAllZones(uint8 *buffer, uint32 *length) +{ + int i; + + *length = 8 + 12 + + NUMZONES*56 + 2*NUMZONES*58 + 4 + + NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4; + + buffer[0] = 'Z'; + buffer[1] = 'N'; + buffer[2] = 'S'; + buffer[3] = '\0'; + *(uint32*)(buffer+4) = *length - 8; + buffer += 8; + + *(int32*)(buffer) = GetIndexForZonePointer(m_pPlayersZone); + *(int32*)(buffer+4) = m_CurrLevel; + *(int16*)(buffer+8) = FindIndex; + *(int16*)(buffer+10) = 0; + buffer += 12; + + for(i = 0; i < NUMZONES; i++){ + memcpy(buffer, ZoneArray[i].name, 8); + *(float*)(buffer+8) = ZoneArray[i].minx; + *(float*)(buffer+12) = ZoneArray[i].miny; + *(float*)(buffer+16) = ZoneArray[i].minz; + *(float*)(buffer+20) = ZoneArray[i].maxx; + *(float*)(buffer+24) = ZoneArray[i].maxy; + *(float*)(buffer+28) = ZoneArray[i].maxz; + *(int32*)(buffer+32) = ZoneArray[i].type; + *(int32*)(buffer+36) = ZoneArray[i].level; + *(int16*)(buffer+40) = ZoneArray[i].zoneinfoDay; + *(int16*)(buffer+42) = ZoneArray[i].zoneinfoNight; + *(int32*)(buffer+44) = GetIndexForZonePointer(ZoneArray[i].child); + *(int32*)(buffer+48) = GetIndexForZonePointer(ZoneArray[i].parent); + *(int32*)(buffer+52) = GetIndexForZonePointer(ZoneArray[i].next); + buffer += 56; + } + + for(i = 0; i < 2*NUMZONES; i++){ + *(int16*)(buffer) = ZoneInfoArray[i].carDensity; + *(int16*)(buffer+2) = ZoneInfoArray[i].carThreshold[0]; + *(int16*)(buffer+4) = ZoneInfoArray[i].carThreshold[1]; + *(int16*)(buffer+6) = ZoneInfoArray[i].carThreshold[2]; + *(int16*)(buffer+8) = ZoneInfoArray[i].carThreshold[3]; + *(int16*)(buffer+10) = ZoneInfoArray[i].carThreshold[4]; + *(int16*)(buffer+12) = ZoneInfoArray[i].carThreshold[5]; + *(int16*)(buffer+14) = ZoneInfoArray[i].copThreshold; + *(int16*)(buffer+16) = ZoneInfoArray[i].gangThreshold[0]; + *(int16*)(buffer+18) = ZoneInfoArray[i].gangThreshold[1]; + *(int16*)(buffer+20) = ZoneInfoArray[i].gangThreshold[2]; + *(int16*)(buffer+22) = ZoneInfoArray[i].gangThreshold[3]; + *(int16*)(buffer+24) = ZoneInfoArray[i].gangThreshold[4]; + *(int16*)(buffer+26) = ZoneInfoArray[i].gangThreshold[5]; + *(int16*)(buffer+28) = ZoneInfoArray[i].gangThreshold[6]; + *(int16*)(buffer+30) = ZoneInfoArray[i].gangThreshold[7]; + *(int16*)(buffer+32) = ZoneInfoArray[i].gangThreshold[8]; + *(uint16*)(buffer+34) = ZoneInfoArray[i].pedDensity; + *(uint16*)(buffer+36) = ZoneInfoArray[i].copDensity; + *(uint16*)(buffer+38) = ZoneInfoArray[i].gangDensity[0]; + *(uint16*)(buffer+40) = ZoneInfoArray[i].gangDensity[1]; + *(uint16*)(buffer+42) = ZoneInfoArray[i].gangDensity[2]; + *(uint16*)(buffer+44) = ZoneInfoArray[i].gangDensity[3]; + *(uint16*)(buffer+46) = ZoneInfoArray[i].gangDensity[4]; + *(uint16*)(buffer+48) = ZoneInfoArray[i].gangDensity[5]; + *(uint16*)(buffer+50) = ZoneInfoArray[i].gangDensity[6]; + *(uint16*)(buffer+52) = ZoneInfoArray[i].gangDensity[7]; + *(uint16*)(buffer+54) = ZoneInfoArray[i].gangDensity[8]; + *(uint16*)(buffer+56) = ZoneInfoArray[i].pedGroup; + buffer += 58; + } + + *(uint16*)(buffer) = TotalNumberOfZones; + *(uint16*)(buffer+2) = TotalNumberOfZoneInfos; + buffer += 4; + + for(i = 0; i < NUMMAPZONES; i++){ + memcpy(buffer, MapZoneArray[i].name, 8); + *(float*)(buffer+8) = MapZoneArray[i].minx; + *(float*)(buffer+12) = MapZoneArray[i].miny; + *(float*)(buffer+16) = MapZoneArray[i].minz; + *(float*)(buffer+20) = MapZoneArray[i].maxx; + *(float*)(buffer+24) = MapZoneArray[i].maxy; + *(float*)(buffer+28) = MapZoneArray[i].maxz; + *(int32*)(buffer+32) = MapZoneArray[i].type; + *(int32*)(buffer+36) = MapZoneArray[i].level; + *(int16*)(buffer+40) = MapZoneArray[i].zoneinfoDay; + *(int16*)(buffer+42) = MapZoneArray[i].zoneinfoNight; +#ifdef STANDALONE + // BUG: GetIndexForZonePointer uses ZoneArray + // so indices will be unpredictable with different memory layout + assert(0); +#endif + *(int32*)(buffer+44) = GetIndexForZonePointer(MapZoneArray[i].child); + *(int32*)(buffer+48) = GetIndexForZonePointer(MapZoneArray[i].parent); + *(int32*)(buffer+52) = GetIndexForZonePointer(MapZoneArray[i].next); + buffer += 56; + } + + for(i = 0; i < NUMAUDIOZONES; i++){ + *(int16*)buffer = AudioZoneArray[i]; + buffer += 2; + } + + *(uint16*)(buffer) = TotalNumberOfMapZones; + *(uint16*)(buffer+2) = NumberOfAudioZones; +} + +void +CTheZones::LoadAllZones(uint8 *buffer, uint32 length) +{ + int i; + + assert(length == 8 + 12 + + NUMZONES*56 + 2*NUMZONES*58 + 4 + + NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4); + assert(buffer[0] == 'Z'); + assert(buffer[1] == 'N'); + assert(buffer[2] == 'S'); + assert(buffer[3] == '\0'); + assert(*(uint32*)(buffer+4) == length - 8); + buffer += 8; + + m_pPlayersZone = GetPointerForZoneIndex(*(int32*)(buffer)); + m_CurrLevel = (eLevelName)*(int32*)(buffer+4); + FindIndex = *(int16*)(buffer+8); + assert(*(int16*)(buffer+10) == 0); + buffer += 12; + + for(i = 0; i < NUMZONES; i++){ + memcpy(ZoneArray[i].name, buffer, 8); + ZoneArray[i].minx = *(float*)(buffer+8); + ZoneArray[i].miny = *(float*)(buffer+12); + ZoneArray[i].minz = *(float*)(buffer+16); + ZoneArray[i].maxx = *(float*)(buffer+20); + ZoneArray[i].maxy = *(float*)(buffer+24); + ZoneArray[i].maxz = *(float*)(buffer+28); + ZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); + ZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); + ZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); + ZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); + ZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); + ZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); + ZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); + buffer += 56; + } + + for(i = 0; i < 2*NUMZONES; i++){ + ZoneInfoArray[i].carDensity = *(int16*)(buffer); + ZoneInfoArray[i].carThreshold[0] = *(int16*)(buffer+2); + ZoneInfoArray[i].carThreshold[1] = *(int16*)(buffer+4); + ZoneInfoArray[i].carThreshold[2] = *(int16*)(buffer+6); + ZoneInfoArray[i].carThreshold[3] = *(int16*)(buffer+8); + ZoneInfoArray[i].carThreshold[4] = *(int16*)(buffer+10); + ZoneInfoArray[i].carThreshold[5] = *(int16*)(buffer+12); + ZoneInfoArray[i].copThreshold = *(int16*)(buffer+14); + ZoneInfoArray[i].gangThreshold[0] = *(int16*)(buffer+16); + ZoneInfoArray[i].gangThreshold[1] = *(int16*)(buffer+18); + ZoneInfoArray[i].gangThreshold[2] = *(int16*)(buffer+20); + ZoneInfoArray[i].gangThreshold[3] = *(int16*)(buffer+22); + ZoneInfoArray[i].gangThreshold[4] = *(int16*)(buffer+24); + ZoneInfoArray[i].gangThreshold[5] = *(int16*)(buffer+26); + ZoneInfoArray[i].gangThreshold[6] = *(int16*)(buffer+28); + ZoneInfoArray[i].gangThreshold[7] = *(int16*)(buffer+30); + ZoneInfoArray[i].gangThreshold[8] = *(int16*)(buffer+32); + ZoneInfoArray[i].pedDensity = *(uint16*)(buffer+34); + ZoneInfoArray[i].copDensity = *(uint16*)(buffer+36); + ZoneInfoArray[i].gangDensity[0] = *(uint16*)(buffer+38); + ZoneInfoArray[i].gangDensity[1] = *(uint16*)(buffer+40); + ZoneInfoArray[i].gangDensity[2] = *(uint16*)(buffer+42); + ZoneInfoArray[i].gangDensity[3] = *(uint16*)(buffer+44); + ZoneInfoArray[i].gangDensity[4] = *(uint16*)(buffer+46); + ZoneInfoArray[i].gangDensity[5] = *(uint16*)(buffer+48); + ZoneInfoArray[i].gangDensity[6] = *(uint16*)(buffer+50); + ZoneInfoArray[i].gangDensity[7] = *(uint16*)(buffer+52); + ZoneInfoArray[i].gangDensity[8] = *(uint16*)(buffer+54); + ZoneInfoArray[i].pedGroup = *(uint16*)(buffer+56); + buffer += 58; + } + + TotalNumberOfZones = *(uint16*)(buffer); + TotalNumberOfZoneInfos = *(uint16*)(buffer+2); + buffer += 4; + + for(i = 0; i < NUMMAPZONES; i++){ + memcpy(MapZoneArray[i].name, buffer, 8); + MapZoneArray[i].minx = *(float*)(buffer+8); + MapZoneArray[i].miny = *(float*)(buffer+12); + MapZoneArray[i].minz = *(float*)(buffer+16); + MapZoneArray[i].maxx = *(float*)(buffer+20); + MapZoneArray[i].maxy = *(float*)(buffer+24); + MapZoneArray[i].maxz = *(float*)(buffer+28); + MapZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); + MapZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); + MapZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); + MapZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); +#ifdef STANDALONE + // BUG: GetPointerForZoneIndex uses ZoneArray + // so pointers will be unpredictable with different memory layout + assert(0); +#endif + MapZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); + MapZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); + MapZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); + buffer += 56; + } + + for(i = 0; i < NUMAUDIOZONES; i++){ + AudioZoneArray[i] = *(int16*)buffer; + buffer += 2; + } + + TotalNumberOfMapZones = *(uint16*)(buffer); + NumberOfAudioZones = *(uint16*)(buffer+2); +} + + STARTPATCHES InjectHook(0x4B5DD0, &CZone::GetTranslatedName, PATCH_JUMP); InjectHook(0x4B5DE0, CTheZones::Init, PATCH_JUMP); @@ -649,5 +869,6 @@ STARTPATCHES InjectHook(0x4B83E0, CTheZones::FindAudioZone, PATCH_JUMP); InjectHook(0x4B8430, CTheZones::FindZoneForPoint, PATCH_JUMP); InjectHook(0x4B8340, CTheZones::AddZoneToAudioZoneArray, PATCH_JUMP); - InjectHook(0x4B8380, CTheZones::InitialiseAudioZoneArray, PATCH_JUMP); + InjectHook(0x4B8510, CTheZones::SaveAllZones, PATCH_JUMP); + InjectHook(0x4B8950, CTheZones::LoadAllZones, PATCH_JUMP); ENDPATCHES diff --git a/src/Zones.h b/src/Zones.h index 47a4dc47..bf3957de 100644 --- a/src/Zones.h +++ b/src/Zones.h @@ -28,7 +28,7 @@ public: CZone *parent; CZone *next; - wchar *GetTranslatedName(); + wchar *GetTranslatedName(void); }; class CZoneInfo @@ -104,6 +104,9 @@ public: static int16 FindAudioZone(CVector *pos); static eLevelName FindZoneForPoint(const CVector &pos); static CZone *GetPointerForZoneIndex(int32 i) { return i == -1 ? nil : &ZoneArray[i]; } + static int32 GetIndexForZonePointer(CZone *zone) { return zone == nil ? -1 : zone - ZoneArray; } static void AddZoneToAudioZoneArray(CZone *zone); static void InitialiseAudioZoneArray(void); + static void SaveAllZones(uint8 *buffer, uint32 *length); + static void LoadAllZones(uint8 *buffer, uint32 length); }; diff --git a/src/config.h b/src/config.h index a1e7335d..8cb02190 100644 --- a/src/config.h +++ b/src/config.h @@ -62,6 +62,9 @@ enum Config { NUMPICKUPS = 336, }; +// We'll use this once we're ready to become independent of the game +// Use it to mark bugs in the code that will prevent the game from working then +//#define STANDALONE // We don't expect to compile for PS2 or Xbox // but it might be interesting for documentation purposes diff --git a/src/entities/Object.cpp b/src/entities/Object.cpp index dbc38b9d..6712d77b 100644 --- a/src/entities/Object.cpp +++ b/src/entities/Object.cpp @@ -1,5 +1,7 @@ #include "common.h" #include "patcher.h" +#include "main.h" +#include "Lights.h" #include "Pools.h" #include "Radar.h" #include "Object.h" @@ -63,6 +65,26 @@ CObject::Render(void) CEntity::Render(); } +bool +CObject::SetupLighting(void) +{ + DeActivateDirectional(); + SetAmbientColours(); + + if(bRenderScorched){ + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + return true; + } + return false; +} + +void +CObject::RemoveLighting(bool reset) +{ + if(reset) + WorldReplaceScorchedLightsWithNormal(Scene.world); +} + WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); } STARTPATCHES diff --git a/src/entities/Object.h b/src/entities/Object.h index 3a8d62f2..de4c8e05 100644 --- a/src/entities/Object.h +++ b/src/entities/Object.h @@ -68,6 +68,8 @@ public: ~CObject(void); void Render(void); + bool SetupLighting(void); + void RemoveLighting(bool reset); void ObjectDamage(float amount); diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp index bf572841..d582bff8 100644 --- a/src/render/Clouds.cpp +++ b/src/render/Clouds.cpp @@ -40,6 +40,16 @@ CClouds::Init(void) CloudRotation = 0.0f; } +void +CClouds::Shutdown(void) +{ + RwTextureDestroy(gpCloudTex[0]); + RwTextureDestroy(gpCloudTex[1]); + RwTextureDestroy(gpCloudTex[2]); + RwTextureDestroy(gpCloudTex[3]); + RwTextureDestroy(gpCloudTex[4]); +} + void CClouds::Update(void) { @@ -48,7 +58,6 @@ CClouds::Update(void) IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f) * 60.0f; } - void CClouds::Render(void) { @@ -424,6 +433,7 @@ CClouds::RenderHorizon(void) STARTPATCHES InjectHook(0x4F6C10, CClouds::Init, PATCH_JUMP); + InjectHook(0x4F6CA0, CClouds::Shutdown, PATCH_JUMP); InjectHook(0x4F6CE0, CClouds::Update, PATCH_JUMP); InjectHook(0x4F6D90, CClouds::Render, PATCH_JUMP); InjectHook(0x4F7F00, CClouds::RenderBackground, PATCH_JUMP); diff --git a/src/render/Clouds.h b/src/render/Clouds.h index 96f04bb1..c8000569 100644 --- a/src/render/Clouds.h +++ b/src/render/Clouds.h @@ -12,6 +12,7 @@ public: static CRGBA &ms_colourBottom; static void Init(void); + static void Shutdown(void); static void Update(void); static void Render(void); static void RenderBackground(int16 topred, int16 topgreen, int16 topblue, diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 405b9bb2..a6f28443 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -53,6 +53,12 @@ CRenderer::Init(void) SortBIGBuildings(); } +void +CRenderer::Shutdown(void) +{ + gSortedVehiclesAndPeds.Shutdown(); +} + void CRenderer::PreRender(void) { @@ -1170,6 +1176,7 @@ CRenderer::RemoveVehiclePedLights(CEntity *ent, bool reset) STARTPATCHES InjectHook(0x4A7680, CRenderer::Init, PATCH_JUMP); + InjectHook(0x4A76A0, CRenderer::Shutdown, PATCH_JUMP); InjectHook(0x4A7B90, CRenderer::RenderOneRoad, PATCH_JUMP); InjectHook(0x4A7BA0, CRenderer::RenderOneNonRoad, PATCH_JUMP); diff --git a/src/render/Renderer.h b/src/render/Renderer.h index 433035a0..4b96c775 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -27,6 +27,7 @@ public: static bool &m_loadingPriority; static void Init(void); + static void Shutdown(void); static void PreRender(void); static void RenderRoads(void);