Skip to content

Commit

Permalink
Add -aditionaldir option
Browse files Browse the repository at this point in the history
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 <path-to-proprietary-files> -additionaldir <path-to-open-source-files>

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 <path-to-writable-directory> -additionaldir <path-to-gdp-directory> -additionaldir <path-to-open-source-files>

The -additionaldir option can also be used to load a mod that replaces
.hog files:

  Descent3 -setdir <path-to-base-game-data> -additionaldir <path-to-mod-files>

[1]: <#373 (comment)>
  • Loading branch information
Jayman2000 committed Sep 29, 2024
1 parent 90e8979 commit f5d2a43
Show file tree
Hide file tree
Showing 23 changed files with 350 additions and 210 deletions.
3 changes: 1 addition & 2 deletions Descent3/Game2DLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,7 @@ bool InitGameModule(const char *name, module *mod) {

// Open the hog file
if (!cf_OpenLibrary(lib_name)) {
tmp_dll_name = Base_directory / "netgames" / name;
tmp_dll_name.replace_extension(".d3m");
tmp_dll_name = cf_LocatePath(lib_name).u8string().c_str();
Multi_game_dll_name.clear();
goto loaddll;
}
Expand Down
2 changes: 1 addition & 1 deletion Descent3/ambient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ void WriteAmbientData() {
CFILE *ofile;

#ifndef NEWEDITOR
ddio_MakePath(filename, Base_directory.u8string().c_str(), "data", "misc", AMBIENT_FILE_NAME, NULL);
ddio_MakePath(filename, cf_GetWritableBaseDirectory().u8string().c_str(), "data", "misc", AMBIENT_FILE_NAME, NULL);
#else
ddio_MakePath(filename, D3HogDir, "data", "misc", AMBIENT_FILE_NAME, NULL);
#endif
Expand Down
4 changes: 2 additions & 2 deletions Descent3/demofile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ void DemoToggleRecording() {
if (stricmp(szfile + (strlen(szfile) - 4), ".dem") != 0) {
strcat(szfile, ".dem");
}
Demo_fname = Base_directory / "demo" / szfile;
Demo_fname = cf_GetWritableBaseDirectory() / "demo" / szfile;
LOG_INFO.printf("Saving demo to file: %s", Demo_fname.u8string().c_str());
// Try to create the file
Demo_cfp = cfopen(Demo_fname, "wb");
Expand Down Expand Up @@ -1408,7 +1408,7 @@ bool LoadDemoDialog() {
// return false;
// #else

std::filesystem::path file = Base_directory / "demo";
std::filesystem::path file = cf_GetWritableBaseDirectory() / "demo";

if (DoPathFileDialog(false, file, TXT_VIEWDEMO, {"*.dem"}, PFDF_FILEMUSTEXIST)) {
Demo_fname = file;
Expand Down
2 changes: 1 addition & 1 deletion Descent3/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,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, cf_GetWritableBaseDirectory().u8string().c_str(), str, NULL);
infile = (CFILE *)cfopen(filename, "rb");
if (infile == NULL) {
done = 1;
Expand Down
8 changes: 4 additions & 4 deletions Descent3/gamesave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,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, cf_GetWritableBaseDirectory().u8string().c_str(), "savegame", filename, NULL);

fp = fopen(pathname, "rb");
if (fp) {
Expand Down Expand Up @@ -391,7 +391,7 @@ void SaveGameDialog() {
#endif

// setup paths.
ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL);
ddio_MakePath(savegame_dir, cf_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL);
// ddio_MakePath(pathname, savegame_dir, "*.sav", NULL); -unused

// create savegame directory if it didn't exist before.
Expand Down Expand Up @@ -543,7 +543,7 @@ void __cdecl LoadGameDialogCB(newuiTiledWindow *wnd, void *data)

LOG_DEBUG.printf("savegame slot=%d", id - SAVE_HOTSPOT_ID);

ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL);
ddio_MakePath(savegame_dir, cf_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL);
snprintf(filename, sizeof(filename), "saveg00%d", (id - SAVE_HOTSPOT_ID));
ddio_MakePath(pathname, savegame_dir, filename, NULL);

Expand Down Expand Up @@ -586,7 +586,7 @@ bool LoadGameDialog() {
}

// setup paths.
ddio_MakePath(savegame_dir, Base_directory.u8string().c_str(), "savegame", NULL);
ddio_MakePath(savegame_dir, cf_GetWritableBaseDirectory().u8string().c_str(), "savegame", NULL);
ddio_MakePath(pathname, savegame_dir, "*.sav", NULL);

// create savegame directory if it didn't exist before.
Expand Down
31 changes: 22 additions & 9 deletions Descent3/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1390,12 +1390,12 @@ void LoadGameSettings() {
void InitIOSystems(bool editor) {
ddio_init_info io_info;

// 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));
Expand All @@ -1404,15 +1404,28 @@ void InitIOSystems(bool editor) {
Error("Failed to get executable path\n");
} else {
std::filesystem::path executablePath(exec_path);
initial_base_directory = executablePath.parent_path();
LOG_INFO << "Using working directory of " << Base_directory;
writable_base_directory = executablePath.parent_path();
LOG_INFO << "Using working directory of " << writable_base_directory;
}
} else {
initial_base_directory = std::filesystem::current_path();
writable_base_directory = std::filesystem::current_path();
}

cf_SetBaseDirectory(initial_base_directory);
ddio_SetWorkingDir(Base_directory.u8string().c_str());
ddio_SetWorkingDir(writable_base_directory.u8string().c_str());
cf_AddBaseDirectory(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) {
LOG_WARNING << "-additionaldir was at the end of the argument list. It should never be at the end of the argument list.";
break;
} else {
cf_AddBaseDirectory(std::filesystem::path(dir_to_add));
additionaldirarg += 2;
}
}

Descent->set_defer_handler(D3DeferHandler);

Expand Down Expand Up @@ -2015,7 +2028,7 @@ void SetupTempDirectory(void) {
exit(1);
}
// restore working dir
ddio_SetWorkingDir(Base_directory.u8string().c_str());
ddio_SetWorkingDir(cf_GetWritableBaseDirectory().u8string().c_str());
}

void DeleteTempFiles() {
Expand Down
75 changes: 40 additions & 35 deletions Descent3/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1061,51 +1061,55 @@ bool ProcessCommandLine() {
#define TRAINING_MISSION_NAME "Pilot Training"

/**
* Count singleplayer missions in directory. Mission should have .mn3 extension.
* @param missions_directory 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<std::filesystem::path> &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;
LOG_DEBUG.printf("Mission path: %s", path.u8string().c_str());
tMissionInfo msninfo{};
GetMissionInfo(path.filename().u8string().c_str(), &msninfo);
for (const 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;
LOG_DEBUG.printf("Mission path: %s", path.u8string().c_str());
tMissionInfo msninfo{};
GetMissionInfo(path.filename().u8string().c_str(), &msninfo);

if (msninfo.name[0] && msninfo.single) {
LOG_DEBUG.printf("Name: %s", msninfo.name);
c++;
if (!(c % 2))
DoWaitMessage(true);
} else {
LOG_DEBUG.printf("Illegal or multiplayer mission: %s", path.u8string().c_str());
}
});
if (msninfo.name[0] && msninfo.single) {
LOG_DEBUG.printf("Name: %s", msninfo.name);
c++;
if (!(c % 2))
DoWaitMessage(true);
} else {
LOG_DEBUG.printf("Illegal or multiplayer mission: %s", 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<std::filesystem::path> &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 (const 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;
}
Expand Down Expand Up @@ -1182,8 +1186,9 @@ bool MenuNewGame() {
// add mission names to listbox
// count valid mission files.
// add a please wait dialog here.
auto missions_directories = cf_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));
Expand All @@ -1196,7 +1201,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++) {
Expand Down
10 changes: 5 additions & 5 deletions Descent3/multi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8010,23 +8010,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, cf_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, cf_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, cf_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, cf_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, cf_GetWritableBaseDirectory().u8string().c_str(), "custom", "sounds", NetPlayers[playernum].voice_taunt4, NULL);
break;
default:
LOG_FATAL.printf("Unknown id (%d) passed to GetFileNameFromPlayerAndID()", id);
Expand Down
9 changes: 6 additions & 3 deletions Descent3/multi_dll_mgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,14 +520,17 @@ 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 *)cf_LocatePath;
api->fp[113] = (int *)cf_LocateMultiplePaths;
api->fp[114] = (int *)cf_GetWritableBaseDirectory;

// Variable pointers
api->vp[0] = (int *)&Player_num;
api->vp[1] = (int *)Tracker_id;
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 *)NULL; // Base_directory; no longer exists
api->vp[6] = (int *)&MultiDLLGameStarting;
api->vp[7] = (int *)MTPilotinfo;
api->vp[8] = (int *)&Num_network_games_known;
Expand Down Expand Up @@ -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 = cf_GetWritableBaseDirectory() / "online";
ddio_DoForeachFile(dll_path_name, std::regex(".+\\.tmp"), [](const std::filesystem::path& path, ...) {
std::error_code ec;
std::filesystem::remove(path, ec);
Expand All @@ -616,7 +619,7 @@ int LoadMultiDLL(const char *name) {

// Open the hog file
if (!cf_OpenLibrary(lib_name)) {
tmp_dll_name = Base_directory / "online" / name;
tmp_dll_name = std::filesystem::path("online") / name;
tmp_dll_name.replace_extension(".d3c");
Multi_conn_dll_name.clear();
goto loaddll;
Expand Down
14 changes: 8 additions & 6 deletions Descent3/multi_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,11 +442,12 @@ int MainMultiplayerMenu() {

std::vector<std::string> dllnames;

ddio_DoForeachFile(Base_directory / "online", std::regex(".*\\.d3c"),
[&dllnames](const std::filesystem::path &path) {
std::string filename = path.stem().string();
for (const auto &online_directory : cf_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) {
Expand All @@ -455,6 +456,7 @@ int MainMultiplayerMenu() {
dllnames.push_back(filename);
}
});
}

for (auto const &name : dllnames) {
lists->AddItem(name.c_str());
Expand Down Expand Up @@ -989,15 +991,15 @@ void DoMultiAllowed(void) {
}

void MultiDoConfigSave() {
std::filesystem::path file = Base_directory / "custom" / "settings";
std::filesystem::path file = cf_GetWritableBaseDirectory() / "custom" / "settings";
if (DoPathFileDialog(true, file, TXT_MULTISAVESET, {"*.mps"}, 0)) {
file.replace_extension(".mps");
MultiSaveSettings(file);
}
}

void MultiDoConfigLoad() {
std::filesystem::path file = Base_directory / "custom" / "settings";
std::filesystem::path file = cf_GetWritableBaseDirectory() / "custom" / "settings";
if (DoPathFileDialog(false, file, TXT_MULTILOADSET, {"*.mps"}, PFDF_FILEMUSTEXIST))
MultiLoadSettings(file);
}
Expand Down
Loading

0 comments on commit f5d2a43

Please sign in to comment.