diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 90d8c19242..2002fe766d 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -19,6 +19,7 @@ - Fix: [#11071, #22958] The virtual floor does not always draw correctly. - Fix: [#18220] Some custom RCT1 scenarios are detected as competition DLC scenarios. - Fix: [#20158] Custom animated scenery .DATs with frame offsets draw a random sprite at the end of their animation. +- Fix: [#22628] Potential crash while rebuilding the scenario index. - Fix: [#23289] Dodgems and Flying Saucer cars can spawn on top of each other when the ride is opened. - Fix: [#24332] Banner font renders differently when using RCT Classic as the base game. - Fix: [#24346] Possible crash during line drawing in OpenGL mode. diff --git a/src/openrct2/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index 9004e87eb0..6309e330e6 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -163,6 +163,21 @@ public: return objectList; } + std::unique_ptr LoadTempObject(std::string_view id) override + { + const ObjectRepositoryItem* ori = _objectRepository.FindObject(id); + if (ori == nullptr) + { + LOG_ERROR("Object '%s' not found in repository.", std::string{ id }.c_str()); + return nullptr; + } + + auto object = _objectRepository.LoadObject(ori); + object->Load(); + + return object; + } + Object* LoadObject(std::string_view identifier) override { const ObjectRepositoryItem* ori = _objectRepository.FindObject(identifier); diff --git a/src/openrct2/object/ObjectManager.h b/src/openrct2/object/ObjectManager.h index 2a8a0dbff5..168ddd37e5 100644 --- a/src/openrct2/object/ObjectManager.h +++ b/src/openrct2/object/ObjectManager.h @@ -37,6 +37,7 @@ struct IObjectManager virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const Object* object) = 0; virtual ObjectList GetLoadedObjects() = 0; + virtual std::unique_ptr LoadTempObject(std::string_view identifier) = 0; virtual Object* LoadObject(std::string_view identifier) = 0; virtual Object* LoadObject(const RCTObjectEntry* entry) = 0; virtual Object* LoadObject(const ObjectEntryDescriptor& descriptor) = 0; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index f64053999c..c6a68bb82a 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -96,8 +96,6 @@ static constexpr ObjectEntryIndex ObjectEntryIndexIgnore = 254; namespace OpenRCT2::RCT1 { - static std::mutex mtx; - class S4Importer final : public IParkImporter { private: @@ -272,19 +270,14 @@ namespace OpenRCT2::RCT1 { auto& objManager = GetContext()->GetObjectManager(); - // Ensure only one thread talks to the object manager at a time - std::lock_guard lock(mtx); - - // Unload loaded scenario text object, if any. - if (auto* obj = objManager.GetLoadedObject(0); obj != nullptr) - objManager.UnloadObjects({ obj->GetDescriptor() }); - // Load the one specified - if (auto* obj = objManager.LoadObject(desc.textObjectId); obj != nullptr) + if (auto obj = objManager.LoadTempObject(desc.textObjectId); obj != nullptr) { - auto* textObject = reinterpret_cast(obj); - name = textObject->GetScenarioName(); - details = textObject->GetScenarioDetails(); + auto& textObject = reinterpret_cast(*obj); + name = textObject.GetScenarioName(); + details = textObject.GetScenarioDetails(); + + obj->Unload(); } } @@ -2415,20 +2408,13 @@ namespace OpenRCT2::RCT1 { auto& objManager = GetContext()->GetObjectManager(); - // Ensure only one thread talks to the object manager at a time - std::lock_guard lock(mtx); - - // Unload loaded scenario text object, if any. - if (auto* obj = objManager.GetLoadedObject(0); obj != nullptr) - objManager.UnloadObjects({ obj->GetDescriptor() }); - // Load the one specified - if (auto* obj = objManager.LoadObject(desc.textObjectId); obj != nullptr) + if (auto obj = objManager.LoadTempObject(desc.textObjectId); obj != nullptr) { - auto* textObject = reinterpret_cast(obj); - name = textObject->GetScenarioName(); - parkName = textObject->GetParkName(); - details = textObject->GetScenarioDetails(); + auto& textObject = reinterpret_cast(*obj); + name = textObject.GetScenarioName(); + parkName = textObject.GetParkName(); + details = textObject.GetScenarioDetails(); } } } diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 183d1f659e..b8f8e16f87 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -95,8 +95,6 @@ namespace OpenRCT2::RCT2 { #define DECRYPT_MONEY(money) (static_cast(Numerics::rol32((money) ^ 0xF4EC9621, 13))) - static std::mutex mtx; - /** * Class to import RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). */ @@ -298,19 +296,14 @@ namespace OpenRCT2::RCT2 { auto& objManager = GetContext()->GetObjectManager(); - // Ensure only one thread talks to the object manager at a time - std::lock_guard lock(mtx); - - // Unload loaded scenario text object, if any. - if (auto* obj = objManager.GetLoadedObject(0); obj != nullptr) - objManager.UnloadObjects({ obj->GetDescriptor() }); - // Load the one specified - if (auto* obj = objManager.LoadObject(desc.textObjectId); obj != nullptr) + if (auto obj = objManager.LoadTempObject(desc.textObjectId); obj != nullptr) { - auto* textObject = reinterpret_cast(obj); - dst->Name = textObject->GetScenarioName(); - dst->Details = textObject->GetScenarioDetails(); + auto& textObject = reinterpret_cast(*obj); + dst->Name = textObject.GetScenarioName(); + dst->Details = textObject.GetScenarioDetails(); + + obj->Unload(); } }