Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring of game features for better management. #146

Merged
merged 4 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading