From 76cc04d044f33c6f3505e22e0d1d9a77bd2ae873 Mon Sep 17 00:00:00 2001 From: ZeroBreakpoint <147563748+ZeroBreakpoint@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:18:23 +1000 Subject: [PATCH] Fix crash in map.getAllEntities("car") when car has an invalid ride --- distribution/changelog.txt | 1 + src/openrct2/scripting/ScriptEngine.h | 2 +- .../scripting/bindings/world/ScMap.cpp | 42 ++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 2ada4a317c..9b9a2b898c 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -7,6 +7,7 @@ - Change: [#24069] [Plugin] Plugins are now available in the scenario editor and track designer. - Change: [#24135] Compress Emscripten js/wasm files. - Fix: [#21919] Non-recolourable cars still show colour picker. +- Fix: [#22182] [Plugin] Crash when using map.getAllEntities("car"). - Fix: [#23108] Missing pieces on Hypercoaster and Hyper-Twister, even with the ‘all drawable track pieces’ cheat enabled. - Fix: [#24013] Failure to load a scenario preview image (minimap) could lead to an uncaught exception error message. - Fix: [#24121] Checkbox labels run beyond the edge of the window if they’re too long to fit. diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index cb2d5ea36f..b7a10f1746 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t kPluginApiVersion = 105; + static constexpr int32_t kPluginApiVersion = 106; // Versions marking breaking changes. static constexpr int32_t kApiVersionPeepDeprecation = 33; diff --git a/src/openrct2/scripting/bindings/world/ScMap.cpp b/src/openrct2/scripting/bindings/world/ScMap.cpp index 217d66cee4..fdbd34ce8c 100644 --- a/src/openrct2/scripting/bindings/world/ScMap.cpp +++ b/src/openrct2/scripting/bindings/world/ScMap.cpp @@ -118,8 +118,22 @@ namespace OpenRCT2::Scripting for (auto carId = trainHead->Id; !carId.IsNull();) { auto car = GetEntity(carId); + + if (car == nullptr) + { + break; + } + result.push_back(GetObjectAsDukValue(_context, std::make_shared(carId))); - carId = car->next_vehicle_on_train; + + // Prevent infinite loops: Ensure next_vehicle_on_train is valid and not self-referencing + auto nextCarId = car->next_vehicle_on_train; + if (nextCarId == carId) + { + break; + } + + carId = nextCarId; } } } @@ -311,7 +325,31 @@ namespace OpenRCT2::Scripting DukValue res; if (type == "car") { - res = createEntityType(_context, initializer); + Vehicle* entity = CreateEntity(); + if (entity == nullptr) + { + // Probably no more space for entities for this specified entity type. + res = ToDuk(_context, undefined); + } + else + { + auto entityPos = CoordsXYZ{ AsOrDefault(initializer["x"], 0), AsOrDefault(initializer["y"], 0), + AsOrDefault(initializer["z"], 0) }; + entity->MoveTo(entityPos); + + // Reset some important vehicle vars to their null values + entity->sound1_id = OpenRCT2::Audio::SoundId::Null; + entity->sound2_id = OpenRCT2::Audio::SoundId::Null; + entity->next_vehicle_on_train = EntityId::GetNull(); + entity->scream_sound_id = OpenRCT2::Audio::SoundId::Null; + for (size_t i = 0; i < std::size(entity->peep); i++) + { + entity->peep[i] = EntityId::GetNull(); + } + entity->BoatLocation.SetNull(); + + res = GetObjectAsDukValue(_context, std::make_shared(entity->Id)); + } } else if (type == "staff") {