From afc7376bab13046d50bb25c5ef8c866f62c28acf Mon Sep 17 00:00:00 2001 From: Silent Date: Fri, 22 May 2026 19:19:23 +0200 Subject: [PATCH 1/2] std.stream: Unload FLA if it lacks any of the imports we need FLA like this is unlikely to exist, but let's play it safe. --- src/shared/f92la/f92la.h | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/shared/f92la/f92la.h b/src/shared/f92la/f92la.h index ba35210d..3534d396 100644 --- a/src/shared/f92la/f92la.h +++ b/src/shared/f92la/f92la.h @@ -5,28 +5,28 @@ struct LibF92LA { // $fastman92limitAdjuster.asi - HMODULE hLib = NULL; + HMODULE hLib = nullptr; // Count of file IDs - int32_t(*GetNumberOfFileIDs)(); + int32_t(*GetNumberOfFileIDs)() = nullptr; // Returns model info, prev file ID - int32_t(*GetFileInfoPrevFileID)(int32_t fileID); + int32_t(*GetFileInfoPrevFileID)(int32_t fileID) = nullptr; // Returns model info, next file ID - int32_t(*GetFileInfoNextFileID)(int32_t fileID); + int32_t(*GetFileInfoNextFileID)(int32_t fileID) = nullptr; // Returns model info, next on CD file ID - int32_t(*GetFileInfoNextOnCDfileID)(int32_t fileID); + int32_t(*GetFileInfoNextOnCDfileID)(int32_t fileID) = nullptr; // Sets file info, Prev file ID - void(*SetFileInfoPrevFileID)(int32_t fileID, int32_t newValue); + void(*SetFileInfoPrevFileID)(int32_t fileID, int32_t newValue) = nullptr; // Sets file info, Next file ID - void(*SetFileInfoNextFileID)(int32_t fileID, int32_t newValue); + void(*SetFileInfoNextFileID)(int32_t fileID, int32_t newValue) = nullptr; // Sets file info, NextOnCd file ID - void (*SetFileInfoNextOnCDfileID)(int32_t fileID, int32_t newValue); + void (*SetFileInfoNextOnCDfileID)(int32_t fileID, int32_t newValue) = nullptr; }; inline LibF92LA Fastman92LimitAdjusterCreate() { LibF92LA f92la; - if(GetModuleHandleEx(0, "$fastman92limitAdjuster.asi", &f92la.hLib)) + if(GetModuleHandleEx(0, TEXT("$fastman92limitAdjuster.asi"), &f92la.hLib) != FALSE || GetModuleHandleEx(0, TEXT("$fastman92limitAdjuster"), &f92la.hLib) != FALSE) { f92la.GetNumberOfFileIDs = (decltype(f92la.GetNumberOfFileIDs)) GetProcAddress(f92la.hLib, "GetNumberOfFileIDs"); f92la.GetFileInfoPrevFileID = (decltype(f92la.GetFileInfoPrevFileID)) GetProcAddress(f92la.hLib, "GetFileInfoPrevFileID"); @@ -35,6 +35,14 @@ inline LibF92LA Fastman92LimitAdjusterCreate() f92la.SetFileInfoPrevFileID = (decltype(f92la.SetFileInfoPrevFileID)) GetProcAddress(f92la.hLib, "SetFileInfoPrevFileID"); f92la.SetFileInfoNextFileID = (decltype(f92la.SetFileInfoNextFileID)) GetProcAddress(f92la.hLib, "SetFileInfoNextFileID"); f92la.SetFileInfoNextOnCDfileID = (decltype(f92la.SetFileInfoNextOnCDfileID)) GetProcAddress(f92la.hLib, "SetFileInfoNextOnCDfileID"); + + // If, for some reason, FLA we're using lacks any of those imports, don't try to do anything with it + if (f92la.GetNumberOfFileIDs == nullptr || f92la.GetFileInfoPrevFileID == nullptr || f92la.GetFileInfoNextFileID == nullptr || f92la.GetFileInfoNextOnCDfileID == nullptr + || f92la.SetFileInfoPrevFileID == nullptr || f92la.SetFileInfoNextFileID == nullptr || f92la.SetFileInfoNextOnCDfileID == nullptr) + { + FreeLibrary(f92la.hLib); + f92la.hLib = nullptr; + } } return f92la; } From f592252d6048dd3b548fb6dcf3e09af311dcc2c3 Mon Sep 17 00:00:00 2001 From: Silent Date: Fri, 22 May 2026 20:05:12 +0200 Subject: [PATCH 2/2] std.stream: Clean up ms_aInfoForModel mod compatibility Now everything is lazily loaded and pointer hacks are removed. Fixes incompatibilities when OLA was loaded through Modloader. --- src/plugins/gta3/std.stream/backend.cpp | 6 +-- src/plugins/gta3/std.stream/directory.cpp | 2 +- src/plugins/gta3/std.stream/refresh.cpp | 2 +- src/plugins/gta3/std.stream/streaming.cpp | 66 +++++++++++++++++++---- src/plugins/gta3/std.stream/streaming.hpp | 14 +++-- src/shared/game/gta3/CStreamingInfo.h | 1 - src/translator/gta3/3/10.hpp | 6 --- src/translator/gta3/vc/10.hpp | 6 --- 8 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/plugins/gta3/std.stream/backend.cpp b/src/plugins/gta3/std.stream/backend.cpp index 17beff0e..93affb01 100644 --- a/src/plugins/gta3/std.stream/backend.cpp +++ b/src/plugins/gta3/std.stream/backend.cpp @@ -420,7 +420,7 @@ void CAbstractStreaming::BuildPrevOnCdMap() { CStreamingInfo* res; prev_on_cd.clear(); - for(id_t i = 0; res = InfoForModel(i); ++i) + for(id_t i = 0; res = std::invoke(InfoForModel, this, i); ++i) { id_t nextOnCd = res->GetNextOnCd(); if(nextOnCd != -1) prev_on_cd.emplace(nextOnCd, i); @@ -661,11 +661,11 @@ void CAbstractStreaming::Patch() { // Check if we have a overrider for this clothing item (based on directory offset) DirectoryInfo* entry; - auto it = this->clothes.find(InfoForModel(index)->GetOffset()); + auto it = this->clothes.find(std::invoke(InfoForModel, this, index)->GetOffset()); if(it != clothes.end() && (entry = this->FindClothEntry(it->second->hash))) { // Yep, we have a overrider, save stock entry and quickly import our abstract model - this->RegisterStockEntry(it->second->filename(), *entry, index, InfoForModel(index)->GetImgId()); + this->RegisterStockEntry(it->second->filename(), *entry, index, std::invoke(InfoForModel, this, index)->GetImgId()); this->QuickImport(index, it->second, false, true); } else diff --git a/src/plugins/gta3/std.stream/directory.cpp b/src/plugins/gta3/std.stream/directory.cpp index 270b2fd2..e91afc19 100644 --- a/src/plugins/gta3/std.stream/directory.cpp +++ b/src/plugins/gta3/std.stream/directory.cpp @@ -136,7 +136,7 @@ static void PerformDirectoryRead(size_t size, auto gf = make_function_hook([&RegisterEntry](gfvc_hook::func_type DontCallMe, uint32_t id, char hadModel) { char r = hadModel; - if(RegisterEntry) r = (char) RegisterEntry(*streaming->InfoForModel(id), !!r); + if(RegisterEntry) r = (char) RegisterEntry(*std::invoke(streaming->InfoForModel, streaming, id), !!r); return r; }); diff --git a/src/plugins/gta3/std.stream/refresh.cpp b/src/plugins/gta3/std.stream/refresh.cpp index d8658de6..76ba64ce 100644 --- a/src/plugins/gta3/std.stream/refresh.cpp +++ b/src/plugins/gta3/std.stream/refresh.cpp @@ -453,7 +453,7 @@ template void Refresher::RequestModels() // Do the requests for(auto& pair : mToRefresh) { - auto& model = *streaming.InfoForModel(pair.first); + auto& model = *std::invoke(streaming.InfoForModel, &streaming, pair.first); auto mflags = model.GetStreamFlags(); if(mflags || pair.second.bShallLoadBack) // Has any importance to the streaming? streaming.RequestModel(pair.first, mflags); diff --git a/src/plugins/gta3/std.stream/streaming.cpp b/src/plugins/gta3/std.stream/streaming.cpp index 164ea948..f2eb6db5 100644 --- a/src/plugins/gta3/std.stream/streaming.cpp +++ b/src/plugins/gta3/std.stream/streaming.cpp @@ -38,7 +38,18 @@ void CAbstractStreaming::InitialiseStructAbstraction() this->f92la = Fastman92LimitAdjusterCreate(); if(this->f92la.hLib) + { plugin_ptr->Log("Using fastman92limitadjuster (%p).", f92la.hLib); + InfoForModel = &CAbstractStreaming::InfoForModelInternal_FLA; + } + else if (gvm.IsSA()) + { + InfoForModel = &CAbstractStreaming::InfoForModelInternal_SA; + } + else + { + InfoForModel = &CAbstractStreaming::InfoForModelInternal_VC; + } } const LibF92LA& CAbstractStreaming::GetF92LA() @@ -61,22 +72,59 @@ int32_t CStreamingInfo::AsF92LA() /* * CAbstractStreaming::InfoForModel * Returns the streaming info pointer for the specified resource id + * San Andreas version of the function */ -CStreamingInfo* CAbstractStreaming::InfoForModel(id_t id) +CStreamingInfo* CAbstractStreaming::InfoForModelInternal_SA(id_t id) const +{ + // Note: sizeof(CStreamingInfo) isn't the actual size, so we must do the indexing manually with sizeof_CStreamingInfo!! + static const uint32_t max_NumResources = (lazy_object<0x5B8AFC, char*>::get() - reinterpret_cast(ms_aInfoForModel)) / sizeof_CStreamingInfo; + + if (id < max_NumResources) + { + return (CStreamingInfo*)((uint8_t*)(ms_aInfoForModel) + (id * sizeof_CStreamingInfo)); + } + return nullptr; +} + +/* +* CAbstractStreaming::InfoForModel +* Returns the streaming info pointer for the specified resource id +* III/Vice City version of the function +*/ +CStreamingInfo* CAbstractStreaming::InfoForModelInternal_VC(id_t id) const { // Note: sizeof(CStreamingInfo) isn't the actual size, so we must do the indexing manually with sizeof_CStreamingInfo!! - static CStreamingInfo* max_InfoForModel = this->f92la.hLib? - (CStreamingInfo*)((uint8_t*)(ms_aInfoForModel) + (f92la.GetNumberOfFileIDs() * sizeof_CStreamingInfo)) : - lazy_object<0x5B8AFC, CStreamingInfo*>::get(); - CStreamingInfo* info = (CStreamingInfo*)((uint8_t*)(ms_aInfoForModel) + (id * sizeof_CStreamingInfo)); - return (info < max_InfoForModel? info : nullptr); + static const uint32_t max_NumResources = lazy_object::get(); + + if (id < max_NumResources) + { + return (CStreamingInfo*)((uint8_t*)(ms_aInfoForModel) + (id * sizeof_CStreamingInfo)); + } + return nullptr; +} + +/* +* CAbstractStreaming::InfoForModel +* Returns the streaming info pointer for the specified resource id +* FLA version of the function +*/ +CStreamingInfo* CAbstractStreaming::InfoForModelInternal_FLA(id_t id) const +{ + // Note: sizeof(CStreamingInfo) isn't the actual size, so we must do the indexing manually with sizeof_CStreamingInfo!! + static const uint32_t max_NumResources = f92la.GetNumberOfFileIDs(); + + if (id < max_NumResources) + { + return (CStreamingInfo*)((uint8_t*)(ms_aInfoForModel) + (id * sizeof_CStreamingInfo)); + } + return nullptr; } // Returns the resource index from it's model info structure auto CAbstractStreaming::InfoForModelIndex(const CStreamingInfo& model) -> id_t { // Note: sizeof(CStreamingInfo) isn't the actual size, so we must do the substraction manually with sizeof_CStreamingInfo!! - return (id_t)( ((uint8_t*)(&model) - (uint8_t*)(InfoForModel(0))) / sizeof_CStreamingInfo ); + return (id_t)( ((uint8_t*)(&model) - (uint8_t*)(ms_aInfoForModel)) / sizeof_CStreamingInfo ); } /* @@ -85,7 +133,7 @@ auto CAbstractStreaming::InfoForModelIndex(const CStreamingInfo& model) -> id_t */ bool CAbstractStreaming::IsModelOnStreaming(id_t id) { - return InfoForModel(id)->GetLoadStatus() != 0; + return std::invoke(InfoForModel, this, id)->GetLoadStatus() != 0; } /* @@ -94,7 +142,7 @@ bool CAbstractStreaming::IsModelOnStreaming(id_t id) */ bool CAbstractStreaming::IsModelAvailable(id_t id) { - return InfoForModel(id)->GetLoadStatus() == 1; + return std::invoke(InfoForModel, this, id)->GetLoadStatus() == 1; } /* diff --git a/src/plugins/gta3/std.stream/streaming.hpp b/src/plugins/gta3/std.stream/streaming.hpp index 2ff437e5..a950935f 100644 --- a/src/plugins/gta3/std.stream/streaming.hpp +++ b/src/plugins/gta3/std.stream/streaming.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -261,9 +262,10 @@ class CAbstractStreaming void RemoveUnusedResources(); bool IsModelOnStreaming(id_t id); bool IsModelAvailable(id_t id); - CStreamingInfo* InfoForModel(id_t id); id_t InfoForModelIndex(const CStreamingInfo& model); + CStreamingInfo* (CAbstractStreaming::*InfoForModel)(id_t id) const; + // Checks if file is clothing item bool IsClothes(const modloader::file* file); @@ -307,6 +309,10 @@ class CAbstractStreaming void LoadAbstractCdDirectory(ref_list files); void BuildPrevOnCdMap(); + CStreamingInfo* InfoForModelInternal_SA(id_t id) const; + CStreamingInfo* InfoForModelInternal_VC(id_t id) const; + CStreamingInfo* InfoForModelInternal_FLA(id_t id) const; + // Refreshing void ProcessRefreshes(); @@ -334,7 +340,7 @@ class CAbstractStreaming // Sets the info for model structure for the resource id void SetInfoForModel(id_t id, uint32_t offset, uint32_t blocks) { - auto& model = *this->InfoForModel(id); + auto& model = *std::invoke(InfoForModel, this, id); model.SetStreamData(offset, blocks); model.SetNextOnCd(-1); ClearNextOnCdPointingTo(id); @@ -358,14 +364,14 @@ class CAbstractStreaming void ClearNextOnCdPointingTo(id_t id) { auto prev_pair = prev_on_cd.find(id); - if(prev_pair != prev_on_cd.end()) InfoForModel(prev_pair->second)->SetNextOnCd(-1); + if(prev_pair != prev_on_cd.end()) std::invoke(InfoForModel, this, prev_pair->second)->SetNextOnCd(-1); } // Restore the next on cd pointing to the specified model.... void RestoreNextOnCdPointingTo(id_t id) { auto prev_pair = prev_on_cd.find(id); - if(prev_pair != prev_on_cd.end()) InfoForModel(prev_pair->second)->SetNextOnCd(id); + if(prev_pair != prev_on_cd.end()) std::invoke(InfoForModel, this, prev_pair->second)->SetNextOnCd(id); } public://protected: diff --git a/src/shared/game/gta3/CStreamingInfo.h b/src/shared/game/gta3/CStreamingInfo.h index b54986af..60a975c7 100644 --- a/src/shared/game/gta3/CStreamingInfo.h +++ b/src/shared/game/gta3/CStreamingInfo.h @@ -96,7 +96,6 @@ struct CStreamingInfo { if(auto f92la = this->GetF92LA()) { - auto i = this->AsF92LA(); f92la->SetFileInfoNextOnCDfileID(this->AsF92LA(), nextOnCd); return; } diff --git a/src/translator/gta3/3/10.hpp b/src/translator/gta3/3/10.hpp index 68843c0d..dbd2d274 100644 --- a/src/translator/gta3/3/10.hpp +++ b/src/translator/gta3/3/10.hpp @@ -105,14 +105,8 @@ static void III_10(std::map& map) // std.stream if(true) { - static void* gta3emu_pMaxInfoForModel; - map[0x40D014] = 0x4089C9; // -> offset ms_aInfoForModel //doublecheck map[xVc(0x4102B2)] = 0x40664B; // -> DWORD MAX_RES ; max resources - map[0x5B8AFC] = >a3emu_pMaxInfoForModel;// -> &ms_aInfoForModel[MAX_INFO_FOR_MODEL] - // DONT CHANGE THE FOLLOWING LINE, CHANGE THE MAPPING ABOVE INSTEAD!!! Maybe change the 0x14 sizeof ///////////// - gta3emu_pMaxInfoForModel = *mem_ptr(0x40D014).get() + (0x14 * *mem_ptr(xVc(0x4102B2)).get()); - /////////////////////////////////// map[0x8E3FE0] = 0x6212C4; // DWORD StreamCreateFlags map[xVc(0x6F76F4)] = 0x62129C; // HANDLE hCdSemaphore diff --git a/src/translator/gta3/vc/10.hpp b/src/translator/gta3/vc/10.hpp index 51812f80..6bc00168 100644 --- a/src/translator/gta3/vc/10.hpp +++ b/src/translator/gta3/vc/10.hpp @@ -150,14 +150,8 @@ static void vc_10(std::map& map) // std.stream if(true) { - static void* vcemu_pMaxInfoForModel; - map[0x40D014] = 0x40D5C9; // -> offset ms_aInfoForModel map[xVc(0x4102B2)] = 0x4102B2; // -> DWORD 1F07h ; max resources - map[0x5B8AFC] = &vcemu_pMaxInfoForModel;// -> &ms_aInfoForModel[MAX_INFO_FOR_MODEL] - // DONT CHANGE THE FOLLOWING LINE, CHANGE THE MAPPING ABOVE INSTEAD!!! Maybe change the 0x14 sizeof ///////////// - vcemu_pMaxInfoForModel = *mem_ptr(0x40D014).get() + (0x14 * *mem_ptr(xVc(0x4102B2)).get()); - /////////////////////////////////// map[0x8E3FE0] = 0x6F771C; // DWORD StreamCreateFlags map[xVc(0x6F76F4)] = 0x6F76F4; // HANDLE hCdSemaphore