Skip to content

Commit

Permalink
Refactoring of game features for better management. (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
Holt59 authored Jun 9, 2024
1 parent c6c5f27 commit 0458708
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 95 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mo2_add_filter(NAME src/interfaces GROUPS
iplugindiagnose
ipluginfilemapper
iplugingame
iplugingamefeatures
iplugininstaller
iplugininstallercustom
iplugininstallersimple
Expand Down
17 changes: 9 additions & 8 deletions src/game_features/bsainvalidation.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
#ifndef BSAINVALIDATION_H
#define BSAINVALIDATION_H
#ifndef UIBASE_GAMEFEATURES_BSAINVALIDATION_H
#define UIBASE_GAMEFEATURES_BSAINVALIDATION_H

#include <QString>

#include "./game_feature.h"

namespace MOBase
{
class IProfile;
}

class QString;

class BSAInvalidation
class BSAInvalidation : public details::GameFeatureCRTP<BSAInvalidation>
{
public:
virtual ~BSAInvalidation() {}

virtual bool isInvalidationBSA(const QString& bsaName) = 0;

virtual void deactivate(MOBase::IProfile* profile) = 0;
Expand All @@ -22,4 +21,6 @@ class BSAInvalidation
virtual bool prepareProfile(MOBase::IProfile* profile) = 0;
};

} // namespace MOBase

#endif // BSAINVALIDATION_H
14 changes: 7 additions & 7 deletions src/game_features/dataarchives.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
#ifndef DATAARCHIVES
#define DATAARCHIVES
#ifndef UIBASE_GAMEFEATURES_DATAARCHIVES_H
#define UIBASE_GAMEFEATURES_DATAARCHIVES_H

#include <QString>
#include <QStringList>

#include "./game_feature.h"

namespace MOBase
{
class IProfile;
}

class DataArchives
class DataArchives : public details::GameFeatureCRTP<DataArchives>
{

public:
virtual ~DataArchives() {}

virtual QStringList vanillaArchives() const = 0;

virtual QStringList archives(const MOBase::IProfile* profile) const = 0;
Expand All @@ -32,4 +30,6 @@ class DataArchives
virtual void removeArchive(MOBase::IProfile* profile, const QString& archiveName) = 0;
};

} // namespace MOBase

#endif // DATAARCHIVES
37 changes: 37 additions & 0 deletions src/game_features/game_feature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef UIBASE_GAMEFEATURES_GAMEFEATURE_H
#define UIBASE_GAMEFEATURES_GAMEFEATURE_H

#include <typeindex>

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 T>
class GameFeatureCRTP : public GameFeature
{
const std::type_info& typeInfo() const final { return typeid(T); }
};

} // namespace details

} // namespace MOBase

#endif
14 changes: 7 additions & 7 deletions src/game_features/gameplugins.h
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
#ifndef GAMEPLUGINS_H
#define GAMEPLUGINS_H
#ifndef UIBASE_GAMEFEATURES_GAMEPLUGINS_H
#define UIBASE_GAMEFEATURES_GAMEPLUGINS_H

#include <QStringList>

#include "./game_feature.h"

namespace MOBase
{
class IPluginList;
}

class GamePlugins
class GamePlugins : public details::GameFeatureCRTP<GamePlugins>
{

public:
virtual ~GamePlugins() {}

virtual void writePluginLists(const MOBase::IPluginList* pluginList) = 0;
virtual void readPluginLists(MOBase::IPluginList* pluginList) = 0;
virtual QStringList getLoadOrder() = 0;
virtual bool lightPluginsAreSupported() = 0;
virtual bool overridePluginsAreSupported() = 0;
};

} // namespace MOBase

#endif // GAMEPLUGINS_H
166 changes: 166 additions & 0 deletions src/game_features/igamefeatures.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#ifndef UIBASE_GAMEFEATURES_IGAMEFEATURES_H
#define UIBASE_GAMEFEATURES_IGAMEFEATURES_H

#include <memory>
#include <tuple>

#include <QStringList>

#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<BSAInvalidation*, DataArchives*, GamePlugins*, LocalSavegames*,
ModDataChecker*, ModDataContent*, SaveGameInfo*, ScriptExtender*,
UnmanagedMods*>;

} // namespace details

// simple concept that only restricting template function that should take a game
// feature to actually viable game feature types
//
template <class T>
concept BaseGameFeature = requires(T) {
{
std::get<T*>(std::declval<details::BaseGameFeaturesP>())
} -> std::convertible_to<T*>;
};

/**
* @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<GameFeature> 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<GameFeature> 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<GameFeature> 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<GameFeature> 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 <BaseGameFeature Feature>
int unregisterFeatures()
{
return 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 <BaseGameFeature T>
std::shared_ptr<T> gameFeature() const
{
// gameFeatureImpl ensure that the returned pointer is of the right type (or
// nullptr), so reinterpret_cast should be fine here
return std::dynamic_pointer_cast<T>(gameFeatureImpl(typeid(T)));
}

public:
virtual ~IGameFeatures() = default;

protected:
virtual std::shared_ptr<GameFeature>
gameFeatureImpl(std::type_info const& info) const = 0;
virtual int unregisterFeaturesImpl(std::type_info const& info) = 0;
};

} // namespace MOBase

#endif
12 changes: 5 additions & 7 deletions src/game_features/localsavegames.h
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
#ifndef LOCALSAVEGAMES_H
#define LOCALSAVEGAMES_H
#ifndef UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H
#define UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H

#include <QDir>

#include "./game_feature.h"
#include "filemapping.h"

namespace MOBase
{
class IProfile;
}

class LocalSavegames
class LocalSavegames : public details::GameFeatureCRTP<LocalSavegames>
{

public:
virtual ~LocalSavegames() {}

virtual MappingType mappings(const QDir& profileSaveDir) const = 0;
virtual bool prepareProfile(MOBase::IProfile* profile) = 0;
};
} // namespace MOBase

#endif // LOCALSAVEGAMES_H
16 changes: 6 additions & 10 deletions src/game_features/moddatachecker.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#ifndef MODDATACHECKER_H
#define MODDATACHECKER_H
#ifndef UIBASE_GAMEFEATURES_MODDATACHECKER_H
#define UIBASE_GAMEFEATURES_MODDATACHECKER_H

#include <memory>

#include "./game_feature.h"

namespace MOBase
{
class IFileTree;
}

class ModDataChecker
class ModDataChecker : public details::GameFeatureCRTP<ModDataChecker>
{
public:
/**
Expand Down Expand Up @@ -59,12 +60,7 @@ class ModDataChecker
{
return nullptr;
}

public:
/**
*
*/
virtual ~ModDataChecker() {}
};
} // namespace MOBase

#endif
Loading

0 comments on commit 0458708

Please sign in to comment.