diff --git a/contributors.md b/contributors.md index 244a5e9921..c56aa370db 100644 --- a/contributors.md +++ b/contributors.md @@ -118,6 +118,7 @@ Appreciation for contributors who have provided substantial work, but are no lon * Wenzhao Qiu (qwzhaox) - Misc. * Tiago Reul (reul) - Misc. * Fredrik Tegnell (fredriktegnell) - Misc. +* Alex Parisi (alex-parisi) - Added API for returning metadata from all registered plugins. ## Bug fixes & Refactors * (KirilAngelov) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index fedf2b08f2..526e594604 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.4.9 (in development) ------------------------------------------------------------------------ +- Feature: [#20709] [Plugin] Plugins can now check metadata from all registered plugins. - Feature: [#21376] Add option to reload an object (for object developers). - Improved: [#21356] Resize the title bar when moving between displays with different scaling factors on Windows systems. - Improved: [#21388] Tooltips will now show even when an error message is present. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index f945bc11d3..4b7e5f28d7 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -56,7 +56,10 @@ declare global { * Plugin writers should check if ui is available using `typeof ui !== 'undefined'`. */ var ui: Ui; - + /** + * APIs for managing the installed plugins + */ + var pluginManager: PluginManager; /** * Registers the plugin. This may only be called once. * @param metadata Information about the plugin and the entry point. @@ -4948,4 +4951,11 @@ declare global { getAllObjects(type: "scenery_group"): SceneryGroupObject[]; getAllObjects(type: "music"): LoadedObject[]; } + + /** + * Interface to handle the plugin manager + */ + interface PluginManager { + readonly plugins: PluginMetadata[]; + } } diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 45e0a69e65..1f942f678b 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -511,6 +511,7 @@ + diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 6211471bc5..8ada7bbb7e 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -34,6 +34,7 @@ # include "bindings/game/ScConsole.hpp" # include "bindings/game/ScContext.hpp" # include "bindings/game/ScDisposable.hpp" +# include "bindings/game/ScPlugin.hpp" # include "bindings/game/ScProfiler.hpp" # include "bindings/network/ScNetwork.hpp" # include "bindings/network/ScPlayer.hpp" @@ -443,6 +444,7 @@ void ScriptEngine::Initialise() ScScenarioObjective::Register(ctx); ScPatrolArea::Register(ctx); ScStaff::Register(ctx); + ScPlugin::Register(ctx); dukglue_register_global(ctx, std::make_shared(), "cheats"); dukglue_register_global(ctx, std::make_shared(), "climate"); @@ -452,6 +454,7 @@ void ScriptEngine::Initialise() dukglue_register_global(ctx, std::make_shared(ctx), "map"); dukglue_register_global(ctx, std::make_shared(ctx), "network"); dukglue_register_global(ctx, std::make_shared(ctx), "park"); + dukglue_register_global(ctx, std::make_shared(), "pluginManager"); dukglue_register_global(ctx, std::make_shared(ctx), "profiler"); dukglue_register_global(ctx, std::make_shared(), "scenario"); dukglue_register_global(ctx, std::make_shared(), "objectManager"); diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index d186007e6b..ba37b88962 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -47,7 +47,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 82; + static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 83; // Versions marking breaking changes. static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33; diff --git a/src/openrct2/scripting/bindings/game/ScPlugin.hpp b/src/openrct2/scripting/bindings/game/ScPlugin.hpp new file mode 100644 index 0000000000..0253b08e56 --- /dev/null +++ b/src/openrct2/scripting/bindings/game/ScPlugin.hpp @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2014-2024 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. + *****************************************************************************/ + +#pragma once + +#ifdef ENABLE_SCRIPTING + +# include "../../Duktape.hpp" +# include "../../ScriptEngine.h" +# include "../game/ScContext.hpp" + +namespace OpenRCT2::Scripting +{ + class ScPlugin + { + public: + static void Register(duk_context* ctx) + { + dukglue_register_property(ctx, &ScPlugin::plugins_get, nullptr, "plugins"); + } + + private: + std::vector plugins_get() + { + auto ctx = getContext(); + auto& allPlugins = getallPlugins(); + return formatMetadata(ctx, allPlugins); + } + + duk_context* getContext() + { + // Get the context from the script engine + OpenRCT2::Scripting::ScriptEngine& scriptEngine = GetContext()->GetScriptEngine(); + return scriptEngine.GetContext(); + } + + const std::vector> getallPlugins() + { + // Get all of the plugins from the script engine + OpenRCT2::Scripting::ScriptEngine& scriptEngine = GetContext()->GetScriptEngine(); + return scriptEngine.GetPlugins(); + } + + const std::vector formatMetadata( + duk_context* ctx, const std::vector>& allPlugins) + { + std::vector formattedMetadata; + duk_idx_t dukIdx = DUK_INVALID_INDEX; + // Iterate through all plugins and and cast their data to Duk objects + for (const auto& pluginPtr : allPlugins) + { + // Pull out metadata + OpenRCT2::Scripting::Plugin& plugin = *pluginPtr; + OpenRCT2::Scripting::PluginMetadata metadata = plugin.GetMetadata(); + // Create object using Duk stack + dukIdx = duk_push_object(ctx); + // Name and Version + duk_push_string(ctx, metadata.Name.c_str()); + duk_put_prop_string(ctx, dukIdx, "name"); + duk_push_string(ctx, metadata.Version.c_str()); + duk_put_prop_string(ctx, dukIdx, "version"); + // Authors + duk_idx_t arrIdx = duk_push_array(ctx); + for (auto [s, idx] = std::tuple{ metadata.Authors.begin(), 0 }; s != metadata.Authors.end(); s++, idx++) + { + auto& str = *s; + duk_push_string(ctx, str.c_str()); + duk_put_prop_index(ctx, arrIdx, idx); + } + duk_put_prop_string(ctx, dukIdx, "authors"); + // Take from Duk stack + formattedMetadata.push_back(DukValue::take_from_stack(ctx, dukIdx)); + dukIdx = DUK_INVALID_INDEX; + } + return formattedMetadata; + } + }; +} // namespace OpenRCT2::Scripting + +#endif