Skip to content

Commit 0458708

Browse files
authored
Refactoring of game features for better management. (#146)
1 parent c6c5f27 commit 0458708

15 files changed

+347
-95
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mo2_add_filter(NAME src/interfaces GROUPS
1818
iplugindiagnose
1919
ipluginfilemapper
2020
iplugingame
21+
iplugingamefeatures
2122
iplugininstaller
2223
iplugininstallercustom
2324
iplugininstallersimple

src/game_features/bsainvalidation.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
#ifndef BSAINVALIDATION_H
2-
#define BSAINVALIDATION_H
1+
#ifndef UIBASE_GAMEFEATURES_BSAINVALIDATION_H
2+
#define UIBASE_GAMEFEATURES_BSAINVALIDATION_H
3+
4+
#include <QString>
5+
6+
#include "./game_feature.h"
37

48
namespace MOBase
59
{
610
class IProfile;
7-
}
8-
9-
class QString;
1011

11-
class BSAInvalidation
12+
class BSAInvalidation : public details::GameFeatureCRTP<BSAInvalidation>
1213
{
1314
public:
14-
virtual ~BSAInvalidation() {}
15-
1615
virtual bool isInvalidationBSA(const QString& bsaName) = 0;
1716

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

24+
} // namespace MOBase
25+
2526
#endif // BSAINVALIDATION_H

src/game_features/dataarchives.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
#ifndef DATAARCHIVES
2-
#define DATAARCHIVES
1+
#ifndef UIBASE_GAMEFEATURES_DATAARCHIVES_H
2+
#define UIBASE_GAMEFEATURES_DATAARCHIVES_H
33

44
#include <QString>
55
#include <QStringList>
66

7+
#include "./game_feature.h"
8+
79
namespace MOBase
810
{
911
class IProfile;
10-
}
1112

12-
class DataArchives
13+
class DataArchives : public details::GameFeatureCRTP<DataArchives>
1314
{
14-
1515
public:
16-
virtual ~DataArchives() {}
17-
1816
virtual QStringList vanillaArchives() const = 0;
1917

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

33+
} // namespace MOBase
34+
3535
#endif // DATAARCHIVES

src/game_features/game_feature.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef UIBASE_GAMEFEATURES_GAMEFEATURE_H
2+
#define UIBASE_GAMEFEATURES_GAMEFEATURE_H
3+
4+
#include <typeindex>
5+
6+
namespace MOBase
7+
{
8+
9+
/**
10+
* Empty class that is inherit by all game features.
11+
*/
12+
class GameFeature
13+
{
14+
public:
15+
GameFeature() = default;
16+
virtual ~GameFeature() = 0 {}
17+
18+
/**
19+
* @brief Retrieve the type index of the main game feature this feature extends.
20+
*/
21+
virtual const std::type_info& typeInfo() const = 0;
22+
};
23+
24+
namespace details
25+
{
26+
27+
template <class T>
28+
class GameFeatureCRTP : public GameFeature
29+
{
30+
const std::type_info& typeInfo() const final { return typeid(T); }
31+
};
32+
33+
} // namespace details
34+
35+
} // namespace MOBase
36+
37+
#endif

src/game_features/gameplugins.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
#ifndef GAMEPLUGINS_H
2-
#define GAMEPLUGINS_H
1+
#ifndef UIBASE_GAMEFEATURES_GAMEPLUGINS_H
2+
#define UIBASE_GAMEFEATURES_GAMEPLUGINS_H
33

44
#include <QStringList>
55

6+
#include "./game_feature.h"
7+
68
namespace MOBase
79
{
810
class IPluginList;
9-
}
1011

11-
class GamePlugins
12+
class GamePlugins : public details::GameFeatureCRTP<GamePlugins>
1213
{
13-
1414
public:
15-
virtual ~GamePlugins() {}
16-
1715
virtual void writePluginLists(const MOBase::IPluginList* pluginList) = 0;
1816
virtual void readPluginLists(MOBase::IPluginList* pluginList) = 0;
1917
virtual QStringList getLoadOrder() = 0;
2018
virtual bool lightPluginsAreSupported() = 0;
2119
virtual bool overridePluginsAreSupported() = 0;
2220
};
2321

22+
} // namespace MOBase
23+
2424
#endif // GAMEPLUGINS_H

src/game_features/igamefeatures.h

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#ifndef UIBASE_GAMEFEATURES_IGAMEFEATURES_H
2+
#define UIBASE_GAMEFEATURES_IGAMEFEATURES_H
3+
4+
#include <memory>
5+
#include <tuple>
6+
7+
#include <QStringList>
8+
9+
#include "game_feature.h"
10+
11+
namespace MOBase
12+
{
13+
14+
class IPluginGame;
15+
16+
// top-level game features
17+
class BSAInvalidation;
18+
class DataArchives;
19+
class GamePlugins;
20+
class LocalSavegames;
21+
class ModDataChecker;
22+
class ModDataContent;
23+
class SaveGameInfo;
24+
class ScriptExtender;
25+
class UnmanagedMods;
26+
27+
namespace details
28+
{
29+
30+
// use pointers in the tuple since are only forward-declaring the features here
31+
using BaseGameFeaturesP =
32+
std::tuple<BSAInvalidation*, DataArchives*, GamePlugins*, LocalSavegames*,
33+
ModDataChecker*, ModDataContent*, SaveGameInfo*, ScriptExtender*,
34+
UnmanagedMods*>;
35+
36+
} // namespace details
37+
38+
// simple concept that only restricting template function that should take a game
39+
// feature to actually viable game feature types
40+
//
41+
template <class T>
42+
concept BaseGameFeature = requires(T) {
43+
{
44+
std::get<T*>(std::declval<details::BaseGameFeaturesP>())
45+
} -> std::convertible_to<T*>;
46+
};
47+
48+
/**
49+
* @brief Interface to game features.
50+
*
51+
*/
52+
class IGameFeatures
53+
{
54+
public:
55+
/**
56+
* @brief Register game feature for the specified game.
57+
*
58+
* This method register a game feature to combine or replace the same feature provided
59+
* by the game. Some features are merged (e.g., ModDataContent, ModDataChecker), while
60+
* other override previous features (e.g., SaveGameInfo).
61+
*
62+
* For features that can be combined, the priority argument indicates the order of
63+
* priority (e.g., the order of the checks for ModDataChecker). For other features,
64+
* the feature with the highest priority will be used. The features provided by the
65+
* game plugin itself always have lowest priority.
66+
*
67+
* The feature is associated to the plugin that registers it, if the plugin is
68+
* disabled, the feature will not be available.
69+
*
70+
* This function will return True if the feature was registered, even if the feature
71+
* is not used du to its low priority.
72+
*
73+
* @param games Names of the game to enable the feature for.
74+
* @param feature Game feature to register.
75+
* @param priority Priority of the game feature. If the plugin registering the feature
76+
* is a game plugin, this parameter is ignored.
77+
* @param replace If true, remove features of the same kind registered by the current
78+
* plugin, otherwise add the feature alongside existing ones.
79+
*
80+
* @return true if the game feature was properly registered, false otherwise.
81+
*/
82+
virtual bool registerFeature(QStringList const& games,
83+
std::shared_ptr<GameFeature> feature, int priority,
84+
bool replace = false) = 0;
85+
86+
/**
87+
* @brief Register game feature for the specified game.
88+
*
89+
* See first overload for more details.
90+
*
91+
* @param game Game to enable the feature for.
92+
* @param feature Game feature to register.
93+
* @param priority Priority of the game feature.
94+
* @param replace If true, remove features of the same kind registered by the current
95+
* plugin, otherwise add the feature alongside existing ones.
96+
*
97+
* @return true if the game feature was properly registered, false otherwise.
98+
*/
99+
virtual bool registerFeature(IPluginGame* game, std::shared_ptr<GameFeature> feature,
100+
int priority, bool replace = false) = 0;
101+
102+
/**
103+
* @brief Register game feature for all games.
104+
*
105+
* See first overload for more details.
106+
*
107+
* @param feature Game feature to register.
108+
* @param priority Priority of the game feature.
109+
* @param replace If true, remove features of the same kind registered by the current
110+
* plugin, otherwise add the feature alongside existing ones.
111+
*
112+
* @return true if the game feature was properly registered, false otherwise.
113+
*/
114+
virtual bool registerFeature(std::shared_ptr<GameFeature> feature, int priority,
115+
bool replace = false) = 0;
116+
117+
/**
118+
* @brief Unregister the given game feature.
119+
*
120+
* This function is safe to use even if the feature was not registered before.
121+
*
122+
* @param feature Feature to unregister.
123+
*/
124+
virtual bool unregisterFeature(std::shared_ptr<GameFeature> feature) = 0;
125+
126+
/**
127+
* @brief Unregister all features of the given type registered by the calling plugin.
128+
*
129+
* This function is safe to use even if the plugin has no feature of the given type
130+
* register.
131+
*
132+
* @return the number of features unregistered.
133+
*
134+
* @tparam Feature Type of game feature to remove.
135+
*/
136+
template <BaseGameFeature Feature>
137+
int unregisterFeatures()
138+
{
139+
return unregisterFeaturesImpl(typeid(Feature));
140+
}
141+
142+
/**
143+
* Retrieve the given game feature, if one exists.
144+
*
145+
* @return the feature of the given type, if one exists, otherwise a null pointer.
146+
*/
147+
template <BaseGameFeature T>
148+
std::shared_ptr<T> gameFeature() const
149+
{
150+
// gameFeatureImpl ensure that the returned pointer is of the right type (or
151+
// nullptr), so reinterpret_cast should be fine here
152+
return std::dynamic_pointer_cast<T>(gameFeatureImpl(typeid(T)));
153+
}
154+
155+
public:
156+
virtual ~IGameFeatures() = default;
157+
158+
protected:
159+
virtual std::shared_ptr<GameFeature>
160+
gameFeatureImpl(std::type_info const& info) const = 0;
161+
virtual int unregisterFeaturesImpl(std::type_info const& info) = 0;
162+
};
163+
164+
} // namespace MOBase
165+
166+
#endif

src/game_features/localsavegames.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
#ifndef LOCALSAVEGAMES_H
2-
#define LOCALSAVEGAMES_H
1+
#ifndef UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H
2+
#define UIBASE_GAMEFEATURES_LOCALSAVEGAMES_H
33

44
#include <QDir>
55

6+
#include "./game_feature.h"
67
#include "filemapping.h"
78

89
namespace MOBase
910
{
1011
class IProfile;
11-
}
1212

13-
class LocalSavegames
13+
class LocalSavegames : public details::GameFeatureCRTP<LocalSavegames>
1414
{
15-
1615
public:
17-
virtual ~LocalSavegames() {}
18-
1916
virtual MappingType mappings(const QDir& profileSaveDir) const = 0;
2017
virtual bool prepareProfile(MOBase::IProfile* profile) = 0;
2118
};
19+
} // namespace MOBase
2220

2321
#endif // LOCALSAVEGAMES_H

src/game_features/moddatachecker.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
#ifndef MODDATACHECKER_H
2-
#define MODDATACHECKER_H
1+
#ifndef UIBASE_GAMEFEATURES_MODDATACHECKER_H
2+
#define UIBASE_GAMEFEATURES_MODDATACHECKER_H
33

44
#include <memory>
55

6+
#include "./game_feature.h"
7+
68
namespace MOBase
79
{
810
class IFileTree;
9-
}
1011

11-
class ModDataChecker
12+
class ModDataChecker : public details::GameFeatureCRTP<ModDataChecker>
1213
{
1314
public:
1415
/**
@@ -59,12 +60,7 @@ class ModDataChecker
5960
{
6061
return nullptr;
6162
}
62-
63-
public:
64-
/**
65-
*
66-
*/
67-
virtual ~ModDataChecker() {}
6863
};
64+
} // namespace MOBase
6965

7066
#endif

0 commit comments

Comments
 (0)