From 0a3e9fdfd930654e1fe30d313261af1f7988b26a Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Thu, 20 Mar 2025 00:16:08 +0100 Subject: [PATCH] Update object manager API to access new object types (#24009) * Update object manager API to access new object types * Use separate mapping for scripting due to different type names * Amend changelog --- distribution/changelog.txt | 1 + distribution/openrct2.d.ts | 9 ++- src/openrct2/libopenrct2.vcxproj | 53 +++++++------- src/openrct2/object/ObjectFactory.cpp | 73 +++++++------------ .../bindings/object/ScInstalledObject.cpp | 53 ++++++++++++++ .../bindings/object/ScInstalledObject.hpp | 30 +------- .../scripting/bindings/object/ScObject.hpp | 15 +--- .../bindings/object/ScObjectManager.cpp | 24 +++--- .../scripting/bindings/world/ScResearch.cpp | 6 +- 9 files changed, 134 insertions(+), 130 deletions(-) create mode 100644 src/openrct2/scripting/bindings/object/ScInstalledObject.cpp diff --git a/distribution/changelog.txt b/distribution/changelog.txt index bf0bb67fb1..3779404d92 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -23,6 +23,7 @@ - Fix: [#23960] Corner path fences can draw over adjacent sloped land (original bug). - Fix: [#23961] Lamps and queue line tvs draw incorrectly on paths with fences. - Fix: [#23983] Ordering files by size does not work and occasionally crashes the game. +- Fix: [#24009] [Plugin] The object manager API does not identify recently introduced object types. 0.4.20 (2025-02-25) ------------------------------------------------------------------------ diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index e9e4241336..e20c702ef0 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -620,12 +620,17 @@ declare global { "scenery_group" | "park_entrance" | "water" | + "scenario_text" | "terrain_surface" | "terrain_edge" | "station" | "music" | "footpath_surface" | - "footpath_railings"; + "footpath_railings" | + "audio" | + "peep_names" | + "peep_animations" | + "climate"; type HookType = "action.execute" | @@ -5362,7 +5367,6 @@ declare global { getObject(type: "footpath_addition", index: number): FootpathAdditionObject; getObject(type: "banner", index: number): BannerObject; getObject(type: "scenery_group", index: number): SceneryGroupObject; - getObject(type: "music", index: number): LoadedObject; /** * Gets all the currently loaded objects for a given object type. @@ -5376,7 +5380,6 @@ declare global { getAllObjects(type: "footpath_addition"): FootpathAdditionObject[]; getAllObjects(type: "banner"): BannerObject[]; getAllObjects(type: "scenery_group"): SceneryGroupObject[]; - getAllObjects(type: "music"): LoadedObject[]; } /** diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 0cc1a5d7a6..ca356e22bb 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -560,45 +560,45 @@ + - - - - - - - - - - - - - - - - - - - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -1095,6 +1095,7 @@ + @@ -1152,4 +1153,4 @@ - \ No newline at end of file + diff --git a/src/openrct2/object/ObjectFactory.cpp b/src/openrct2/object/ObjectFactory.cpp index 627c3e901e..46f9b10e2b 100644 --- a/src/openrct2/object/ObjectFactory.cpp +++ b/src/openrct2/object/ObjectFactory.cpp @@ -15,6 +15,7 @@ #include "../PlatformEnvironment.h" #include "../audio/Audio.h" #include "../core/Console.hpp" +#include "../core/EnumMap.hpp" #include "../core/File.h" #include "../core/FileStream.h" #include "../core/Json.hpp" @@ -404,50 +405,29 @@ namespace OpenRCT2::ObjectFactory return result; } - static ObjectType ParseObjectType(const std::string& s) - { - if (s == "ride") - return ObjectType::ride; - if (s == "footpath_banner") - return ObjectType::banners; - if (s == "footpath_item") - return ObjectType::pathAdditions; - if (s == "scenery_small") - return ObjectType::smallScenery; - if (s == "scenery_large") - return ObjectType::largeScenery; - if (s == "scenery_wall") - return ObjectType::walls; - if (s == "scenery_group") - return ObjectType::sceneryGroup; - if (s == "park_entrance") - return ObjectType::parkEntrance; - if (s == "water") - return ObjectType::water; - if (s == "scenario_text") - return ObjectType::scenarioText; - if (s == "terrain_surface") - return ObjectType::terrainSurface; - if (s == "terrain_edge") - return ObjectType::terrainEdge; - if (s == "station") - return ObjectType::station; - if (s == "music") - return ObjectType::music; - if (s == "footpath_surface") - return ObjectType::footpathSurface; - if (s == "footpath_railings") - return ObjectType::footpathRailings; - if (s == "audio") - return ObjectType::audio; - if (s == "peep_names") - return ObjectType::peepNames; - if (s == "peep_animations") - return ObjectType::peepAnimations; - if (s == "climate") - return ObjectType::climate; - return ObjectType::none; - } + static const EnumMap kObjectTypeMap = { + { "ride", ObjectType::ride }, + { "scenery_small", ObjectType::smallScenery }, + { "scenery_large", ObjectType::largeScenery }, + { "scenery_wall", ObjectType::walls }, + { "footpath_banner", ObjectType::banners }, + { "footpath_legacy", ObjectType::paths }, + { "footpath_item", ObjectType::pathAdditions }, + { "scenery_group", ObjectType::sceneryGroup }, + { "park_entrance", ObjectType::parkEntrance }, + { "water", ObjectType::water }, + { "scenario_text", ObjectType::scenarioText }, + { "terrain_surface", ObjectType::terrainSurface }, + { "terrain_edge", ObjectType::terrainEdge }, + { "station", ObjectType::station }, + { "music", ObjectType::music }, + { "footpath_surface", ObjectType::footpathSurface }, + { "footpath_railings", ObjectType::footpathRailings }, + { "audio", ObjectType::audio }, + { "peep_names", ObjectType::peepNames }, + { "peep_animations", ObjectType::peepAnimations }, + { "climate", ObjectType::climate }, + }; std::unique_ptr CreateObjectFromZipFile(IObjectRepository& objectRepository, std::string_view path, bool loadImages) { @@ -544,9 +524,10 @@ namespace OpenRCT2::ObjectFactory std::unique_ptr result; - auto objectType = ParseObjectType(Json::GetString(jRoot["objectType"])); - if (objectType != ObjectType::none) + auto lookup = kObjectTypeMap.find(Json::GetString(jRoot["objectType"])); + if (lookup != kObjectTypeMap.end()) { + auto objectType = lookup->second; auto id = Json::GetString(jRoot["id"]); // Base audio files are renamed to a common, virtual name so asset packs can override it correctly. diff --git a/src/openrct2/scripting/bindings/object/ScInstalledObject.cpp b/src/openrct2/scripting/bindings/object/ScInstalledObject.cpp new file mode 100644 index 0000000000..c4aa54b430 --- /dev/null +++ b/src/openrct2/scripting/bindings/object/ScInstalledObject.cpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * Copyright (c) 2014-2025 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#ifdef ENABLE_SCRIPTING + + #include "ScObject.hpp" + +namespace OpenRCT2::Scripting +{ + static const EnumMap kObjectTypeMap = { + { "ride", ObjectType::ride }, + { "small_scenery", ObjectType::smallScenery }, + { "large_scenery", ObjectType::largeScenery }, + { "wall", ObjectType::walls }, + { "banner", ObjectType::banners }, + { "footpath", ObjectType::paths }, + { "footpath_addition", ObjectType::pathAdditions }, + { "scenery_group", ObjectType::sceneryGroup }, + { "park_entrance", ObjectType::parkEntrance }, + { "water", ObjectType::water }, + { "scenario_text", ObjectType::scenarioText }, + { "terrain_surface", ObjectType::terrainSurface }, + { "terrain_edge", ObjectType::terrainEdge }, + { "station", ObjectType::station }, + { "music", ObjectType::music }, + { "footpath_surface", ObjectType::footpathSurface }, + { "footpath_railings", ObjectType::footpathRailings }, + { "audio", ObjectType::audio }, + { "peep_names", ObjectType::peepNames }, + { "peep_animations", ObjectType::peepAnimations }, + { "climate", ObjectType::climate }, + }; + + std::string_view objectTypeToString(ObjectType type) + { + auto result = kObjectTypeMap.find(type); + return result != kObjectTypeMap.end() ? result->first : ""; + } + + ObjectType objectTypeFromString(std::string_view string) + { + auto result = kObjectTypeMap.find(string); + return result != kObjectTypeMap.end() ? result->second : ObjectType::none; + } +} // namespace OpenRCT2::Scripting + +#endif diff --git a/src/openrct2/scripting/bindings/object/ScInstalledObject.hpp b/src/openrct2/scripting/bindings/object/ScInstalledObject.hpp index 553d178a42..7fa8bd2da1 100644 --- a/src/openrct2/scripting/bindings/object/ScInstalledObject.hpp +++ b/src/openrct2/scripting/bindings/object/ScInstalledObject.hpp @@ -17,34 +17,12 @@ #include "../../ScriptEngine.h" #include + #include namespace OpenRCT2::Scripting { - inline std::string_view ObjectTypeToString(uint8_t type) - { - static constexpr std::string_view Types[] = { - "ride", - "small_scenery", - "large_scenery", - "wall", - "banner", - "footpath", - "footpath_addition", - "scenery_group", - "park_entrance", - "water", - "stex", - "terrain_surface", - "terrain_edge", - "station", - "music", - "footpath_surface", - "footpath_railings", - }; - if (type >= std::size(Types)) - return "unknown"; - return Types[type]; - } + std::string_view objectTypeToString(ObjectType type); + ObjectType objectTypeFromString(std::string_view string); inline std::string_view ObjectSourceGameToString(ObjectSourceGame sourceGame) { @@ -122,7 +100,7 @@ namespace OpenRCT2::Scripting auto installedObject = GetInstalledObject(); if (installedObject != nullptr) { - return std::string(ObjectTypeToString(EnumValue(installedObject->Type))); + return std::string(objectTypeToString(installedObject->Type)); } return {}; } diff --git a/src/openrct2/scripting/bindings/object/ScObject.hpp b/src/openrct2/scripting/bindings/object/ScObject.hpp index 440cc8f6c3..e11bf731cd 100644 --- a/src/openrct2/scripting/bindings/object/ScObject.hpp +++ b/src/openrct2/scripting/bindings/object/ScObject.hpp @@ -51,19 +51,6 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &ScObject::numImages_get, nullptr, "numImages"); } - static std::optional StringToObjectType(std::string_view type) - { - for (uint8_t i = 0; i < EnumValue(ObjectType::count); i++) - { - auto s = ObjectTypeToString(i); - if (s == type) - { - return static_cast(i); - } - } - return std::nullopt; - } - private: std::shared_ptr installedObject_get() const { @@ -82,7 +69,7 @@ namespace OpenRCT2::Scripting std::string type_get() const { - return std::string(ObjectTypeToString(EnumValue(_type))); + return std::string(objectTypeToString(_type)); } int32_t index_get() const diff --git a/src/openrct2/scripting/bindings/object/ScObjectManager.cpp b/src/openrct2/scripting/bindings/object/ScObjectManager.cpp index 1fad4ad1f3..bab6a27f9b 100644 --- a/src/openrct2/scripting/bindings/object/ScObjectManager.cpp +++ b/src/openrct2/scripting/bindings/object/ScObjectManager.cpp @@ -157,15 +157,15 @@ void ScObjectManager::unload(const DukValue& p1, const DukValue& p2) if (p1.type() == DukValue::STRING) { const auto& szP1 = p1.as_string(); - auto objType = ScObject::StringToObjectType(szP1); - if (objType) + auto objType = objectTypeFromString(szP1); + if (objType != ObjectType::none) { // unload(type, index) if (p2.type() != DukValue::NUMBER) throw DukException() << "'index' is invalid."; auto objIndex = p2.as_uint(); - auto obj = objectManager.GetLoadedObject(*objType, objIndex); + auto obj = objectManager.GetLoadedObject(objType, objIndex); if (obj != nullptr) { objectManager.UnloadObjects({ obj->GetDescriptor() }); @@ -198,13 +198,13 @@ DukValue ScObjectManager::getObject(const std::string& typez, int32_t index) con auto ctx = GetContext()->GetScriptEngine().GetContext(); auto& objManager = GetContext()->GetObjectManager(); - auto type = ScObject::StringToObjectType(typez); - if (type) + auto type = objectTypeFromString(typez); + if (type != ObjectType::none) { - auto obj = objManager.GetLoadedObject(*type, index); + auto obj = objManager.GetLoadedObject(type, index); if (obj != nullptr) { - return CreateScObject(ctx, *type, index); + return CreateScObject(ctx, type, index); } } else @@ -220,16 +220,16 @@ std::vector ScObjectManager::getAllObjects(const std::string& typez) c auto& objManager = GetContext()->GetObjectManager(); std::vector result; - auto type = ScObject::StringToObjectType(typez); - if (type) + auto type = objectTypeFromString(typez); + if (type != ObjectType::none) { - auto count = getObjectEntryGroupCount(*type); + auto count = getObjectEntryGroupCount(type); for (auto i = 0u; i < count; i++) { - auto obj = objManager.GetLoadedObject(*type, i); + auto obj = objManager.GetLoadedObject(type, i); if (obj != nullptr) { - result.push_back(CreateScObject(ctx, *type, i)); + result.push_back(CreateScObject(ctx, type, i)); } } } diff --git a/src/openrct2/scripting/bindings/world/ScResearch.cpp b/src/openrct2/scripting/bindings/world/ScResearch.cpp index 6936d31831..f58c5a6db8 100644 --- a/src/openrct2/scripting/bindings/world/ScResearch.cpp +++ b/src/openrct2/scripting/bindings/world/ScResearch.cpp @@ -233,10 +233,10 @@ namespace OpenRCT2::Scripting bool ScResearch::isObjectResearched(const std::string& typez, ObjectEntryIndex index) { auto result = false; - auto type = ScObject::StringToObjectType(typez); - if (type) + auto type = objectTypeFromString(typez); + if (type != ObjectType::none) { - result = ResearchIsInvented(*type, index); + result = ResearchIsInvented(type, index); } else {