From 7ee49d8f2b5c8f88c1c0a16c6e2f8575c893f364 Mon Sep 17 00:00:00 2001 From: mix Date: Sun, 25 May 2025 21:37:58 +0100 Subject: [PATCH] Fix #23289: Dodgems and Flying Saucers can spawn on top of each other --- distribution/changelog.txt | 1 + src/openrct2/entity/EntityBase.h | 2 ++ src/openrct2/entity/EntityRegistry.cpp | 29 ++++++++++++++++++-------- src/openrct2/ride/Ride.cpp | 2 +- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 2cad08f413..bcfbf5c697 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -18,6 +18,7 @@ - Fix: [#5269] Font bugs when using the Russian release of RCT2 as the base game. - Fix: [#11071, #22958] The virtual floor does not always draw correctly. - Fix: [#20158] Custom animated scenery .DATs with frame offsets draw a random sprite at the end of their animation. +- 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. - Fix: [#24353] ‘Show dirty visuals’ is off by one pixel and does not work correctly with higher framerates. diff --git a/src/openrct2/entity/EntityBase.h b/src/openrct2/entity/EntityBase.h index 77b887aff2..56918a6006 100644 --- a/src/openrct2/entity/EntityBase.h +++ b/src/openrct2/entity/EntityBase.h @@ -54,6 +54,8 @@ struct EntityBase */ void MoveTo(const CoordsXYZ& newLocation); + void MoveToAndUpdateSpatialIndex(const CoordsXYZ& newLocation); + /** * Sets the entity location without screen invalidation. */ diff --git a/src/openrct2/entity/EntityRegistry.cpp b/src/openrct2/entity/EntityRegistry.cpp index c9e8802052..89474dc7e3 100644 --- a/src/openrct2/entity/EntityRegistry.cpp +++ b/src/openrct2/entity/EntityRegistry.cpp @@ -448,6 +448,18 @@ static void EntitySpatialRemove(EntityBase& entity) entity.SpatialIndex = kInvalidSpatialIndex; } +static void UpdateEntitySpatialIndex(EntityBase& entity) +{ + if (entity.SpatialIndex & kSpatialIndexDirtyMask) + { + if (entity.SpatialIndex != kInvalidSpatialIndex) + { + EntitySpatialRemove(entity); + } + EntitySpatialInsert(entity, { entity.x, entity.y }); + } +} + void UpdateEntitiesSpatialIndex() { for (auto& entityList : gEntityLists) @@ -455,16 +467,9 @@ void UpdateEntitiesSpatialIndex() for (auto& entityId : entityList) { auto* entity = TryGetEntity(entityId); - if (entity == nullptr || entity->Type == EntityType::Null) - continue; - - if (entity->SpatialIndex & kSpatialIndexDirtyMask) + if (entity != nullptr && entity->Type != EntityType::Null) { - if (entity->SpatialIndex != kInvalidSpatialIndex) - { - EntitySpatialRemove(*entity); - } - EntitySpatialInsert(*entity, { entity->x, entity->y }); + UpdateEntitySpatialIndex(*entity); } } } @@ -538,6 +543,12 @@ void EntityBase::MoveTo(const CoordsXYZ& newLocation) } } +void EntityBase::MoveToAndUpdateSpatialIndex(const CoordsXYZ& newLocation) +{ + MoveTo(newLocation); + UpdateEntitySpatialIndex(*this); +} + /** * Frees any dynamically attached memory to the entity, such as peep name. */ diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 1f96f2a96d..0e6a4f49f1 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -3308,7 +3308,7 @@ static Vehicle* VehicleCreateCar( chosenLoc.x = dodgemPos.x + (ScenarioRand() & 0xFF); } while (vehicle->DodgemsCarWouldCollideAt(chosenLoc).has_value()); - vehicle->MoveTo({ chosenLoc, dodgemPos.z }); + vehicle->MoveToAndUpdateSpatialIndex({ chosenLoc, dodgemPos.z }); } else {