From 68947925159bcc17132420c948995da382e2a47d Mon Sep 17 00:00:00 2001 From: Jason Yundt Date: Fri, 24 May 2024 15:26:43 -0400 Subject: [PATCH] Add -aditionaldir option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, Descent 3 would look for all of its game data files in a single directory. This change allows users to spread out Descent 3’s game data over multiple directories. Building Descent 3 produces multiple files that can be freely redistributed (Descent3, d3-linux.hog, online/Direct TCP~IP.d3c, etc.). Running Descent 3 requires those files and several additional files that cannot be freely redistributed. Before this change, the files that were redistributable had to be in the same directory as the files that were not redistributable. This change makes it so that they can be in separate directories. The main motivation behind this change is to allow people to package Descent 3 for Linux in a reasonable manner. For the most part, binary packages for Descent 3 will contain all of the freely redistributable components. Package managers will copy those components into system directories that are owned by root and that users probably shouldn’t edit manually. Users will then create a new directory and copy the game data from their copy of Descent 3 into that new directory. Users will then be able to run: Descent3 -setdir -additionaldir The -additionaldir option can also be used to support more complicated scenarios. For example, if the user is using Debian’s game-data-packager [1], then they would do something like this: Descent3 -setdir -additionaldir -additionaldir Or, if the user is loading a mod that replaces .hog files: Descent3 -setdir -additionaldir [1]: --- Descent3/Game2DLL.cpp | 3 +- Descent3/ambient.cpp | 2 +- Descent3/demofile.cpp | 4 +- Descent3/descent.h | 1 + Descent3/game.cpp | 2 +- Descent3/gamesave.cpp | 8 +-- Descent3/init.cpp | 34 ++++++++---- Descent3/menu.cpp | 77 ++++++++++++++------------ Descent3/multi.cpp | 10 ++-- Descent3/multi_dll_mgr.cpp | 12 +++-- Descent3/multi_ui.cpp | 18 +++---- Descent3/pilot.cpp | 10 ++-- Descent3/pilot_class.cpp | 4 +- cfile/cfile.cpp | 4 +- cfile/cfile.h | 4 +- cfile/tests/cfile_tests.cpp | 9 +++- ddio/ddio.h | 2 +- editor/MainFrm.cpp | 2 +- editor/editor_lighting.cpp | 4 +- editor/gameeditor.cpp | 4 +- gamedata/gamedata.cpp | 90 +++++++++++++++++++++++++------ gamedata/gamedata.h | 49 ++++++++++++++--- gamedata/tests/gamedata_tests.cpp | 6 +-- linux/lnxcontroller.cpp | 2 +- manage/manage.cpp | 8 +-- netcon/includes/con_dll.h | 37 ++++++++----- netcon/includes/mdllinit.h | 5 +- netcon/mtclient/mtclient.cpp | 28 +++++----- win32/WinController.cpp | 2 +- 29 files changed, 291 insertions(+), 150 deletions(-) diff --git a/Descent3/Game2DLL.cpp b/Descent3/Game2DLL.cpp index 24ea6c530..8e920ce5a 100644 --- a/Descent3/Game2DLL.cpp +++ b/Descent3/Game2DLL.cpp @@ -581,8 +581,7 @@ bool InitGameModule(const char *name, module *mod) { // Open the hog file if (!cf_OpenLibrary(lib_name)) { - ddio_MakePath(tmp_dll_name, Base_directory.u8string().c_str(), "netgames", name, NULL); - strcat(tmp_dll_name, ".d3m"); + strncpy(tmp_dll_name, gd_LocatePath(lib_name).u8string().c_str(), sizeof(tmp_dll_name)); Multi_game_dll_name[0] = '\0'; goto loaddll; } diff --git a/Descent3/ambient.cpp b/Descent3/ambient.cpp index 420bbb5ac..3cbf74cd3 100644 --- a/Descent3/ambient.cpp +++ b/Descent3/ambient.cpp @@ -294,7 +294,7 @@ void WriteAmbientData() { CFILE *ofile; #ifndef NEWEDITOR - ddio_MakePath(filename, Base_directory.u8string().c_str(), "data", "misc", AMBIENT_FILE_NAME, NULL); + ddio_MakePath(filename, gd_GetWritableBaseDirectory().u8string().c_str(), "data", "misc", AMBIENT_FILE_NAME, NULL); #else ddio_MakePath(filename, D3HogDir, "data", "misc", AMBIENT_FILE_NAME, NULL); #endif diff --git a/Descent3/demofile.cpp b/Descent3/demofile.cpp index 3a4c05d50..033ac15eb 100644 --- a/Descent3/demofile.cpp +++ b/Descent3/demofile.cpp @@ -361,7 +361,7 @@ void DemoToggleRecording() { if (stricmp(szfile + (strlen(szfile) - 4), ".dem") != 0) { strcat(szfile, ".dem"); } - Demo_fname = Base_directory / "demo" / szfile; + Demo_fname = gd_GetWritableBaseDirectory() / "demo" / szfile; mprintf(0, "Saving demo to file: %s\n", Demo_fname.u8string().c_str()); // Try to create the file Demo_cfp = cfopen(Demo_fname, "wb"); @@ -1424,7 +1424,7 @@ bool LoadDemoDialog() { // return false; // #else - std::filesystem::path file = Base_directory / "demo"; + std::filesystem::path file = gd_GetWritableBaseDirectory() / "demo"; if (DoPathFileDialog(false, file, TXT_VIEWDEMO, {"*.dem"}, PFDF_FILEMUSTEXIST)) { Demo_fname = file; diff --git a/Descent3/descent.h b/Descent3/descent.h index 8634e0832..4dd4715ea 100644 --- a/Descent3/descent.h +++ b/Descent3/descent.h @@ -130,6 +130,7 @@ #include #include +#include #include "application.h" diff --git a/Descent3/game.cpp b/Descent3/game.cpp index c195cd0a7..edfc67571 100644 --- a/Descent3/game.cpp +++ b/Descent3/game.cpp @@ -1299,7 +1299,7 @@ void DoScreenshot() { count = 1; while (!done) { snprintf(str, sizeof(str), "Screenshot%.3d.png", count); - ddio_MakePath(filename, Base_directory.u8string().c_str(), str, NULL); + ddio_MakePath(filename, gd_GetWritableBaseDirectory().u8string().c_str(), str, NULL); infile = (CFILE *)cfopen(filename, "rb"); if (infile == NULL) { done = 1; diff --git a/Descent3/gamesave.cpp b/Descent3/gamesave.cpp index 271933275..094142747 100644 --- a/Descent3/gamesave.cpp +++ b/Descent3/gamesave.cpp @@ -351,7 +351,7 @@ void QuickSaveGame() { i = Quicksave_game_slot; snprintf(filename, sizeof(filename), "saveg00%d", i); - ddio_MakePath(pathname, Base_directory.u8string().c_str(), "savegame", filename, NULL); + ddio_MakePath(pathname, gd_GetWritableBaseDirectory().u8string().c_str(), "savegame", filename, NULL); fp = fopen(pathname, "rb"); if (fp) { @@ -394,7 +394,7 @@ void SaveGameDialog() { #endif // setup paths. - ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL); + ddio_MakePath(savegame_dir, gd_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL); // ddio_MakePath(pathname, savegame_dir, "*.sav", NULL); -unused // create savegame directory if it didn't exist before. @@ -546,7 +546,7 @@ void __cdecl LoadGameDialogCB(newuiTiledWindow *wnd, void *data) mprintf(0, "savegame slot=%d\n", id - SAVE_HOTSPOT_ID); - ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL); + ddio_MakePath(savegame_dir, gd_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL); snprintf(filename, sizeof(filename), "saveg00%d", (id - SAVE_HOTSPOT_ID)); ddio_MakePath(pathname, savegame_dir, filename, NULL); @@ -589,7 +589,7 @@ bool LoadGameDialog() { } // setup paths. - ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL); + ddio_MakePath(savegame_dir, gd_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL); ddio_MakePath(pathname, savegame_dir, "*.sav", NULL); // create savegame directory if it didn't exist before. diff --git a/Descent3/init.cpp b/Descent3/init.cpp index 1f26fd249..7850fc3c6 100644 --- a/Descent3/init.cpp +++ b/Descent3/init.cpp @@ -1392,13 +1392,14 @@ void LoadGameSettings() { */ void InitIOSystems(bool editor) { ddio_init_info io_info; + std::vector initial_base_directories = {}; - // Set the base directory + // Set the writable base directory int dirarg = FindArg("-setdir"); int exedirarg = FindArg("-useexedir"); - std::filesystem::path initial_base_directory; + std::filesystem::path writable_base_directory; if (dirarg) { - initial_base_directory = GameArgs[dirarg + 1]; + writable_base_directory = GameArgs[dirarg + 1]; } else if (exedirarg) { char exec_path[_MAX_PATH]; memset(exec_path, 0, sizeof(exec_path)); @@ -1407,15 +1408,30 @@ void InitIOSystems(bool editor) { Error("Failed to get executable path\n"); } else { std::filesystem::path executablePath(exec_path); - initial_base_directory = executablePath.parent_path(); - mprintf(0, "Using working directory of %s\n", Base_directory); + writable_base_directory = executablePath.parent_path(); + mprintf(0, "Using working directory of %s\n", writable_base_directory); } } else { - initial_base_directory = std::filesystem::current_path(); + writable_base_directory = std::filesystem::current_path(); } - gd_Init(initial_base_directory); - ddio_SetWorkingDir(Base_directory.u8string().c_str()); + ddio_SetWorkingDir(writable_base_directory.u8string().c_str()); + initial_base_directories.insert(initial_base_directories.begin(), writable_base_directory); + + // Set any additional base directories + auto additionaldirarg = 0; + while (0 != (additionaldirarg = FindArg("-additionaldir", additionaldirarg))) { + const auto dir_to_add = GetArg(additionaldirarg + 1); + if (dir_to_add == NULL) { + mprintf(0, "-additionaldir was at the end of the argument list. It should never be at the end of the argument list.\n"); + break; + } else { + initial_base_directories.insert(initial_base_directories.begin(), std::filesystem::path(dir_to_add)); + additionaldirarg += 2; + } + } + + gd_Init(initial_base_directories); Descent->set_defer_handler(D3DeferHandler); @@ -2039,7 +2055,7 @@ void SetupTempDirectory(void) { exit(1); } // restore working dir - ddio_SetWorkingDir(Base_directory.u8string().c_str()); + ddio_SetWorkingDir(gd_GetWritableBaseDirectory().u8string().c_str()); } void DeleteTempFiles() { diff --git a/Descent3/menu.cpp b/Descent3/menu.cpp index d19daba13..4ca24ddc7 100644 --- a/Descent3/menu.cpp +++ b/Descent3/menu.cpp @@ -684,6 +684,8 @@ bool Directplay_lobby_launched_game = false; #endif +#include "gamedata.h" + #define IDV_QUIT 0xff // Menu Item Defines #define IDV_NEWGAME 10 @@ -1060,51 +1062,55 @@ bool ProcessCommandLine() { #define TRAINING_MISSION_NAME "Pilot Training" /** - * Count singleplayer missions in directory. Mission should have .mn3 extension. - * @param missions where to search missions. Should be a valid directory. + * Count singleplayer missions in directories. Mission should have .mn3 extension. + * @param missions_directories where to search missions. Should be a list of valid directories. * @return count of found missions */ -static inline int count_missions(const std::filesystem::path &missions_directory) { +static inline int count_missions(const std::vector &missions_directories) { int c = 0; - ddio_DoForeachFile(missions_directory, std::regex(".*\\.mn3"), [&c](const std::filesystem::path &path) { - if (stricmp(path.filename().u8string().c_str(), "d3_2.mn3") == 0) - return; - mprintf(0, "Mission path: %s\n", path.u8string().c_str()); - tMissionInfo msninfo{}; - GetMissionInfo(path.filename().u8string().c_str(), &msninfo); + for (auto missions_directory : missions_directories) { + ddio_DoForeachFile(missions_directory, std::regex(".*\\.mn3"), [&c](const std::filesystem::path &path) { + if (stricmp(path.filename().u8string().c_str(), "d3_2.mn3") == 0) + return; + mprintf(0, "Mission path: %s\n", path.u8string().c_str()); + tMissionInfo msninfo{}; + GetMissionInfo(path.filename().u8string().c_str(), &msninfo); - if (msninfo.name[0] && msninfo.single) { - mprintf(0, "Name: %s\n", msninfo.name); - c++; - if (!(c % 2)) - DoWaitMessage(true); - } else { - mprintf(0, "Illegal or multiplayer mission: %s\n", path.u8string().c_str()); - } - }); + if (msninfo.name[0] && msninfo.single) { + mprintf(0, "Name: %s\n", msninfo.name); + c++; + if (!(c % 2)) + DoWaitMessage(true); + } else { + mprintf(0, "Illegal or multiplayer mission: %s\n", path.u8string().c_str()); + } + }); + } return c; } static inline int generate_mission_listbox(newuiListBox *lb, int n_maxfiles, char **filelist, - const std::filesystem::path &missions_directory) { + const std::vector &missions_directories) { int c = 0; - ddio_DoForeachFile( - missions_directory, std::regex(".*\\.mn3"), [&c, &lb, &n_maxfiles, &filelist](const std::filesystem::path &path) { - tMissionInfo msninfo{}; - if (c < n_maxfiles) { - if (stricmp(path.filename().u8string().c_str(), "d3_2.mn3") == 0) - return; - if (GetMissionInfo(path.filename().u8string().c_str(), &msninfo) && msninfo.name[0] && msninfo.single) { - filelist[c] = mem_strdup(path.filename().u8string().c_str()); - lb->AddItem(msninfo.name); - c++; - if (!(c % 2)) - DoWaitMessage(true); + for (auto missions_directory : missions_directories) { + ddio_DoForeachFile( + missions_directory, std::regex(".*\\.mn3"), [&c, &lb, &n_maxfiles, &filelist](const std::filesystem::path &path) { + tMissionInfo msninfo{}; + if (c < n_maxfiles) { + if (stricmp(path.filename().u8string().c_str(), "d3_2.mn3") == 0) + return; + if (GetMissionInfo(path.filename().u8string().c_str(), &msninfo) && msninfo.name[0] && msninfo.single) { + filelist[c] = mem_strdup(path.filename().u8string().c_str()); + lb->AddItem(msninfo.name); + c++; + if (!(c % 2)) + DoWaitMessage(true); + } } - } - }); + }); + } return c; } @@ -1181,8 +1187,9 @@ bool MenuNewGame() { // add mission names to listbox // count valid mission files. // add a please wait dialog here. + auto missions_directories = gd_LocateMultiplePaths("missions"); n_missions = 0; - n_missions += count_missions(D3MissionsDir); + n_missions += count_missions(missions_directories); if (n_missions) { // allocate extra mission slot because of check below which adds a name to the filelist. filelist = (char **)mem_malloc(sizeof(char *) * (n_missions + 1)); @@ -1195,7 +1202,7 @@ bool MenuNewGame() { goto missions_fail; } // generate real listbox now. - generate_mission_listbox(msn_lb, n_missions, filelist, D3MissionsDir); + generate_mission_listbox(msn_lb, n_missions, filelist, missions_directories); // #ifdef RELEASE int k; for (k = 0; k < n_missions; k++) { diff --git a/Descent3/multi.cpp b/Descent3/multi.cpp index 1e8356b9c..ac83bac8a 100644 --- a/Descent3/multi.cpp +++ b/Descent3/multi.cpp @@ -8095,23 +8095,23 @@ char *GetFileNameFromPlayerAndID(int16_t playernum, int16_t id) { break; case NETFILE_ID_SHIP_TEX: if (NetPlayers[playernum].ship_logo[0]) - ddio_MakePath(rval, Base_directory.u8string().c_str(), "custom", "graphics", NetPlayers[playernum].ship_logo, NULL); + ddio_MakePath(rval, gd_GetWritableBaseDirectory().u8string().c_str(), "custom", "graphics", NetPlayers[playernum].ship_logo, NULL); break; case NETFILE_ID_VOICE_TAUNT1: if (NetPlayers[playernum].voice_taunt1[0]) - ddio_MakePath(rval, Base_directory.u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt1, NULL); + ddio_MakePath(rval, gd_GetWritableBaseDirectory().u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt1, NULL); break; case NETFILE_ID_VOICE_TAUNT2: if (NetPlayers[playernum].voice_taunt2[0]) - ddio_MakePath(rval, Base_directory.u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt2, NULL); + ddio_MakePath(rval, gd_GetWritableBaseDirectory().u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt2, NULL); break; case NETFILE_ID_VOICE_TAUNT3: if (NetPlayers[playernum].voice_taunt3[0]) - ddio_MakePath(rval, Base_directory.u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt3, NULL); + ddio_MakePath(rval, gd_GetWritableBaseDirectory().u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt3, NULL); break; case NETFILE_ID_VOICE_TAUNT4: if (NetPlayers[playernum].voice_taunt4[0]) - ddio_MakePath(rval, Base_directory.u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt4, NULL); + ddio_MakePath(rval, gd_GetWritableBaseDirectory().u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt4, NULL); break; default: mprintf(0, "Unknown id (%d) passed to GetFileNameFromPlayerAndID()\n", id); diff --git a/Descent3/multi_dll_mgr.cpp b/Descent3/multi_dll_mgr.cpp index cfded0447..2c4f3afd5 100644 --- a/Descent3/multi_dll_mgr.cpp +++ b/Descent3/multi_dll_mgr.cpp @@ -521,6 +521,9 @@ void GetMultiAPI(multi_api *api) { api->fp[109] = (int *)GetRankIndex; api->fp[110] = (int *)CheckGetD3M; api->fp[111] = (int *)ddio_DoForeachFile; + api->fp[112] = (int *)gd_LocatePath; + api->fp[113] = (int *)gd_LocateMultiplePaths; + api->fp[114] = (int *)gd_GetWritableBaseDirectory; // Variable pointers api->vp[0] = (int *)&Player_num; @@ -528,7 +531,7 @@ void GetMultiAPI(multi_api *api) { api->vp[2] = (int *)&Game_is_master_tracker_game; api->vp[3] = (int *)&Game_mode; api->vp[4] = (int *)NULL; // Current_pilot; no longer a struct - api->vp[5] = (int *)&Base_directory; + api->vp[5] = (int *)&Base_directories; api->vp[6] = (int *)&MultiDLLGameStarting; api->vp[7] = (int *)MTPilotinfo; api->vp[8] = (int *)&Num_network_games_known; @@ -598,7 +601,7 @@ int LoadMultiDLL(const char *name) { if (MultiDLLHandle.handle) FreeMultiDLL(); - std::filesystem::path dll_path_name = Base_directory / "online"; + std::filesystem::path dll_path_name = gd_GetWritableBaseDirectory() / "online"; ddio_DoForeachFile(dll_path_name, std::regex(".+\\.tmp"), [](const std::filesystem::path& path, ...) { std::error_code ec; std::filesystem::remove(path, ec); @@ -621,8 +624,9 @@ int LoadMultiDLL(const char *name) { // Open the hog file if (!cf_OpenLibrary(lib_name)) { - ddio_MakePath(tmp_dll_name, Base_directory.u8string().c_str(), "online", name, NULL); - strcat(tmp_dll_name, ".d3c"); + std::filesystem::path tmp_dll_path = std::filesystem::path("online") / name; + tmp_dll_path += ".d3c"; + strncpy(tmp_dll_name, tmp_dll_path.u8string().c_str(), sizeof(tmp_dll_name)); Multi_conn_dll_name[0] = 0; goto loaddll; } diff --git a/Descent3/multi_ui.cpp b/Descent3/multi_ui.cpp index d8f7ed4c0..ed2eab190 100644 --- a/Descent3/multi_ui.cpp +++ b/Descent3/multi_ui.cpp @@ -442,11 +442,12 @@ int MainMultiplayerMenu() { std::vector dllnames; - ddio_DoForeachFile(Base_directory / "online", std::regex(".*\\.d3c"), - [&dllnames](const std::filesystem::path &path) { - std::string filename = path.stem().string(); + for (auto online_directory : gd_LocateMultiplePaths("online")) { + ddio_DoForeachFile(online_directory, std::regex(".*\\.d3c"), + [&dllnames](const std::filesystem::path &path) { + std::string filename = path.stem().string(); - std::replace(filename.begin(), filename.end(), '~', '/'); + std::replace(filename.begin(), filename.end(), '~', '/'); // Place PXO_NAME first in list if (stricmp(filename.c_str(), PXO_NAME) == 0) { @@ -455,6 +456,7 @@ int MainMultiplayerMenu() { dllnames.push_back(filename); } }); + } for (auto const &name : dllnames) { lists->AddItem(name.c_str()); @@ -470,9 +472,7 @@ int MainMultiplayerMenu() { exit_menu = 1; menu_wnd.Destroy(); return 0; - } - - if (dftidx != -1) { + } else { lists->SetCurrentItem(sznetgame); //>SetCurrentIndex(dftidx); } @@ -989,7 +989,7 @@ void DoMultiAllowed(void) { } void MultiDoConfigSave() { - std::filesystem::path file = Base_directory / "custom" / "settings"; + std::filesystem::path file = gd_GetWritableBaseDirectory() / "custom" / "settings"; if (DoPathFileDialog(true, file, TXT_MULTISAVESET, {"*.mps"}, 0)) { file.replace_extension(".mps"); MultiSaveSettings(file); @@ -997,7 +997,7 @@ void MultiDoConfigSave() { } void MultiDoConfigLoad() { - std::filesystem::path file = Base_directory / "custom" / "settings"; + std::filesystem::path file = gd_GetWritableBaseDirectory() / "custom" / "settings"; if (DoPathFileDialog(false, file, TXT_MULTILOADSET, {"*.mps"}, PFDF_FILEMUSTEXIST)) MultiLoadSettings(file); } diff --git a/Descent3/pilot.cpp b/Descent3/pilot.cpp index 312ac0655..50ec7cae5 100644 --- a/Descent3/pilot.cpp +++ b/Descent3/pilot.cpp @@ -1584,7 +1584,7 @@ bool PltDelete(pilot *Pilot) { std::string pfilename = Pilot->get_filename(); std::error_code ec; if (!pfilename.empty()) { - return std::filesystem::remove(Base_directory / pfilename, ec); + return std::filesystem::remove(gd_GetWritableBaseDirectory() / pfilename, ec); } else { Int3(); // this is odd @@ -1598,7 +1598,7 @@ bool PltDelete(pilot *Pilot) { PltMakeFNValid(pname); pfilename = std::string(pname) + PLTEXTENSION; - return std::filesystem::remove(Base_directory / pfilename, ec); + return std::filesystem::remove(gd_GetWritableBaseDirectory() / pfilename, ec); } } @@ -1637,7 +1637,7 @@ void PltReadFile(pilot *Pilot, bool keyconfig, bool missiondata) { return; // open and process file - std::filesystem::path filename = Base_directory / pfilename; + std::filesystem::path filename = gd_GetWritableBaseDirectory() / pfilename; try { file = cfopen(filename, "rb"); if (!file) @@ -1680,7 +1680,7 @@ std::vector PltGetPilots(std::string ignore_filename, int display_d // clear list PltClearList(); - std::filesystem::path search = std::filesystem::path(Base_directory); + std::filesystem::path search = gd_GetWritableBaseDirectory(); std::regex wildcard; std::vector result; @@ -3312,7 +3312,7 @@ void _ReadOldPilotFile(pilot *Pilot, bool keyconfig, bool missiondata) { std::string pfilename = Pilot->get_filename(); // open and process file - std::filesystem::path filename = Base_directory / pfilename; + std::filesystem::path filename = gd_GetWritableBaseDirectory() / pfilename; CFILE *file = cfopen(filename, "rb"); if (!file) return; diff --git a/Descent3/pilot_class.cpp b/Descent3/pilot_class.cpp index 58477612f..f862f93ff 100644 --- a/Descent3/pilot_class.cpp +++ b/Descent3/pilot_class.cpp @@ -417,7 +417,7 @@ int pilot::flush(bool new_file) { } CFILE *file; - std::filesystem::path real_filename = Base_directory / filename; + std::filesystem::path real_filename = gd_GetWritableBaseDirectory() / filename; if (new_file && cfexist(real_filename)) { // the file already exists, we can't write out @@ -499,7 +499,7 @@ int pilot::read(bool skip_config, bool skip_mission_data) { } CFILE *file; - std::filesystem::path real_filename = Base_directory / filename; + std::filesystem::path real_filename = gd_GetWritableBaseDirectory() / filename; if (!cfexist(real_filename)) { // the file already exists, we can't write out diff --git a/cfile/cfile.cpp b/cfile/cfile.cpp index 549e7e321..4ff083457 100644 --- a/cfile/cfile.cpp +++ b/cfile/cfile.cpp @@ -91,8 +91,8 @@ static void cf_Close(); static CFILE *open_file_in_lib(const char *filename); // Opens a HOG file. Future calls to cfopen(), etc. will look in this HOG. -// Parameters: libname - path to the HOG file, relative to Base_directory. -// NOTE: libname must be valid for the entire execution of the program. Therefore, Base_directory +// Parameters: libname - path to the HOG file, relative to one of the Base_directories. +// NOTE: libname must be valid for the entire execution of the program. Therefore, Base_directories // must not change. // Returns: 0 if error, else library handle that can be used to close the library int cf_OpenLibrary(const std::filesystem::path &libname) { diff --git a/cfile/cfile.h b/cfile/cfile.h index 787960cdd..48fc6ada6 100644 --- a/cfile/cfile.h +++ b/cfile/cfile.h @@ -145,8 +145,8 @@ enum CFileExitStatus { bool cf_IsFileInHog(const std::filesystem::path& filename, const std::filesystem::path& hogname); // Opens a HOG file. Future calls to cfopen(), etc. will look in this HOG. -// Parameters: libname - path to the HOG file, relative to Base_directory. -// NOTE: libname must be valid for the entire execution of the program. Therefore, Base_directory +// Parameters: libname - path to the HOG file, relative to one of the Base_directories. +// NOTE: libname must be valid for the entire execution of the program. Therefore, Base_directories // must not change. // Returns: 0 if error, else library handle that can be used to close the library int cf_OpenLibrary(const std::filesystem::path& libname); diff --git a/cfile/tests/cfile_tests.cpp b/cfile/tests/cfile_tests.cpp index 96cd26b77..f9ab98544 100644 --- a/cfile/tests/cfile_tests.cpp +++ b/cfile/tests/cfile_tests.cpp @@ -23,8 +23,13 @@ #include "gamedata.h" #include "cfile.h" +void run_gd_init() { + std::vector base_directories = {std::filesystem::current_path()}; + gd_Init(base_directories); +} + TEST(D3, CFileIO) { - gd_Init(std::filesystem::current_path()); + run_gd_init(); int lib_handle = cf_OpenLibrary("TestDir/test.hog"); CFILE *file_handle = cfopen("lowercase.txt", "rb"); char buf[5]; @@ -45,7 +50,7 @@ TEST(D3, CFileIO) { } TEST(D3, CFileLibrary) { - gd_Init(std::filesystem::current_path()); + run_gd_init(); // First pass - without search path in "TestDir" (i.e. not search actual files in directory) // Second pass - with search path (files in directory goes first) for (int i = 0; i < 2; i++) { diff --git a/ddio/ddio.h b/ddio/ddio.h index f512e196b..d080625ec 100644 --- a/ddio/ddio.h +++ b/ddio/ddio.h @@ -419,4 +419,4 @@ bool ddio_CreateLockFile(const std::filesystem::path &dir); */ bool ddio_DeleteLockFile(const std::filesystem::path &dir); -#endif \ No newline at end of file +#endif diff --git a/editor/MainFrm.cpp b/editor/MainFrm.cpp index ebaca3acf..a904e5769 100644 --- a/editor/MainFrm.cpp +++ b/editor/MainFrm.cpp @@ -1462,7 +1462,7 @@ void InitCScripts() { CreateNewMine(); // Setup include directories for OSIRIS - ddio_MakePath(path, Base_directory.u8string().c_str(), "data", "levels", NULL); + ddio_MakePath(path, gd_GetWritableBaseDirectory().u8string().c_str(), "data", "levels", NULL); } // Copied from winmain.cpp diff --git a/editor/editor_lighting.cpp b/editor/editor_lighting.cpp index 8fbe1059d..77b8a32fa 100644 --- a/editor/editor_lighting.cpp +++ b/editor/editor_lighting.cpp @@ -871,7 +871,7 @@ void DoRadiosityForRooms() { if (save_after_bsp) { char filename[_MAX_PATH]; - ddio_MakePath(filename, Base_directory.u8string().c_str(), "BSPSave.D3L", NULL); + ddio_MakePath(filename, gd_GetWritableBaseDirectory().u8string().c_str(), "BSPSave.D3L", NULL); // Save the level to SaveLevel(filename); @@ -1141,7 +1141,7 @@ void DoRadiosityForRooms() { SqueezeLightmaps(0, -1); char filename[_MAX_PATH + 1]; - ddio_MakePath(filename, Base_directory.u8string().c_str(), "LightSave.D3L", NULL); + ddio_MakePath(filename, gd_GetWritableBaseDirectory().u8string().c_str(), "LightSave.D3L", NULL); // Save the level to disk SaveLevel(filename); diff --git a/editor/gameeditor.cpp b/editor/gameeditor.cpp index d05057538..558d02366 100644 --- a/editor/gameeditor.cpp +++ b/editor/gameeditor.cpp @@ -614,7 +614,7 @@ void GameToEditor(bool set_viewer_from_player) { if (Temp_level_saved) { char filename[_MAX_PATH]; - ddio_MakePath(filename, Base_directory.u8string().c_str(), "GameSave.D3L", NULL); // make explicit path + ddio_MakePath(filename, gd_GetWritableBaseDirectory().u8string().c_str(), "GameSave.D3L", NULL); // make explicit path LoadLevel(filename); Temp_level_saved = 0; } @@ -754,7 +754,7 @@ void EditorToGame() { // set game working directory bool set_size = false; ddio_GetWorkingDir(Editor_dir, sizeof(Editor_dir)); - ddio_SetWorkingDir(Base_directory.u8string().c_str()); + ddio_SetWorkingDir(gd_GetWritableBaseDirectory().u8string().c_str()); Osiris_ResetAllTimers(); diff --git a/gamedata/gamedata.cpp b/gamedata/gamedata.cpp index 25e760a28..7df54aa51 100644 --- a/gamedata/gamedata.cpp +++ b/gamedata/gamedata.cpp @@ -19,26 +19,41 @@ #include "pserror.h" #include +#include #ifdef __LINUX__ #include #endif -// The "root" directory of the D3 file tree -std::filesystem::path Base_directory; +/* The "root" directories of the D3 file tree + * + * Directories that come first override directories that come later. For + * example, if Base_directories[0] / "d3_linux.hog" exists and + * Base_directories[1] / "d3_linux.hog" also exists, then the one in + * Base_directories[0] will get used. The one in Base_directories[1] will be + * ignored. This allows you to write code like this: + * + * for (auto directory : Base_directories) { + * if(file_we_need_is_in(directory)) { + * use_file_thats_in(directory); + * break; + * } + * } + */ +std::vector Base_directories; // This function must be called before you use anything else from this module. -void gd_Init(std::filesystem::path initial_base_directory) { - Base_directory = initial_base_directory; +void gd_Init(std::vector initial_base_directories) { + Base_directories = initial_base_directories; } #ifdef WIN32 -std::filesystem::path gd_LocatePathCaseInsensitiveHelper(std::filesystem::path relative_path) { - return Base_directory / relative_path; +std::filesystem::path gd_LocatePathCaseInsensitiveHelper(std::filesystem::path relative_path, std::filesystem::path starting_dir) { + return starting_dir / relative_path; } #else -std::filesystem::path gd_LocatePathCaseInsensitiveHelper(std::filesystem::path relative_path) { - auto return_value = Base_directory; +std::filesystem::path gd_LocatePathCaseInsensitiveHelper(std::filesystem::path relative_path, std::filesystem::path starting_dir) { + auto return_value = starting_dir; for (auto component : relative_path) { if (!std::filesystem::exists(return_value) || component == "." || component == "..") { return_value /= component; @@ -61,18 +76,61 @@ std::filesystem::path gd_LocatePathCaseInsensitiveHelper(std::filesystem::path r } #endif +std::vector gd_LocatePathMultiplePathsHelper(std::filesystem::path relative_path, bool stop_after_first_result) { + ASSERT(("realative_path should be a relative path.", relative_path.is_relative())); + std::vector return_value = { }; + for (auto base_directory : Base_directories) { + ASSERT(("base_directory should be an absolute path.", base_directory.is_absolute())); + auto to_append = gd_LocatePathCaseInsensitiveHelper(relative_path, base_directory); + ASSERT(("to_append should be an absolute path.", to_append.is_absolute())); + if (std::filesystem::exists(to_append)) { + return_value.insert(return_value.begin(), to_append); + if (stop_after_first_result) { + break; + } + } + } + return return_value; +} + /** - * Tries to find a relative path inside of Base_directory. + * Tries to find a relative path inside of one of the Base_directories. * * @param relative_path A relative path that we’ll hopefully find in - * Base_directory. You don’t have to get the capitalization - * of relative_path correct, even on macOS and Linux. + * one of the Base_directories. You don’t have to get the + * capitalization of relative_path correct, even on macOS + * and Linux. * - * @return An absolute path that’s inside Base_directory. + * @return Either an absolute path that’s inside Base_directory or an empty path + * if nothing is found. */ std::filesystem::path gd_LocatePath(std::filesystem::path relative_path) { - ASSERT(("realative_path should be a relative path.", relative_path.is_relative())); - auto return_value = gd_LocatePathCaseInsensitiveHelper(relative_path); - ASSERT(("return_value should be an absolute path.", return_value.is_absolute())); - return return_value; + auto return_value_list = gd_LocatePathMultiplePathsHelper(relative_path, true); + if (return_value_list.empty()) { + return ""; + } else { + return return_value_list[0]; + } +} + +/** + * Tries to find multiple relative paths inside of the Base_directories. + * + * @param relative_path A relative path that we’ll hopefully find in + * one or more of the Base_directories. You don’t have to + * get the capitalization of relative_path correct, even on + * macOS and Linux. + * + * @return A list of absolute paths. Each path will be inside one of the + * Base_directories. + */ +std::vector gd_LocateMultiplePaths(std::filesystem::path relative_path) { + return gd_LocatePathMultiplePathsHelper(relative_path, false); +} + +/* Not all Base_directories are necessarily writable, but this function will + * return one that should be writable. + */ +std::filesystem::path gd_GetWritableBaseDirectory() { + return Base_directories.back(); } diff --git a/gamedata/gamedata.h b/gamedata/gamedata.h index 24359e269..b5901cf7d 100644 --- a/gamedata/gamedata.h +++ b/gamedata/gamedata.h @@ -19,22 +19,57 @@ #define GAMEDATA_H #include +#include -// The "root" directory of the D3 file tree -extern std::filesystem::path Base_directory; +/* The "root" directories of the D3 file tree + * + * Directories that come first override directories that come later. For + * example, if Base_directories[0] / "d3_linux.hog" exists and + * Base_directories[1] / "d3_linux.hog" also exists, then the one in + * Base_directories[0] will get used. The one in Base_directories[1] will be + * ignored. This allows you to write code like this: + * + * for (auto directory : Base_directories) { + * if(file_we_need_is_in(directory)) { + * use_file_thats_in(directory); + * break; + * } + * } + */ +extern std::vector Base_directories; // This function must be called before you use anything else from this module. -void gd_Init(std::filesystem::path initial_base_directory); +void gd_Init(std::vector initial_base_directories); /** - * Tries to find a relative path inside of Base_directory. + * Tries to find a relative path inside of one of the Base_directories. * * @param relative_path A relative path that we’ll hopefully find in - * Base_directory. You don’t have to get the capitalization - * of relative_path correct, even on macOS and Linux. + * one of the Base_directories. You don’t have to get the + * capitalization of relative_path correct, even on macOS + * and Linux. * - * @return An absolute path that’s inside Base_directory. + * @return Either an absolute path that’s inside Base_directory or an empty path + * if nothing is found. */ std::filesystem::path gd_LocatePath(std::filesystem::path relative_path); +/** + * Tries to find multiple relative paths inside of the Base_directories. + * + * @param relative_path A relative path that we’ll hopefully find in + * one or more of the Base_directories. You don’t have to + * get the capitalization of relative_path correct, even on + * macOS and Linux. + * + * @return A list of absolute paths. Each path will be inside one of the + * Base_directories. + */ +std::vector gd_LocateMultiplePaths(std::filesystem::path relative_path); + +/* Not all Base_directories are necessarily writable, but this function will + * return one that should be writable. + */ +std::filesystem::path gd_GetWritableBaseDirectory(); + #endif diff --git a/gamedata/tests/gamedata_tests.cpp b/gamedata/tests/gamedata_tests.cpp index c06da5109..41b1fda31 100644 --- a/gamedata/tests/gamedata_tests.cpp +++ b/gamedata/tests/gamedata_tests.cpp @@ -20,7 +20,7 @@ #include #include "gamedata.h" -TEST(D3, CFileCaseSensitiveSearchNew) { +TEST(D3, GameDataCaseSensitiveSearch) { const std::vector test_paths = { std::filesystem::path("TestDir") / "CamelCase.txt", std::filesystem::path("TestDir") / "lowercase.txt", @@ -28,11 +28,11 @@ TEST(D3, CFileCaseSensitiveSearchNew) { }; auto cwd = std::filesystem::current_path(); - gd_Init(cwd / "no-exist-dir"); + gd_Init({cwd / "no-exist-dir"}); std::filesystem::path filename_new = gd_LocatePath("no-exist-file.txt"); EXPECT_FALSE(std::filesystem::exists(filename_new)); - gd_Init(cwd); + gd_Init({cwd}); for (auto const &item : test_paths) { std::string file_lc = item.u8string(); diff --git a/linux/lnxcontroller.cpp b/linux/lnxcontroller.cpp index 2b8521770..e6cc28d4a 100644 --- a/linux/lnxcontroller.cpp +++ b/linux/lnxcontroller.cpp @@ -1401,7 +1401,7 @@ int CTLLex(const char *command) { void lnxgameController::parse_ctl_file(int devnum, const char *ctlname) { // parse each file until we find a name match, no name match, just return ddio_DoForeachFile( - Base_directory, std::regex(".*\\.ctl"), [this, &devnum, &ctlname](const std::filesystem::path &path) { + gd_GetWritableBaseDirectory(), std::regex(".*\\.ctl"), [this, &devnum, &ctlname](const std::filesystem::path &path) { InfFile file; bool found_name = false; diff --git a/manage/manage.cpp b/manage/manage.cpp index 61302d1a8..3eeb0f065 100644 --- a/manage/manage.cpp +++ b/manage/manage.cpp @@ -676,11 +676,11 @@ int mng_LoadTableFiles(int show_progress) { // the user doesn't want network support int mng_InitLocalTables() { // Set the local table directory from the base directory. - auto base_directory_string = Base_directory.u8string(); - strncpy(LocalD3Dir, base_directory_string.c_str(), sizeof LocalD3Dir); + auto writable_base_directory_string = gd_GetWritableBaseDirectory().u8string(); + strncpy(LocalD3Dir, writable_base_directory_string.c_str(), sizeof LocalD3Dir); LocalD3Dir[sizeof LocalD3Dir - 1] = '\0'; - if (strlen(LocalD3Dir) != strlen(base_directory_string.c_str())) { - mprintf(0, "Warning: Base_directory is too long to fit in LocalD3Dir, so LocalD3Dir was truncated."); + if (strlen(LocalD3Dir) != strlen(writable_base_directory_string.c_str())) { + mprintf(0, "Warning: GetWritableBaseDirectory() is too long to fit in LocalD3Dir, so LocalD3Dir was truncated."); } mprintf(1, "Local dir:%s\n", LocalD3Dir); diff --git a/netcon/includes/con_dll.h b/netcon/includes/con_dll.h index 1a01f636f..2e34a9a15 100644 --- a/netcon/includes/con_dll.h +++ b/netcon/includes/con_dll.h @@ -272,6 +272,7 @@ #include "ship.h" #include "pstypes.h" +#include "gamedata.h" #if defined(POSIX) #include @@ -706,6 +707,15 @@ typedef void (*ddio_DoForeachFile_fp)(const std::filesystem::path &search_path, const std::function &func); ddio_DoForeachFile_fp DLLddio_DoForeachFile; +typedef decltype(&gd_LocatePath) gd_LocatePath_fp; +gd_LocatePath_fp DLLgd_LocatePath; + +typedef decltype(&gd_LocateMultiplePaths) gd_LocateMultiplePaths_fp; +gd_LocateMultiplePaths_fp DLLgd_LocateMultiplePaths; + +typedef decltype(&gd_GetWritableBaseDirectory) gd_GetWritableBaseDirectory_fp; +gd_GetWritableBaseDirectory_fp DLLgd_GetWritableBaseDirectory; + int DLLUIClass_CurrID = 0xD0; #define MAX_NET_GAMES 100 @@ -775,7 +785,7 @@ int DLLGame_mode; char *DLLTracker_id; int *DLLNum_directplay_games; netgame_info *DLLNetgame; -std::filesystem::path *DLLLocalD3Dir; +std::vector *DLLBase_directories; int *DLLMultiGameStarting; netplayer *DLLMNetPlayers; int MTWritingPilot, MTReadingPilot; @@ -1005,13 +1015,15 @@ int StartMultiplayerGameMenu() { DLLListRemoveAll(script_list); #if (!(defined(OEM) || defined(DEMO))) - DLLddio_DoForeachFile(*DLLLocalD3Dir / "netgames", std::regex(".+\\.d3m"), - [&dll_ui_items](const std::filesystem::path& path){ - dll_ui_items.insert_or_assign( - path.stem().u8string(), - DLLCreateNewUITextItem(path.stem().u8string().c_str(), UICOL_LISTBOX_LO, -1) - ); - } ); + for (auto netgames_directory : DLLgd_LocateMultiplePaths("netgames")) { + DLLddio_DoForeachFile(netgames_directory, std::regex(".+\\.d3m"), + [&dll_ui_items](const std::filesystem::path& path){ + dll_ui_items.insert_or_assign( + path.stem().u8string(), + DLLCreateNewUITextItem(path.stem().u8string().c_str(), UICOL_LISTBOX_LO, -1) + ); + } ); + } #else dll_ui_items.insert_or_assign("Anarchy", DLLCreateNewUITextItem("Anarchy", UICOL_LISTBOX_LO, -1)); dll_ui_items.insert_or_assign("Capture The Flag", DLLCreateNewUITextItem("Capture The Flag", UICOL_LISTBOX_LO, -1)); @@ -1024,9 +1036,10 @@ int StartMultiplayerGameMenu() { #if (!(defined(OEM) || defined(DEMO))) msn_list *mi; - const std::vector> search_paths = { - {*DLLLocalD3Dir / "data" / "levels", std::regex(".+\\.msn")}, - {*DLLLocalD3Dir / "missions", std::regex(".+\\.mn3")} + std::vector> search_paths = { }; + for (auto base_directory : *DLLBase_directories) { + search_paths.push_back({base_directory / "data" / "levels", std::regex(".+\\.msn")}); + search_paths.push_back({base_directory / "missions", std::regex(".+\\.mn3")}); }; for (auto const &i : search_paths) { @@ -1081,7 +1094,7 @@ int StartMultiplayerGameMenu() { DLLNetgame->flags = NF_RANDOMIZE_RESPAWN; DLLNewUIWindowLoadBackgroundImage(main_wnd, "multimain.ogf"); DLLNewUIWindowOpen(main_wnd); - if (DLLMultiLoadSettings(*DLLLocalD3Dir / "custom" / "settings" / "default.mps")) { + if (DLLMultiLoadSettings(DLLgd_GetWritableBaseDirectory() / "custom" / "settings" / "default.mps")) { DLLEditSetText(mission_name_edit, DLLNetgame->name); #if (!(defined(OEM) || defined(DEMO))) p = DLLGetMissionName(DLLNetgame->mission); diff --git a/netcon/includes/mdllinit.h b/netcon/includes/mdllinit.h index cf9b7dbbf..4a83c3ebf 100644 --- a/netcon/includes/mdllinit.h +++ b/netcon/includes/mdllinit.h @@ -275,6 +275,9 @@ DLLShowNetgameInfo = (ShowNetgameInfo_fp)API.fp[108]; // API.fp[109]; // Not used DLLCheckGetD3M = (CheckGetD3M_fp)API.fp[110]; DLLddio_DoForeachFile = (ddio_DoForeachFile_fp)API.fp[111]; +DLLgd_LocatePath = (gd_LocatePath_fp)API.fp[112]; +DLLgd_LocateMultiplePaths = (gd_LocateMultiplePaths_fp)API.fp[113]; +DLLgd_GetWritableBaseDirectory = (gd_GetWritableBaseDirectory_fp)API.fp[114]; DLLMPlayers = (player *)API.players; DLLNetgame = (netgame_info *)API.netgame; @@ -286,7 +289,7 @@ DLLTracker_id = (char *)API.vp[1]; DLLGame_is_master_tracker_game = API.vp[2]; DLLGame_mode = *API.vp[3]; // DLLCurrent_pilot = (pilot *)API.vp[4]; -DLLLocalD3Dir = (std::filesystem::path *)API.vp[5]; +DLLBase_directories = (std::vector *)API.vp[5]; DLLMultiGameStarting = (int *)API.vp[6]; DLLMTPilotinfo = (vmt_descent3_struct *)API.vp[7]; DLLNum_network_games_known = API.vp[8]; diff --git a/netcon/mtclient/mtclient.cpp b/netcon/mtclient/mtclient.cpp index e5455d53c..dca62b7f6 100644 --- a/netcon/mtclient/mtclient.cpp +++ b/netcon/mtclient/mtclient.cpp @@ -2149,7 +2149,7 @@ void CheckPXOForAnomalies() { // This is bad. It could be user error, but it could be something worse. FILE *errfile; char errfilepath[_MAX_PATH]; - DLLddio_MakePath(errfilepath, DLLLocalD3Dir->u8string().c_str(), "pxo.err", NULL); + DLLddio_MakePath(errfilepath, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "pxo.err", NULL); errfile = fopen(errfilepath, "at"); if (errfile) { fprintf(errfile, "Dup TID: %s & %s / %s\n", DLLMPlayers[j].callsign, DLLMPlayers[i].callsign, @@ -2333,12 +2333,12 @@ int MTVersionCheck() { // Load the DLL and get it's version // Specify the correct path - DLLddio_MakePath(fulldllpath, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(fulldllpath, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); if (!DLLmod_LoadModule(&MTAVDLLHandle, fulldllpath, MODF_LAZY)) { DLLmprintf(0, "Unable to load Mastertracker Auto version update DLL (mtav.dll)\n"); // Try restoring a backup of the DLL - DLLddio_MakePath(szolddll, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); - DLLddio_MakePath(szbakdll, DLLLocalD3Dir->u8string().c_str(), "mtav.bak", NULL); + DLLddio_MakePath(szolddll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(szbakdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.bak", NULL); CopyFile(szbakdll, szolddll, FALSE); return 0; } @@ -2347,8 +2347,8 @@ int MTVersionCheck() { DLLmprintf(0, "Unable to Find DLLAVInit() function in mtav.dll\n"); DLLmod_FreeModule(&MTAVDLLHandle); // Try restoring a backup of the DLL - DLLddio_MakePath(szolddll, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); - DLLddio_MakePath(szbakdll, DLLLocalD3Dir->u8string().c_str(), "mtav.bak", NULL); + DLLddio_MakePath(szolddll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(szbakdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.bak", NULL); CopyFile(szbakdll, szolddll, FALSE); return 0; } @@ -2357,8 +2357,8 @@ int MTVersionCheck() { DLLmprintf(0, "Unable to Find DLLAVGetVersion() function in mtav.dll\n"); DLLmod_FreeModule(&MTAVDLLHandle); // Try restoring a backup of the DLL - DLLddio_MakePath(szolddll, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); - DLLddio_MakePath(szbakdll, DLLLocalD3Dir->u8string().c_str(), "mtav.bak", NULL); + DLLddio_MakePath(szolddll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(szbakdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.bak", NULL); CopyFile(szbakdll, szolddll, FALSE); return 0; } @@ -2367,8 +2367,8 @@ int MTVersionCheck() { DLLmprintf(0, "Unable to Find DLLRunCheck() function in mtav.dll\n"); DLLmod_FreeModule(&MTAVDLLHandle); // Try restoring a backup of the DLL - DLLddio_MakePath(szolddll, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); - DLLddio_MakePath(szbakdll, DLLLocalD3Dir->u8string().c_str(), "mtav.bak", NULL); + DLLddio_MakePath(szolddll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(szbakdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.bak", NULL); CopyFile(szbakdll, szolddll, FALSE); return 0; } @@ -2393,8 +2393,8 @@ int MTVersionCheck() { if (MTUpdateURL[0]) { // We need to get a new DLL DLLmprintf(0, "Mastertracker says we need a new version, which is at %s.\n", MTUpdateURL); - sprintf(sznewdll, "%s\\newmtav.dll", DLLLocalD3Dir->u8string().c_str()); - DLLddio_MakePath(sznewdll, DLLLocalD3Dir->u8string().c_str(), "newmtav.dll", NULL); + sprintf(sznewdll, "%s\\newmtav.dll", DLLgd_GetWritableBaseDirectory().u8string().c_str()); + DLLddio_MakePath(sznewdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "newmtav.dll", NULL); inetfile = new InetGetFile(MTUpdateURL, sznewdll); while (1) { DLLPollUI(); @@ -2407,8 +2407,8 @@ int MTVersionCheck() { if (inetfile->IsFileReceived()) { DLLmprintf(0, "Mastertracker update DLL received.\n"); DLLmod_FreeModule(&MTAVDLLHandle); - DLLddio_MakePath(szolddll, DLLLocalD3Dir->u8string().c_str(), "mtav.dll", NULL); - DLLddio_MakePath(szbakdll, DLLLocalD3Dir->u8string().c_str(), "mtav.bak", NULL); + DLLddio_MakePath(szolddll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.dll", NULL); + DLLddio_MakePath(szbakdll, DLLgd_GetWritableBaseDirectory().u8string().c_str(), "mtav.bak", NULL); // We have the file, now backup & copy it and try to reload. CopyFile(szolddll, szbakdll, FALSE); diff --git a/win32/WinController.cpp b/win32/WinController.cpp index 3de939820..c927fef41 100644 --- a/win32/WinController.cpp +++ b/win32/WinController.cpp @@ -1677,7 +1677,7 @@ int CTLLex(const char *command) { void gameWinController::parse_ctl_file(int devnum, const char *ctlname) { // parse each file until we find a name match, no name match, just return ddio_DoForeachFile( - Base_directory, std::regex(".*\\.ctl"), [this, &devnum, &ctlname](const std::filesystem::path &path) { + gd_GetWritableBaseDirectory(), std::regex(".*\\.ctl"), [this, &devnum, &ctlname](const std::filesystem::path &path) { InfFile file; bool found_name = false;