Skip to content

Commit 5e07df8

Browse files
authored
mods: Move collecting mods to own function (#830)
Moves the logic that goes through all the paths where mods can be installed to its own function as part of improving code maintainability and future refactoring.
1 parent 21843ee commit 5e07df8

File tree

2 files changed

+122
-103
lines changed

2 files changed

+122
-103
lines changed

primedev/mods/modmanager.cpp

+110-103
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ void ModManager::LoadMods()
111111
if (m_bHasLoadedMods)
112112
UnloadMods();
113113

114-
std::vector<fs::path> modDirs;
115-
116114
// ensure dirs exist
117115
fs::remove_all(GetCompiledAssetsPath());
118116
fs::create_directories(GetModFolderPath());
@@ -137,107 +135,8 @@ void ModManager::LoadMods()
137135
m_bHasEnabledModsCfg = m_EnabledModsCfg.IsObject();
138136
}
139137

140-
// get mod directories
141-
std::filesystem::directory_iterator classicModsDir = fs::directory_iterator(GetModFolderPath());
142-
std::filesystem::directory_iterator remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath());
143-
std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
144-
145-
for (fs::directory_entry dir : classicModsDir)
146-
if (fs::exists(dir.path() / "mod.json"))
147-
modDirs.push_back(dir.path());
148-
149-
// Special case for Thunderstore and remote mods directories
150-
// Set up regex for `AUTHOR-MOD-VERSION` pattern
151-
std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
152-
153-
for (fs::directory_iterator dirIterator : {thunderstoreModsDir, remoteModsDir})
154-
{
155-
for (fs::directory_entry dir : dirIterator)
156-
{
157-
fs::path modsDir = dir.path() / "mods"; // Check for mods folder in the Thunderstore mod
158-
// Use regex to match `AUTHOR-MOD-VERSION` pattern
159-
if (!std::regex_match(dir.path().string(), pattern))
160-
{
161-
spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
162-
continue; // skip loading mod that doesn't match
163-
}
164-
if (fs::exists(modsDir) && fs::is_directory(modsDir))
165-
{
166-
for (fs::directory_entry subDir : fs::directory_iterator(modsDir))
167-
{
168-
if (fs::exists(subDir.path() / "mod.json"))
169-
{
170-
modDirs.push_back(subDir.path());
171-
}
172-
}
173-
}
174-
}
175-
}
176-
177-
for (fs::path modDir : modDirs)
178-
{
179-
// read mod json file
180-
std::ifstream jsonStream(modDir / "mod.json");
181-
std::stringstream jsonStringStream;
182-
183-
// fail if no mod json
184-
if (jsonStream.fail())
185-
{
186-
spdlog::warn(
187-
"Mod file at '{}' does not exist or could not be read, is it installed correctly?", (modDir / "mod.json").string());
188-
continue;
189-
}
190-
191-
while (jsonStream.peek() != EOF)
192-
jsonStringStream << (char)jsonStream.get();
193-
194-
jsonStream.close();
195-
196-
Mod mod(modDir, (char*)jsonStringStream.str().c_str());
197-
198-
for (auto& pair : mod.DependencyConstants)
199-
{
200-
if (m_DependencyConstants.find(pair.first) != m_DependencyConstants.end() && m_DependencyConstants[pair.first] != pair.second)
201-
{
202-
spdlog::error(
203-
"'{}' attempted to register a dependency constant '{}' for '{}' that already exists for '{}'. "
204-
"Change the constant name.",
205-
mod.Name,
206-
pair.first,
207-
pair.second,
208-
m_DependencyConstants[pair.first]);
209-
mod.m_bWasReadSuccessfully = false;
210-
break;
211-
}
212-
if (m_DependencyConstants.find(pair.first) == m_DependencyConstants.end())
213-
m_DependencyConstants.emplace(pair);
214-
}
215-
216-
for (std::string& dependency : mod.PluginDependencyConstants)
217-
{
218-
m_PluginDependencyConstants.insert(dependency);
219-
}
220-
221-
if (m_bHasEnabledModsCfg && m_EnabledModsCfg.HasMember(mod.Name.c_str()))
222-
mod.m_bEnabled = m_EnabledModsCfg[mod.Name.c_str()].IsTrue();
223-
else
224-
mod.m_bEnabled = true;
225-
226-
if (mod.m_bWasReadSuccessfully)
227-
{
228-
if (mod.m_bEnabled)
229-
spdlog::info("'{}' loaded successfully, version {}", mod.Name, mod.Version);
230-
else
231-
spdlog::info("'{}' loaded successfully, version {} (DISABLED)", mod.Name, mod.Version);
232-
233-
m_LoadedMods.push_back(mod);
234-
}
235-
else
236-
spdlog::warn("Mod file at '{}' failed to load", (modDir / "mod.json").string());
237-
}
238-
239-
// sort by load prio, lowest-highest
240-
std::sort(m_LoadedMods.begin(), m_LoadedMods.end(), [](Mod& a, Mod& b) { return a.LoadPriority < b.LoadPriority; });
138+
// Load mod info from filesystem into `m_LoadedMods`
139+
SearchFilesystemForMods();
241140

242141
// This is used to check if some mods have a folder but no entry in enabledmods.json
243142
bool newModsDetected = false;
@@ -621,6 +520,114 @@ void ModManager::UnloadMods()
621520
m_LoadedMods.clear();
622521
}
623522

523+
void ModManager::SearchFilesystemForMods()
524+
{
525+
std::vector<fs::path> modDirs;
526+
m_LoadedMods.clear();
527+
528+
// get mod directories
529+
std::filesystem::directory_iterator classicModsDir = fs::directory_iterator(GetModFolderPath());
530+
std::filesystem::directory_iterator remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath());
531+
std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
532+
533+
for (fs::directory_entry dir : classicModsDir)
534+
if (fs::exists(dir.path() / "mod.json"))
535+
modDirs.push_back(dir.path());
536+
537+
// Special case for Thunderstore and remote mods directories
538+
// Set up regex for `AUTHOR-MOD-VERSION` pattern
539+
std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
540+
541+
for (fs::directory_iterator dirIterator : {thunderstoreModsDir, remoteModsDir})
542+
{
543+
for (fs::directory_entry dir : dirIterator)
544+
{
545+
fs::path modsDir = dir.path() / "mods"; // Check for mods folder in the Thunderstore mod
546+
// Use regex to match `AUTHOR-MOD-VERSION` pattern
547+
if (!std::regex_match(dir.path().string(), pattern))
548+
{
549+
spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
550+
continue; // skip loading mod that doesn't match
551+
}
552+
if (fs::exists(modsDir) && fs::is_directory(modsDir))
553+
{
554+
for (fs::directory_entry subDir : fs::directory_iterator(modsDir))
555+
{
556+
if (fs::exists(subDir.path() / "mod.json"))
557+
{
558+
modDirs.push_back(subDir.path());
559+
}
560+
}
561+
}
562+
}
563+
}
564+
565+
for (fs::path modDir : modDirs)
566+
{
567+
// read mod json file
568+
std::ifstream jsonStream(modDir / "mod.json");
569+
std::stringstream jsonStringStream;
570+
571+
// fail if no mod json
572+
if (jsonStream.fail())
573+
{
574+
spdlog::warn(
575+
"Mod file at '{}' does not exist or could not be read, is it installed correctly?", (modDir / "mod.json").string());
576+
continue;
577+
}
578+
579+
while (jsonStream.peek() != EOF)
580+
jsonStringStream << (char)jsonStream.get();
581+
582+
jsonStream.close();
583+
584+
Mod mod(modDir, (char*)jsonStringStream.str().c_str());
585+
586+
for (auto& pair : mod.DependencyConstants)
587+
{
588+
if (m_DependencyConstants.find(pair.first) != m_DependencyConstants.end() && m_DependencyConstants[pair.first] != pair.second)
589+
{
590+
spdlog::error(
591+
"'{}' attempted to register a dependency constant '{}' for '{}' that already exists for '{}'. "
592+
"Change the constant name.",
593+
mod.Name,
594+
pair.first,
595+
pair.second,
596+
m_DependencyConstants[pair.first]);
597+
mod.m_bWasReadSuccessfully = false;
598+
break;
599+
}
600+
if (m_DependencyConstants.find(pair.first) == m_DependencyConstants.end())
601+
m_DependencyConstants.emplace(pair);
602+
}
603+
604+
for (std::string& dependency : mod.PluginDependencyConstants)
605+
{
606+
m_PluginDependencyConstants.insert(dependency);
607+
}
608+
609+
if (m_bHasEnabledModsCfg && m_EnabledModsCfg.HasMember(mod.Name.c_str()))
610+
mod.m_bEnabled = m_EnabledModsCfg[mod.Name.c_str()].IsTrue();
611+
else
612+
mod.m_bEnabled = true;
613+
614+
if (mod.m_bWasReadSuccessfully)
615+
{
616+
if (mod.m_bEnabled)
617+
spdlog::info("'{}' loaded successfully, version {}", mod.Name, mod.Version);
618+
else
619+
spdlog::info("'{}' loaded successfully, version {} (DISABLED)", mod.Name, mod.Version);
620+
621+
m_LoadedMods.push_back(mod);
622+
}
623+
else
624+
spdlog::warn("Mod file at '{}' failed to load", (modDir / "mod.json").string());
625+
}
626+
627+
// sort by load prio, lowest-highest
628+
std::sort(m_LoadedMods.begin(), m_LoadedMods.end(), [](Mod& a, Mod& b) { return a.LoadPriority < b.LoadPriority; });
629+
}
630+
624631
std::string ModManager::NormaliseModFilePath(const fs::path path)
625632
{
626633
std::string str = path.lexically_normal().string();

primedev/mods/modmanager.h

+12
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ class ModManager
4646
std::unordered_map<std::string, std::string> m_DependencyConstants;
4747
std::unordered_set<std::string> m_PluginDependencyConstants;
4848

49+
private:
50+
/**
51+
* Load information for all mods from filesystem.
52+
*
53+
* This looks for mods in several directories (expecting them to be formatted in
54+
* some way); it then uses respective `mod.json` manifest files to create `Mod`
55+
* instances, which are then stored in the `m_LoadedMods` variable.
56+
*
57+
* @returns nothing
58+
**/
59+
void SearchFilesystemForMods();
60+
4961
public:
5062
ModManager();
5163
void LoadMods();

0 commit comments

Comments
 (0)