diff --git a/CMakeLists.txt b/CMakeLists.txt index 2de2af16..5cbaefa2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC "src/settings.h" "src/sfall_config.cc" "src/sfall_config.h" + "src/sfall_ext.cc" + "src/sfall_ext.h" "src/sfall_global_vars.cc" "src/sfall_global_vars.h" "src/sfall_global_scripts.cc" diff --git a/src/game.cc b/src/game.cc index d7743375..3f2974ca 100644 --- a/src/game.cc +++ b/src/game.cc @@ -52,6 +52,7 @@ #include "settings.h" #include "sfall_arrays.h" #include "sfall_config.h" +#include "sfall_ext.h" #include "sfall_global_scripts.h" #include "sfall_global_vars.h" #include "sfall_ini.h" @@ -1378,6 +1379,8 @@ static int gameDbInit() } } + sfallLoadMods(); + if (compat_access("f2_res.dat", 0) == 0) { dbOpen("f2_res.dat", 0, nullptr, 1); } diff --git a/src/sfall_ext.cc b/src/sfall_ext.cc new file mode 100644 index 00000000..9408d3d1 --- /dev/null +++ b/src/sfall_ext.cc @@ -0,0 +1,85 @@ +#include "sfall_ext.h" + +#include +#include + +#include "db.h" +#include "debug.h" +#include "platform_compat.h" + +namespace fallout { + +/** + * Load mods from the mod directory + */ +void sfallLoadMods() +{ + // SFALL: additional mods from the mods directory / mods_order.txt + const char* modsPath = "mods"; + const char* loadOrderFilename = "mods_order.txt"; + + char loadOrderFilepath[COMPAT_MAX_PATH]; + compat_makepath(loadOrderFilepath, nullptr, modsPath, loadOrderFilename, nullptr); + + // If the mods folder does not exist, create it. + compat_mkdir(modsPath); + + // If load order file does not exist, initialize it automatically with mods already in the mods folder. + if (compat_access(loadOrderFilepath, 0) != 0) { + debugPrint("Generating Mods Order file based on the contents of Mods folder: %s\n", loadOrderFilepath); + + File* stream = fileOpen(loadOrderFilepath, "wt"); + if (stream != nullptr) { + char** fileList; + int fileListLength = fileNameListInit("mods\\*.dat", &fileList, 0, 0); + + for (int index = 0; index < fileListLength; index++) { + fileWriteString(fileList[index], stream); + fileWriteString("\n", stream); + } + fileClose(stream); + fileNameListFree(&fileList, 0); + } + } + + // Add mods from load order file. + File* stream = fileOpen(loadOrderFilepath, "r"); + if (stream != nullptr) { + char mod[COMPAT_MAX_PATH]; + while (fileReadString(mod, COMPAT_MAX_PATH, stream)) { + std::string modPath { mod }; + + if (modPath.find_first_of(";#") != std::string::npos) + continue; // skip comments + + // ltrim + modPath.erase(modPath.begin(), std::find_if(modPath.begin(), modPath.end(), [](unsigned char ch) { + return !isspace(ch); + })); + + // rtrim + modPath.erase(std::find_if(modPath.rbegin(), modPath.rend(), [](unsigned char ch) { + return !isspace(ch); + }).base(), + modPath.end()); + + if (modPath.empty()) + continue; // skip empty lines + + char normalizedModPath[COMPAT_MAX_PATH]; + compat_makepath(normalizedModPath, nullptr, modsPath, modPath.c_str(), nullptr); + + if (compat_access(normalizedModPath, 0) == 0) { + debugPrint("Loading mod %s\n", normalizedModPath); + dbOpen(normalizedModPath, 0, nullptr, 1); + } else { + debugPrint("Skipping invalid mod entry %s in %s\n", normalizedModPath, loadOrderFilepath); + } + } + fileClose(stream); + } else { + debugPrint("Error opening %s for read\n", loadOrderFilepath); + } +} + +} // namespace fallout diff --git a/src/sfall_ext.h b/src/sfall_ext.h new file mode 100644 index 00000000..a58c140c --- /dev/null +++ b/src/sfall_ext.h @@ -0,0 +1,10 @@ +#ifndef SFALL_EXT_H +#define SFALL_EXT_H + +namespace fallout { + +void sfallLoadMods(); + +} // namespace fallout + +#endif /* SFALL_EXT_H */