aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest/modmanager.h
blob: 6d89e93497a5560dc7e25eb58fac47f65c735591 (plain)
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 <string>
#include <vector>
#include <filesystem>
#include "rapidjson/document.h"
#include "memalloc.h"
#include "squirrel.h"

namespace fs = std::filesystem;

const std::string MOD_FOLDER_SUFFIX = "/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 RsonRunOn;

	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
	fs::path ModDirectory;
	bool Enabled = true;

	// 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

	// other stuff

	bool wasReadSuccessfully = false;

  public:
	Mod(fs::path modPath, char* jsonBuf);
};

struct ModOverrideFile
{
  public:
	Mod* owningMod;
	fs::path path;
};

class ModManager
{
  private:
	bool m_hasLoadedMods = false;
	bool m_hasEnabledModsCfg;
	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 Mods/Compiled/
	void BuildScriptsRson();
	void TryBuildKeyValues(const char* filename);
	void BuildPdef();
};

fs::path GetModFolderPath();
fs::path GetCompiledAssetsPath();

extern ModManager* g_pModManager;