mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-24 23:34:37 +01:00
Close #13000: Refactor ObjectFactory to use unique_ptr
Employs the smart pointer unique_ptr for safer memory management. Classes involved: - ObjectRepository - ObjectManager
This commit is contained in:
@@ -35,7 +35,7 @@ class ObjectManager final : public IObjectManager
|
||||
{
|
||||
private:
|
||||
IObjectRepository& _objectRepository;
|
||||
std::vector<Object*> _loadedObjects;
|
||||
std::vector<std::unique_ptr<Object>> _loadedObjects;
|
||||
std::array<std::vector<ObjectEntryIndex>, RIDE_TYPE_COUNT> _rideTypeToObjectMap;
|
||||
|
||||
// Used to return a safe empty vector back from GetAllRideEntries, can be removed when std::span is available
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return _loadedObjects[index];
|
||||
return _loadedObjects[index].get();
|
||||
}
|
||||
|
||||
Object* GetLoadedObject(int32_t objectType, size_t index) override
|
||||
@@ -114,14 +114,15 @@ public:
|
||||
int32_t slot = FindSpareSlot(objectType);
|
||||
if (slot != -1)
|
||||
{
|
||||
loadedObject = GetOrLoadObject(ori);
|
||||
if (loadedObject != nullptr)
|
||||
auto object = GetOrLoadObject(ori);
|
||||
if (object != nullptr)
|
||||
{
|
||||
if (_loadedObjects.size() <= static_cast<size_t>(slot))
|
||||
{
|
||||
_loadedObjects.resize(slot + 1);
|
||||
}
|
||||
_loadedObjects[slot] = loadedObject;
|
||||
loadedObject = object.get();
|
||||
_loadedObjects[slot] = std::move(object);
|
||||
UpdateSceneryGroupIndexes();
|
||||
ResetTypeToRideEntryIndexMap();
|
||||
}
|
||||
@@ -140,7 +141,7 @@ public:
|
||||
size_t numNewLoadedObjects = 0;
|
||||
auto loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects);
|
||||
|
||||
SetNewLoadedObjectList(loadedObjects);
|
||||
SetNewLoadedObjectList(std::move(loadedObjects));
|
||||
LoadDefaultObjects();
|
||||
UpdateSceneryGroupIndexes();
|
||||
ResetTypeToRideEntryIndexMap();
|
||||
@@ -177,9 +178,9 @@ public:
|
||||
|
||||
void UnloadAll() override
|
||||
{
|
||||
for (auto object : _loadedObjects)
|
||||
for (auto& object : _loadedObjects)
|
||||
{
|
||||
UnloadObject(object);
|
||||
UnloadObject(object.get());
|
||||
}
|
||||
UpdateSceneryGroupIndexes();
|
||||
ResetTypeToRideEntryIndexMap();
|
||||
@@ -187,7 +188,7 @@ public:
|
||||
|
||||
void ResetObjects() override
|
||||
{
|
||||
for (auto loadedObject : _loadedObjects)
|
||||
for (auto& loadedObject : _loadedObjects)
|
||||
{
|
||||
if (loadedObject != nullptr)
|
||||
{
|
||||
@@ -334,7 +335,8 @@ private:
|
||||
Guard::ArgumentNotNull(object, GUARD_LINE);
|
||||
|
||||
auto result = std::numeric_limits<size_t>().max();
|
||||
auto it = std::find(_loadedObjects.begin(), _loadedObjects.end(), object);
|
||||
auto it = std::find_if(
|
||||
_loadedObjects.begin(), _loadedObjects.end(), [object](auto& obj) { return obj.get() == object; });
|
||||
if (it != _loadedObjects.end())
|
||||
{
|
||||
result = std::distance(_loadedObjects.begin(), it);
|
||||
@@ -342,7 +344,7 @@ private:
|
||||
return result;
|
||||
}
|
||||
|
||||
void SetNewLoadedObjectList(const std::vector<Object*>& newLoadedObjects)
|
||||
void SetNewLoadedObjectList(std::vector<std::unique_ptr<Object>> newLoadedObjects)
|
||||
{
|
||||
if (newLoadedObjects.empty())
|
||||
{
|
||||
@@ -352,13 +354,15 @@ private:
|
||||
{
|
||||
UnloadObjectsExcept(newLoadedObjects);
|
||||
}
|
||||
_loadedObjects = newLoadedObjects;
|
||||
_loadedObjects = std::move(newLoadedObjects);
|
||||
}
|
||||
|
||||
void UnloadObject(Object* object)
|
||||
{
|
||||
if (object != nullptr)
|
||||
{
|
||||
object->Unload();
|
||||
|
||||
// TODO try to prevent doing a repository search
|
||||
const ObjectRepositoryItem* ori = _objectRepository.FindObject(object->GetObjectEntry());
|
||||
if (ori != nullptr)
|
||||
@@ -370,40 +374,37 @@ private:
|
||||
// slots, we have to make sure find and set all of them to nullptr
|
||||
for (auto& obj : _loadedObjects)
|
||||
{
|
||||
if (obj == object)
|
||||
if (obj.get() == object)
|
||||
{
|
||||
obj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
object->Unload();
|
||||
delete object;
|
||||
}
|
||||
}
|
||||
|
||||
void UnloadObjectsExcept(const std::vector<Object*>& newLoadedObjects)
|
||||
void UnloadObjectsExcept(const std::vector<std::unique_ptr<Object>>& newLoadedObjects)
|
||||
{
|
||||
// Build a hash set for quick checking
|
||||
auto exceptSet = std::unordered_set<Object*>();
|
||||
for (auto object : newLoadedObjects)
|
||||
for (auto& object : newLoadedObjects)
|
||||
{
|
||||
if (object != nullptr)
|
||||
{
|
||||
exceptSet.insert(object);
|
||||
exceptSet.insert(object.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Unload objects that are not in the hash set
|
||||
size_t totalObjectsLoaded = 0;
|
||||
size_t numObjectsUnloaded = 0;
|
||||
for (auto object : _loadedObjects)
|
||||
for (auto& object : _loadedObjects)
|
||||
{
|
||||
if (object != nullptr)
|
||||
{
|
||||
totalObjectsLoaded++;
|
||||
if (exceptSet.find(object) == exceptSet.end())
|
||||
if (exceptSet.find(object.get()) == exceptSet.end())
|
||||
{
|
||||
UnloadObject(object);
|
||||
UnloadObject(object.get());
|
||||
numObjectsUnloaded++;
|
||||
}
|
||||
}
|
||||
@@ -414,7 +415,7 @@ private:
|
||||
|
||||
void UpdateSceneryGroupIndexes()
|
||||
{
|
||||
for (auto loadedObject : _loadedObjects)
|
||||
for (auto& loadedObject : _loadedObjects)
|
||||
{
|
||||
if (loadedObject != nullptr)
|
||||
{
|
||||
@@ -423,26 +424,26 @@ private:
|
||||
{
|
||||
case OBJECT_TYPE_SMALL_SCENERY:
|
||||
sceneryEntry = static_cast<rct_scenery_entry*>(loadedObject->GetLegacyData());
|
||||
sceneryEntry->small_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject);
|
||||
sceneryEntry->small_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get());
|
||||
break;
|
||||
case OBJECT_TYPE_LARGE_SCENERY:
|
||||
sceneryEntry = static_cast<rct_scenery_entry*>(loadedObject->GetLegacyData());
|
||||
sceneryEntry->large_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject);
|
||||
sceneryEntry->large_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get());
|
||||
break;
|
||||
case OBJECT_TYPE_WALLS:
|
||||
sceneryEntry = static_cast<rct_scenery_entry*>(loadedObject->GetLegacyData());
|
||||
sceneryEntry->wall.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject);
|
||||
sceneryEntry->wall.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get());
|
||||
break;
|
||||
case OBJECT_TYPE_BANNERS:
|
||||
sceneryEntry = static_cast<rct_scenery_entry*>(loadedObject->GetLegacyData());
|
||||
sceneryEntry->banner.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject);
|
||||
sceneryEntry->banner.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get());
|
||||
break;
|
||||
case OBJECT_TYPE_PATH_BITS:
|
||||
sceneryEntry = static_cast<rct_scenery_entry*>(loadedObject->GetLegacyData());
|
||||
sceneryEntry->path_bit.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject);
|
||||
sceneryEntry->path_bit.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get());
|
||||
break;
|
||||
case OBJECT_TYPE_SCENERY_GROUP:
|
||||
auto sgObject = dynamic_cast<SceneryGroupObject*>(loadedObject);
|
||||
auto sgObject = dynamic_cast<SceneryGroupObject*>(loadedObject.get());
|
||||
sgObject->UpdateEntryIndexes();
|
||||
break;
|
||||
}
|
||||
@@ -507,17 +508,15 @@ private:
|
||||
}
|
||||
else
|
||||
{
|
||||
Object* loadedObject = nullptr;
|
||||
loadedObject = ori->LoadedObject;
|
||||
auto loadedObject = ori->LoadedObject;
|
||||
if (loadedObject == nullptr)
|
||||
{
|
||||
loadedObject = _objectRepository.LoadObject(ori);
|
||||
if (loadedObject == nullptr)
|
||||
auto object = _objectRepository.LoadObject(ori);
|
||||
if (object == nullptr)
|
||||
{
|
||||
invalidEntries.push_back(entry);
|
||||
ReportObjectLoadProblem(&entry);
|
||||
}
|
||||
delete loadedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,9 +576,10 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Object*> LoadObjects(std::vector<const ObjectRepositoryItem*>& requiredObjects, size_t* outNewObjectsLoaded)
|
||||
std::vector<std::unique_ptr<Object>> LoadObjects(
|
||||
std::vector<const ObjectRepositoryItem*>& requiredObjects, size_t* outNewObjectsLoaded)
|
||||
{
|
||||
std::vector<Object*> objects;
|
||||
std::vector<std::unique_ptr<Object>> objects;
|
||||
std::vector<Object*> loadedObjects;
|
||||
std::vector<rct_object_entry> badObjects;
|
||||
objects.resize(OBJECT_ENTRY_COUNT);
|
||||
@@ -589,14 +589,14 @@ private:
|
||||
std::mutex commonMutex;
|
||||
ParallelFor(requiredObjects, [this, &commonMutex, requiredObjects, &objects, &badObjects, &loadedObjects](size_t i) {
|
||||
auto ori = requiredObjects[i];
|
||||
Object* loadedObject = nullptr;
|
||||
std::unique_ptr<Object> object;
|
||||
if (ori != nullptr)
|
||||
{
|
||||
loadedObject = ori->LoadedObject;
|
||||
auto loadedObject = ori->LoadedObject;
|
||||
if (loadedObject == nullptr)
|
||||
{
|
||||
loadedObject = _objectRepository.LoadObject(ori);
|
||||
if (loadedObject == nullptr)
|
||||
object = _objectRepository.LoadObject(ori);
|
||||
if (object == nullptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(commonMutex);
|
||||
badObjects.push_back(ori->ObjectEntry);
|
||||
@@ -605,13 +605,13 @@ private:
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(commonMutex);
|
||||
loadedObjects.push_back(loadedObject);
|
||||
loadedObjects.push_back(object.get());
|
||||
// Connect the ori to the registered object
|
||||
_objectRepository.RegisterLoadedObject(ori, loadedObject);
|
||||
_objectRepository.RegisterLoadedObject(ori, object.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
objects[i] = loadedObject;
|
||||
objects[i] = std::move(object);
|
||||
});
|
||||
|
||||
// Load objects
|
||||
@@ -637,22 +637,23 @@ private:
|
||||
return objects;
|
||||
}
|
||||
|
||||
Object* GetOrLoadObject(const ObjectRepositoryItem* ori)
|
||||
std::unique_ptr<Object> GetOrLoadObject(const ObjectRepositoryItem* ori)
|
||||
{
|
||||
Object* loadedObject = ori->LoadedObject;
|
||||
std::unique_ptr<Object> object;
|
||||
auto loadedObject = ori->LoadedObject;
|
||||
if (loadedObject == nullptr)
|
||||
{
|
||||
// Try to load object
|
||||
loadedObject = _objectRepository.LoadObject(ori);
|
||||
if (loadedObject != nullptr)
|
||||
object = _objectRepository.LoadObject(ori);
|
||||
if (object != nullptr)
|
||||
{
|
||||
loadedObject->Load();
|
||||
object->Load();
|
||||
|
||||
// Connect the ori to the registered object
|
||||
_objectRepository.RegisterLoadedObject(ori, loadedObject);
|
||||
_objectRepository.RegisterLoadedObject(ori, object.get());
|
||||
}
|
||||
}
|
||||
return loadedObject;
|
||||
return object;
|
||||
}
|
||||
|
||||
void ResetTypeToRideEntryIndexMap()
|
||||
@@ -717,18 +718,18 @@ std::unique_ptr<IObjectManager> CreateObjectManager(IObjectRepository& objectRep
|
||||
return std::make_unique<ObjectManager>(objectRepository);
|
||||
}
|
||||
|
||||
void* object_manager_get_loaded_object_by_index(size_t index)
|
||||
Object* object_manager_get_loaded_object_by_index(size_t index)
|
||||
{
|
||||
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
Object* loadedObject = objectManager.GetLoadedObject(index);
|
||||
return static_cast<void*>(loadedObject);
|
||||
return loadedObject;
|
||||
}
|
||||
|
||||
void* object_manager_get_loaded_object(const rct_object_entry* entry)
|
||||
Object* object_manager_get_loaded_object(const rct_object_entry* entry)
|
||||
{
|
||||
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
Object* loadedObject = objectManager.GetLoadedObject(entry);
|
||||
return static_cast<void*>(loadedObject);
|
||||
return loadedObject;
|
||||
}
|
||||
|
||||
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const void* loadedObject)
|
||||
|
||||
Reference in New Issue
Block a user