From 60f5d5c8a5aa00250f9a70a43e73f2a3f0ee6f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Fri, 31 May 2024 21:21:17 +0200 Subject: [PATCH 1/4] Refactoring of game features for better management. --- src/CMakeLists.txt | 1 + src/game_features/bsainvalidation.h | 17 ++-- src/game_features/dataarchives.h | 14 +-- src/game_features/game_feature.h | 37 +++++++ src/game_features/gameplugins.h | 14 +-- src/game_features/localsavegames.h | 12 +-- src/game_features/moddatachecker.h | 16 ++- src/game_features/moddatacontent.h | 16 ++- src/game_features/savegameinfo.h | 23 ++--- src/game_features/scriptextender.h | 13 ++- src/game_features/unmanagedmods.h | 13 ++- src/imoinfo.h | 150 +++++++++++++++++++++++++++- src/iplugingame.h | 23 ----- src/iplugingamefeatures.h | 61 +++++++++++ 14 files changed, 315 insertions(+), 95 deletions(-) create mode 100644 src/game_features/game_feature.h create mode 100644 src/iplugingamefeatures.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28f3101d..6f69635c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ mo2_add_filter(NAME src/interfaces GROUPS iplugindiagnose ipluginfilemapper iplugingame + iplugingamefeatures iplugininstaller iplugininstallercustom iplugininstallersimple diff --git a/src/game_features/bsainvalidation.h b/src/game_features/bsainvalidation.h index 555c44ee..926753d6 100644 --- a/src/game_features/bsainvalidation.h +++ b/src/game_features/bsainvalidation.h @@ -1,18 +1,17 @@ -#ifndef BSAINVALIDATION_H -#define BSAINVALIDATION_H +#ifndef UIBASE_GAMEFEATURES_BSAINVALIDATION_H +#define UIBASE_GAMEFEATURES_BSAINVALIDATION_H + +#include + +#include "./game_feature.h" namespace MOBase { class IProfile; -} - -class QString; -class BSAInvalidation +class BSAInvalidation : public details::GameFeatureCRTP { public: - virtual ~BSAInvalidation() {} - virtual bool isInvalidationBSA(const QString& bsaName) = 0; virtual void deactivate(MOBase::IProfile* profile) = 0; @@ -22,4 +21,6 @@ class BSAInvalidation virtual bool prepareProfile(MOBase::IProfile* profile) = 0; }; +} // namespace MOBase + #endif // BSAINVALIDATION_H diff --git a/src/game_features/dataarchives.h b/src/game_features/dataarchives.h index 8fc00ba8..65c1419f 100644 --- a/src/game_features/dataarchives.h +++ b/src/game_features/dataarchives.h @@ -1,20 +1,18 @@ -#ifndef DATAARCHIVES -#define DATAARCHIVES +#ifndef UIBASE_GAMEFEATURES_DATAARCHIVES_H +#define UIBASE_GAMEFEATURES_DATAARCHIVES_H #include #include +#include "./game_feature.h" + namespace MOBase { class IProfile; -} -class DataArchives +class DataArchives : public details::GameFeatureCRTP { - public: - virtual ~DataArchives() {} - virtual QStringList vanillaArchives() const = 0; virtual QStringList archives(const MOBase::IProfile* profile) const = 0; @@ -32,4 +30,6 @@ class DataArchives virtual void removeArchive(MOBase::IProfile* profile, const QString& archiveName) = 0; }; +} // namespace MOBase + #endif // DATAARCHIVES diff --git a/src/game_features/game_feature.h b/src/game_features/game_feature.h new file mode 100644 index 00000000..fca6f846 --- /dev/null +++ b/src/game_features/game_feature.h @@ -0,0 +1,37 @@ +#ifndef UIBASE_GAMEFEATURES_GAMEFEATURE_H +#define UIBASE_GAMEFEATURES_GAMEFEATURE_H + +#include + +namespace MOBase +{ + +/** + * Empty class that is inherit by all game features. + */ +class GameFeature +{ +public: + GameFeature() = default; + virtual ~GameFeature() = 0 {} + + /** + * @brief Retrieve the type index of the main game feature this feature extends. + */ + virtual const std::type_info& typeInfo() const = 0; +}; + +namespace details +{ + + template + class GameFeatureCRTP : public GameFeature + { + const std::type_info& typeInfo() const final { return typeid(T); } + }; + +} // namespace details + +} // namespace MOBase + +#endif diff --git a/src/game_features/gameplugins.h b/src/game_features/gameplugins.h index 4db6de64..9ad29a23 100644 --- a/src/game_features/gameplugins.h +++ b/src/game_features/gameplugins.h @@ -1,19 +1,17 @@ -#ifndef GAMEPLUGINS_H -#define GAMEPLUGINS_H +#ifndef UIBASE_GAMEFEATURES_GAMEPLUGINS_H +#define UIBASE_GAMEFEATURES_GAMEPLUGINS_H #include +#include "./game_feature.h" + namespace MOBase { class IPluginList; -} -class GamePlugins +class GamePlugins : public details::GameFeatureCRTP { - public: - virtual ~GamePlugins() {} - virtual void writePluginLists(const MOBase::IPluginList* pluginList) = 0; virtual void readPluginLists(MOBase::IPluginList* pluginList) = 0; virtual QStringList getLoadOrder() = 0; @@ -21,4 +19,6 @@ class GamePlugins virtual bool overridePluginsAreSupported() = 0; }; +} // namespace MOBase + #endif // GAMEPLUGINS_H diff --git a/src/game_features/localsavegames.h b/src/game_features/localsavegames.h index 5b2d66fc..2db6a4e2 100644 --- a/src/game_features/localsavegames.h +++ b/src/game_features/localsavegames.h @@ -1,23 +1,21 @@ -#ifndef LOCALSAVEGAMES_H -#define LOCALSAVEGAMES_H +#ifndef UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H +#define UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H #include +#include "./game_feature.h" #include "filemapping.h" namespace MOBase { class IProfile; -} -class LocalSavegames +class LocalSavegames : public details::GameFeatureCRTP { - public: - virtual ~LocalSavegames() {} - virtual MappingType mappings(const QDir& profileSaveDir) const = 0; virtual bool prepareProfile(MOBase::IProfile* profile) = 0; }; +} // namespace MOBase #endif // LOCALSAVEGAMES_H diff --git a/src/game_features/moddatachecker.h b/src/game_features/moddatachecker.h index d466a07b..4c95f79d 100644 --- a/src/game_features/moddatachecker.h +++ b/src/game_features/moddatachecker.h @@ -1,14 +1,15 @@ -#ifndef MODDATACHECKER_H -#define MODDATACHECKER_H +#ifndef UIBASE_GAMEFEATURES_MODDATACHECKER_H +#define UIBASE_GAMEFEATURES_MODDATACHECKER_H #include +#include "./game_feature.h" + namespace MOBase { class IFileTree; -} -class ModDataChecker +class ModDataChecker : public details::GameFeatureCRTP { public: /** @@ -59,12 +60,7 @@ class ModDataChecker { return nullptr; } - -public: - /** - * - */ - virtual ~ModDataChecker() {} }; +} // namespace MOBase #endif diff --git a/src/game_features/moddatacontent.h b/src/game_features/moddatacontent.h index cf25ab30..b86527c4 100644 --- a/src/game_features/moddatacontent.h +++ b/src/game_features/moddatacontent.h @@ -1,5 +1,5 @@ -#ifndef MODDATACONTENT_H -#define MODDATACONTENT_H +#ifndef UIBASE_GAMEFEATURES_MODDATACONTENT_H +#define UIBASE_GAMEFEATURES_MODDATACONTENT_H #include #include @@ -7,10 +7,11 @@ #include +#include "./game_feature.h" + namespace MOBase { class IFileTree; -} /** * The ModDataContent feature is used (when available) to indicate to users the content @@ -55,7 +56,7 @@ class IFileTree; * - modgroup: * https://github.com/ModOrganizer2/modorganizer/blob/master/src/resources/contents/xedit.png */ -class ModDataContent +class ModDataContent : public details::GameFeatureCRTP { public: struct Content @@ -115,12 +116,7 @@ class ModDataContent */ virtual std::vector getContentsFor(std::shared_ptr fileTree) const = 0; - -public: - /** - * - */ - virtual ~ModDataContent() {} }; +} // namespace MOBase #endif diff --git a/src/game_features/savegameinfo.h b/src/game_features/savegameinfo.h index 588f896b..b5ea2160 100644 --- a/src/game_features/savegameinfo.h +++ b/src/game_features/savegameinfo.h @@ -1,22 +1,20 @@ -#ifndef SAVEGAMEINFO_H -#define SAVEGAMEINFO_H - -namespace MOBase -{ -class ISaveGame; -} -namespace MOBase -{ -class ISaveGameInfoWidget; -} +#ifndef UIBASE_GAMEFEATURES_SAVEGAMEINFO_H +#define UIBASE_GAMEFEATURES_SAVEGAMEINFO_H #include #include #include #include +#include "./game_feature.h" + +namespace MOBase +{ +class ISaveGame; +class ISaveGameInfoWidget; + /** Feature to get hold of stuff to do with save games */ -class SaveGameInfo +class SaveGameInfo : public details::GameFeatureCRTP { public: virtual ~SaveGameInfo() {} @@ -49,5 +47,6 @@ class SaveGameInfo */ virtual MOBase::ISaveGameInfoWidget* getSaveGameWidget(QWidget* parent = 0) const = 0; }; +} // namespace MOBase #endif // SAVEGAMEINFO_H diff --git a/src/game_features/scriptextender.h b/src/game_features/scriptextender.h index 0eb148f6..0453f1db 100644 --- a/src/game_features/scriptextender.h +++ b/src/game_features/scriptextender.h @@ -1,12 +1,17 @@ -#ifndef SCRIPTEXTENDER -#define SCRIPTEXTENDER +#ifndef UIBASE_GAMEFEATURES_SCRIPTEXTENDER +#define UIBASE_GAMEFEATURES_SCRIPTEXTENDER #include #include #include -class ScriptExtender +#include "./game_feature.h" + +namespace MOBase +{ + +class ScriptExtender : public details::GameFeatureCRTP { public: @@ -37,4 +42,6 @@ class ScriptExtender virtual WORD getArch() const = 0; }; +} // namespace MOBase + #endif // SCRIPTEXTENDER diff --git a/src/game_features/unmanagedmods.h b/src/game_features/unmanagedmods.h index cc59d022..6eeb8a7e 100644 --- a/src/game_features/unmanagedmods.h +++ b/src/game_features/unmanagedmods.h @@ -1,14 +1,17 @@ -#ifndef UNMANAGEDMODS_H -#define UNMANAGEDMODS_H +#ifndef UIBASE_GAMEFEATURES_UNMANAGEDMODS_H +#define UIBASE_GAMEFEATURES_UNMANAGEDMODS_H #include #include #include -class UnmanagedMods +#include "./game_feature.h" + +namespace MOBase { -public: +class UnmanagedMods : public details::GameFeatureCRTP +{ public: virtual ~UnmanagedMods() {} @@ -37,4 +40,6 @@ class UnmanagedMods virtual QStringList secondaryFiles(const QString& modName) const = 0; }; +} // namespace MOBase + #endif // UNMANAGEDMODS_H diff --git a/src/imoinfo.h b/src/imoinfo.h index 7a85e62b..3a7c3974 100644 --- a/src/imoinfo.h +++ b/src/imoinfo.h @@ -27,8 +27,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include +#include "game_feature.h" #include "guessedvalue.h" #include "imodlist.h" #include "iprofile.h" @@ -45,6 +47,141 @@ class IPluginList; class IPlugin; class IPluginGame; +// top-level game features +class BSAInvalidation; +class DataArchives; +class GamePlugins; +class LocalSavegames; +class ModDataChecker; +class ModDataContent; +class SaveGameInfo; +class ScriptExtender; +class UnmanagedMods; + +template +concept BaseGameFeature = requires(T) { + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v; +}; + +/** + * @brief Interface to game features. + * + */ +class IGameFeatures +{ +public: + /** + * @brief Register game feature for the specified game. + * + * This method register a game feature to combine or replace the same feature provided + * by the game. Some features are merged (e.g., ModDataContent, ModDataChecker), while + * other override previous features (e.g., SaveGameInfo). + * + * For features that can be combined, the priority argument indicates the order of + * priority (e.g., the order of the checks for ModDataChecker). For other features, + * the feature with the highest priority will be used. The features provided by the + * game plugin itself always have lowest priority. + * + * The feature is associated to the plugin that registers it, if the plugin is + * disabled, the feature will not be available. + * + * This function will return True if the feature was registered, even if the feature + * is not used du to its low priority. + * + * @param games Names of the game to enable the feature for. + * @param feature Game feature to register. + * @param priority Priority of the game feature. If the plugin registering the feature + * is a game plugin, this parameter is ignored. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(QStringList const& games, + std::shared_ptr feature, int priority, + bool replace = false) = 0; + + /** + * @brief Register game feature for the specified game. + * + * See first overload for more details. + * + * @param game Game to enable the feature for. + * @param feature Game feature to register. + * @param priority Priority of the game feature. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(IPluginGame* game, std::shared_ptr feature, + int priority, bool replace = false) = 0; + + /** + * @brief Register game feature for all games. + * + * See first overload for more details. + * + * @param feature Game feature to register. + * @param priority Priority of the game feature. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(std::shared_ptr feature, int priority, + bool replace = false) = 0; + + /** + * @brief Unregister the given game feature. + * + * This function is safe to use even if the feature was not registered before. + * + * @param feature Feature to unregister. + */ + virtual bool unregisterFeature(std::shared_ptr feature) = 0; + + /** + * @brief Unregister all features of the given type registered by the calling plugin. + * + * This function is safe to use even if the plugin has no feature of the given type + * register. + * + * @return the number of features unregistered. + * + * @tparam Feature Type of game feature to remove. + */ + template + int unregisterFeatures() + { + unregisterFeaturesImpl(typeid(Feature)); + } + + /** + * Retrieve the given game feature, if one exists. + * + * @return the feature of the given type, if one exists, otherwise a null pointer. + */ + template + T* gameFeature() const + { + // gameFeatureImpl ensure that the returned pointer is of the right type (or + // nullptr), so reinterpret_cast should be fine here + return dynamic_cast(gameFeatureImpl(typeid(T))); + } + +public: + virtual ~IGameFeatures() = default; + +protected: + virtual GameFeature* gameFeatureImpl(std::type_info const& info) const = 0; + virtual int unregisterFeaturesImpl(std::type_info const& info) = 0; +}; + /** * @brief Interface to class that provides information about the running session * of Mod Organizer to be used by plugins @@ -302,22 +439,27 @@ class QDLLEXPORT IOrganizer : public QObject /** * @return interface to the download manager */ - virtual MOBase::IDownloadManager* downloadManager() const = 0; + virtual IDownloadManager* downloadManager() const = 0; /** * @return interface to the list of plugins (esps, esms, and esls) */ - virtual MOBase::IPluginList* pluginList() const = 0; + virtual IPluginList* pluginList() const = 0; /** * @return interface to the list of mods */ - virtual MOBase::IModList* modList() const = 0; + virtual IModList* modList() const = 0; /** * @return interface to the active profile */ - virtual MOBase::IProfile* profile() const = 0; + virtual IProfile* profile() const = 0; + + /** + * @return interface to game features. + */ + virtual IGameFeatures* gameFeatures() const = 0; /** * @brief runs a program using the virtual filesystem diff --git a/src/iplugingame.h b/src/iplugingame.h index df5de5b4..a191e646 100644 --- a/src/iplugingame.h +++ b/src/iplugingame.h @@ -93,26 +93,6 @@ class IPluginGame : public QObject, public IPlugin */ virtual QString displayGameName() const { return gameName(); } - template - T* feature() const - { - auto list = featureList(); - auto iter = list.find(typeid(T)); - if (iter != list.end()) { - try { - return std::any_cast(iter->second); - } catch (const std::bad_any_cast&) { - // don't use log::error() here so log.h and fmt aren't pulled into - // plugins - qCritical("failed to retrieve feature type %s (got %s)", typeid(T).name(), - typeid(iter->second).name()); - return nullptr; - } - } else { - return nullptr; - } - } - /** * @brief Detect the game. * @@ -369,9 +349,6 @@ class IPluginGame : public QObject, public IPlugin * @brief Get a URL for the support page for the game */ virtual QString getSupportURL() const { return ""; } - -protected: - virtual std::map featureList() const = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(IPluginGame::ProfileSettings) diff --git a/src/iplugingamefeatures.h b/src/iplugingamefeatures.h new file mode 100644 index 00000000..553d3020 --- /dev/null +++ b/src/iplugingamefeatures.h @@ -0,0 +1,61 @@ +/* +Mod Organizer shared UI functionality + +Copyright (C) 2024 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef IPLUGINGAMEFEATURES_H +#define IPLUGINGAMEFEATURES_H + +namespace MOBase +{ + +class BSAInvalidation; +class DataArchives; +class GamePlugins; +class LocalSavegames; +class ModDataChecker; +class ModDataContent; +class SaveGameInfo; +class ScriptExtender; +class UnmanagedMods; + +/** + * @brief A plugin to implement game features. + * + */ +class IPluginGameFeautres +{ +public: + /** + * Retrieve the priority of these game features. + * + * For mergeable features, e.g., ModDataChecker, this indicates the order in which the + * features are merged, otherwise, it indicates which plugin should provide the + * feature. + * + * The managed game always has lowest priority. + * + * @return the priority of this set of features. + */ + virtual int priority() = 0; +}; + +} // namespace MOBase + +#endif // IPLUGINDIAGNOSE_H +#pragma once From d84d7f09ff963527ac2a1f55b47d079e330034f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sat, 1 Jun 2024 09:58:53 +0200 Subject: [PATCH 2/4] Move IGameFeatures to a separate file. --- src/game_features/igamefeatures.h | 165 ++++++++++++++++++++++++++++++ src/imoinfo.h | 136 +----------------------- 2 files changed, 166 insertions(+), 135 deletions(-) create mode 100644 src/game_features/igamefeatures.h diff --git a/src/game_features/igamefeatures.h b/src/game_features/igamefeatures.h new file mode 100644 index 00000000..c474249b --- /dev/null +++ b/src/game_features/igamefeatures.h @@ -0,0 +1,165 @@ +#ifndef UIBASE_GAMEFEATURES_IGAMEFEATURES_H +#define UIBASE_GAMEFEATURES_IGAMEFEATURES_H + +#include +#include + +#include + +#include "game_feature.h" + +namespace MOBase +{ + +class IPluginGame; + +// top-level game features +class BSAInvalidation; +class DataArchives; +class GamePlugins; +class LocalSavegames; +class ModDataChecker; +class ModDataContent; +class SaveGameInfo; +class ScriptExtender; +class UnmanagedMods; + +namespace details +{ + + // use pointers in the tuple since are only forward-declaring the features here + using BaseGameFeaturesP = + std::tuple; + +} // namespace details + +// simple concept that only restricting template function that should take a game +// feature to actually viable game feature types +// +template +concept BaseGameFeature = requires(T) { + { + std::get(std::declval()) + } -> std::convertible_to; +}; + +/** + * @brief Interface to game features. + * + */ +class IGameFeatures +{ +public: + /** + * @brief Register game feature for the specified game. + * + * This method register a game feature to combine or replace the same feature provided + * by the game. Some features are merged (e.g., ModDataContent, ModDataChecker), while + * other override previous features (e.g., SaveGameInfo). + * + * For features that can be combined, the priority argument indicates the order of + * priority (e.g., the order of the checks for ModDataChecker). For other features, + * the feature with the highest priority will be used. The features provided by the + * game plugin itself always have lowest priority. + * + * The feature is associated to the plugin that registers it, if the plugin is + * disabled, the feature will not be available. + * + * This function will return True if the feature was registered, even if the feature + * is not used du to its low priority. + * + * @param games Names of the game to enable the feature for. + * @param feature Game feature to register. + * @param priority Priority of the game feature. If the plugin registering the feature + * is a game plugin, this parameter is ignored. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(QStringList const& games, + std::shared_ptr feature, int priority, + bool replace = false) = 0; + + /** + * @brief Register game feature for the specified game. + * + * See first overload for more details. + * + * @param game Game to enable the feature for. + * @param feature Game feature to register. + * @param priority Priority of the game feature. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(IPluginGame* game, std::shared_ptr feature, + int priority, bool replace = false) = 0; + + /** + * @brief Register game feature for all games. + * + * See first overload for more details. + * + * @param feature Game feature to register. + * @param priority Priority of the game feature. + * @param replace If true, remove features of the same kind registered by the current + * plugin, otherwise add the feature alongside existing ones. + * + * @return true if the game feature was properly registered, false otherwise. + */ + virtual bool registerFeature(std::shared_ptr feature, int priority, + bool replace = false) = 0; + + /** + * @brief Unregister the given game feature. + * + * This function is safe to use even if the feature was not registered before. + * + * @param feature Feature to unregister. + */ + virtual bool unregisterFeature(std::shared_ptr feature) = 0; + + /** + * @brief Unregister all features of the given type registered by the calling plugin. + * + * This function is safe to use even if the plugin has no feature of the given type + * register. + * + * @return the number of features unregistered. + * + * @tparam Feature Type of game feature to remove. + */ + template + int unregisterFeatures() + { + unregisterFeaturesImpl(typeid(Feature)); + } + + /** + * Retrieve the given game feature, if one exists. + * + * @return the feature of the given type, if one exists, otherwise a null pointer. + */ + template + T* gameFeature() const + { + // gameFeatureImpl ensure that the returned pointer is of the right type (or + // nullptr), so reinterpret_cast should be fine here + return dynamic_cast(gameFeatureImpl(typeid(T))); + } + +public: + virtual ~IGameFeatures() = default; + +protected: + virtual GameFeature* gameFeatureImpl(std::type_info const& info) const = 0; + virtual int unregisterFeaturesImpl(std::type_info const& info) = 0; +}; + +} // namespace MOBase + +#endif \ No newline at end of file diff --git a/src/imoinfo.h b/src/imoinfo.h index 3a7c3974..407a379a 100644 --- a/src/imoinfo.h +++ b/src/imoinfo.h @@ -46,141 +46,7 @@ class IDownloadManager; class IPluginList; class IPlugin; class IPluginGame; - -// top-level game features -class BSAInvalidation; -class DataArchives; -class GamePlugins; -class LocalSavegames; -class ModDataChecker; -class ModDataContent; -class SaveGameInfo; -class ScriptExtender; -class UnmanagedMods; - -template -concept BaseGameFeature = requires(T) { - std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || - std::is_same_v; -}; - -/** - * @brief Interface to game features. - * - */ -class IGameFeatures -{ -public: - /** - * @brief Register game feature for the specified game. - * - * This method register a game feature to combine or replace the same feature provided - * by the game. Some features are merged (e.g., ModDataContent, ModDataChecker), while - * other override previous features (e.g., SaveGameInfo). - * - * For features that can be combined, the priority argument indicates the order of - * priority (e.g., the order of the checks for ModDataChecker). For other features, - * the feature with the highest priority will be used. The features provided by the - * game plugin itself always have lowest priority. - * - * The feature is associated to the plugin that registers it, if the plugin is - * disabled, the feature will not be available. - * - * This function will return True if the feature was registered, even if the feature - * is not used du to its low priority. - * - * @param games Names of the game to enable the feature for. - * @param feature Game feature to register. - * @param priority Priority of the game feature. If the plugin registering the feature - * is a game plugin, this parameter is ignored. - * @param replace If true, remove features of the same kind registered by the current - * plugin, otherwise add the feature alongside existing ones. - * - * @return true if the game feature was properly registered, false otherwise. - */ - virtual bool registerFeature(QStringList const& games, - std::shared_ptr feature, int priority, - bool replace = false) = 0; - - /** - * @brief Register game feature for the specified game. - * - * See first overload for more details. - * - * @param game Game to enable the feature for. - * @param feature Game feature to register. - * @param priority Priority of the game feature. - * @param replace If true, remove features of the same kind registered by the current - * plugin, otherwise add the feature alongside existing ones. - * - * @return true if the game feature was properly registered, false otherwise. - */ - virtual bool registerFeature(IPluginGame* game, std::shared_ptr feature, - int priority, bool replace = false) = 0; - - /** - * @brief Register game feature for all games. - * - * See first overload for more details. - * - * @param feature Game feature to register. - * @param priority Priority of the game feature. - * @param replace If true, remove features of the same kind registered by the current - * plugin, otherwise add the feature alongside existing ones. - * - * @return true if the game feature was properly registered, false otherwise. - */ - virtual bool registerFeature(std::shared_ptr feature, int priority, - bool replace = false) = 0; - - /** - * @brief Unregister the given game feature. - * - * This function is safe to use even if the feature was not registered before. - * - * @param feature Feature to unregister. - */ - virtual bool unregisterFeature(std::shared_ptr feature) = 0; - - /** - * @brief Unregister all features of the given type registered by the calling plugin. - * - * This function is safe to use even if the plugin has no feature of the given type - * register. - * - * @return the number of features unregistered. - * - * @tparam Feature Type of game feature to remove. - */ - template - int unregisterFeatures() - { - unregisterFeaturesImpl(typeid(Feature)); - } - - /** - * Retrieve the given game feature, if one exists. - * - * @return the feature of the given type, if one exists, otherwise a null pointer. - */ - template - T* gameFeature() const - { - // gameFeatureImpl ensure that the returned pointer is of the right type (or - // nullptr), so reinterpret_cast should be fine here - return dynamic_cast(gameFeatureImpl(typeid(T))); - } - -public: - virtual ~IGameFeatures() = default; - -protected: - virtual GameFeature* gameFeatureImpl(std::type_info const& info) const = 0; - virtual int unregisterFeaturesImpl(std::type_info const& info) = 0; -}; +class IGameFeatures; /** * @brief Interface to class that provides information about the running session From 2ac1d9547479900f60f6fdf7c4015f41c009364f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sat, 1 Jun 2024 10:21:16 +0200 Subject: [PATCH 3/4] Add missing return statement. --- src/game_features/igamefeatures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game_features/igamefeatures.h b/src/game_features/igamefeatures.h index c474249b..ac76ae45 100644 --- a/src/game_features/igamefeatures.h +++ b/src/game_features/igamefeatures.h @@ -136,7 +136,7 @@ class IGameFeatures template int unregisterFeatures() { - unregisterFeaturesImpl(typeid(Feature)); + return unregisterFeaturesImpl(typeid(Feature)); } /** From ce0d751890112f9c90b8fac63ac3f22b5f58bad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sat, 1 Jun 2024 16:06:32 +0200 Subject: [PATCH 4/4] Wrap game feature in shared pointer. --- src/game_features/igamefeatures.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/game_features/igamefeatures.h b/src/game_features/igamefeatures.h index ac76ae45..c625bfbf 100644 --- a/src/game_features/igamefeatures.h +++ b/src/game_features/igamefeatures.h @@ -145,19 +145,20 @@ class IGameFeatures * @return the feature of the given type, if one exists, otherwise a null pointer. */ template - T* gameFeature() const + std::shared_ptr gameFeature() const { // gameFeatureImpl ensure that the returned pointer is of the right type (or // nullptr), so reinterpret_cast should be fine here - return dynamic_cast(gameFeatureImpl(typeid(T))); + return std::dynamic_pointer_cast(gameFeatureImpl(typeid(T))); } public: virtual ~IGameFeatures() = default; protected: - virtual GameFeature* gameFeatureImpl(std::type_info const& info) const = 0; - virtual int unregisterFeaturesImpl(std::type_info const& info) = 0; + virtual std::shared_ptr + gameFeatureImpl(std::type_info const& info) const = 0; + virtual int unregisterFeaturesImpl(std::type_info const& info) = 0; }; } // namespace MOBase