1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#pragma once
#include "convar.h"
#include "memalloc.h"
#include "squirrel.h"
#include "rapidjson/document.h"
#include <string>
#include <vector>
#include <filesystem>
namespace fs = std::filesystem;
const std::string MOD_FOLDER_SUFFIX = "/mods";
const std::string REMOTE_MOD_FOLDER_SUFFIX = "/runtime/remote/mods";
const fs::path MOD_OVERRIDE_DIR = "mod";
const std::string COMPILED_ASSETS_SUFFIX = "/runtime/compiled";
struct ModConVar
{
public:
std::string Name;
std::string DefaultValue;
std::string HelpString;
int Flags;
};
struct ModScriptCallback
{
public:
ScriptContext Context;
// called before the codecallback is executed
std::string BeforeCallback;
// called after the codecallback has finished executing
std::string AfterCallback;
};
struct ModScript
{
public:
std::string Path;
std::string RunOn;
std::vector<ModScriptCallback> Callbacks;
};
// these are pretty much identical, could refactor to use the same stuff?
struct ModVPKEntry
{
public:
bool m_bAutoLoad;
std::string m_sVpkPath;
};
struct ModRpakEntry
{
public:
bool m_bAutoLoad;
std::string m_sPakName;
};
class Mod
{
public:
// runtime stuff
bool m_bEnabled = true;
bool m_bWasReadSuccessfully = false;
fs::path m_ModDirectory;
// bool m_bIsRemote;
// mod.json stuff:
// the mod's name
std::string Name;
// the mod's description
std::string Description;
// the mod's version, should be in semver
std::string Version;
// a download link to the mod, for clients that try to join without the mod
std::string DownloadLink;
// whether clients need the mod to join servers running this mod
bool RequiredOnClient;
// the priority for this mod's files, mods with prio 0 are loaded first, then 1, then 2, etc
int LoadPriority;
// custom scripts used by the mod
std::vector<ModScript> Scripts;
// convars created by the mod
std::vector<ModConVar*> ConVars;
// custom localisation files created by the mod
std::vector<std::string> LocalisationFiles;
// other files:
std::vector<ModVPKEntry> Vpks;
std::unordered_map<size_t, std::string> KeyValues;
std::vector<std::string> BinkVideos;
std::string Pdiff; // only need one per mod
std::vector<ModRpakEntry> Rpaks;
std::unordered_map<std::string, std::string>
RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite
public:
Mod(fs::path modPath, char* jsonBuf);
};
struct ModOverrideFile
{
public:
Mod* m_pOwningMod;
fs::path m_Path;
};
class ModManager
{
private:
bool m_bHasLoadedMods = false;
bool m_bHasEnabledModsCfg;
rapidjson_document m_EnabledModsCfg;
// precalculated hashes
size_t m_hScriptsRsonHash;
size_t m_hPdefHash;
public:
std::vector<Mod> m_LoadedMods;
std::unordered_map<std::string, ModOverrideFile> m_ModFiles;
public:
ModManager();
void LoadMods();
void UnloadMods();
std::string NormaliseModFilePath(const fs::path path);
void CompileAssetsForFile(const char* filename);
// compile asset type stuff, these are done in files under runtime/compiled/
void BuildScriptsRson();
void TryBuildKeyValues(const char* filename);
void BuildPdef();
};
fs::path GetModFolderPath();
fs::path GetCompiledAssetsPath();
extern ModManager* g_pModManager;
|