diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index 6b5489e2e..0339f9c8a 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -1250,7 +1250,7 @@ int app_main(int argc, char const * const * argv) ParseOptions(); G_ExtInit(); - G_AddSearchPaths(); + //G_AddSearchPaths(); #ifdef STARTUP_SETUP_WINDOW diff --git a/source/blood/src/common.cpp b/source/blood/src/common.cpp index 66f5f74ab..6fdb4e0f5 100644 --- a/source/blood/src/common.cpp +++ b/source/blood/src/common.cpp @@ -260,321 +260,6 @@ void G_LoadGroups() pathsearchmode = bakpathsearchmode; } -#if defined _WIN32 -static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize) -{ - // KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds - REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY }; - - for (auto &wow64key : wow64keys) - { - HKEY hkey; - LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey); - - if (keygood != ERROR_SUCCESS) - continue; - - LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize); - - RegCloseKey(hkey); - - if (retval == ERROR_SUCCESS) - return 1; - } - - return 0; -} -#endif - -#ifndef EDUKE32_TOUCH_DEVICES -#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD -static void G_AddSteamPaths(const char *basepath) -{ - UNREFERENCED_PARAMETER(basepath); -#if 0 - char buf[BMAX_PATH]; - - // PORT-TODO: - // Duke Nukem 3D: Megaton Edition (Steam) - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath); - addsearchpath(buf); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - - // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) -#if defined EDUKE32_OSX - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); -#endif -#endif -} - -// A bare-bones "parser" for Valve's KeyValues VDF format. -// There is no guarantee this will function properly with ill-formed files. -static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend) -{ - while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - // comments - if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/') - { - while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - } -} -static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend) -{ - (*vdfbuf)++; - while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend) -{ - while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return; - - if ((*vdfbuf)[0] == '{') - { - (*vdfbuf)++; - do - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - } - while ((*vdfbuf)[0] != '}'); - (*vdfbuf)++; - } - else if ((*vdfbuf)[0] == '\"') - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - else if ((*vdfbuf)[0] != '}') - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend) -{ - char *token = *vdfbuf; - - if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend) - { - token++; - - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - // account for escape sequences - char *writeseeker = token, *readseeker = token; - while (readseeker <= *vdfbuf) - { - if (readseeker[0] == '\\') - readseeker++; - - writeseeker[0] = readseeker[0]; - - writeseeker++; - readseeker++; - } - - return token; - } - - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - return token; -} -static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - if (token != NULL) // pass in NULL to find the next key instead of a specific one - while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return 0; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - if (*vdfbuf == vdfbufend) - return 0; - - return 1; -} -static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return NULL; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return NULL; - - return KeyValues_NormalizeToken(vdfbuf, vdfbufend); -} - -static void G_ParseSteamKeyValuesForPaths(const char *vdf) -{ - buildvfs_fd fd = buildvfs_open_read(vdf); - int32_t size = buildvfs_length(fd); - char *vdfbufstart, *vdfbuf, *vdfbufend; - - if (size <= 0) - return; - - vdfbufstart = vdfbuf = (char*)Xmalloc(size); - size = (int32_t)buildvfs_read(fd, vdfbuf, size); - buildvfs_close(fd); - vdfbufend = vdfbuf + size; - - if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders")) - { - char *result; - vdfbuf++; - while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL) - G_AddSteamPaths(result); - } - - Xfree(vdfbufstart); -} -#endif -#endif - -void G_AddSearchPaths(void) -{ -#ifndef EDUKE32_TOUCH_DEVICES -#if defined __linux__ || defined EDUKE32_BSD - char buf[BMAX_PATH]; - char *homepath = Bgethomedir(); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath); - G_ParseSteamKeyValuesForPaths(buf); - - Bfree(homepath); - - addsearchpath("/usr/share/games/nblood"); - addsearchpath("/usr/local/share/games/nblood"); -#elif defined EDUKE32_OSX - char buf[BMAX_PATH]; - int32_t i; - char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) }; - char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) }; - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]); - G_ParseSteamKeyValuesForPaths(buf); - -#if 0 - // Duke Nukem 3D: Atomic Edition (GOG.com) - Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]); - addsearchpath_user(buf, SEARCHPATH_REMOVE); -#endif - } - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/NBlood", support[i]); - addsearchpath(buf); - } - - for (i = 0; i < 2; i++) - { - Bfree(applications[i]); - Bfree(support[i]); - } -#elif defined (_WIN32) - char buf[BMAX_PATH] = {0}; - DWORD bufsize; - bool found = false; - - // Blood: One Unit Whole Blood (Steam) - bufsize = sizeof(buf); - if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 299030)", "InstallLocation", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - found = true; - } - - // Blood: One Unit Whole Blood (GOG.com) - bufsize = sizeof(buf); - if (!found && G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGONEUNITONEBLOOD", "PATH", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - found = true; - } - - // Blood: Fresh Supply (Steam) - bufsize = sizeof(buf); - if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 1010750)", "InstallLocation", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - strncat(buf, R"(\addons\Cryptic Passage)", 23); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - found = true; - } - - // Blood: Fresh Supply (GOG.com) - bufsize = sizeof(buf); - if (!found && G_ReadRegistryValue(R"(SOFTWARE\Wow6432Node\GOG.com\Games\1374469660)", "path", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - strncat(buf, R"(\addons\Cryptic Passage)", 23); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - found = true; - } -#endif -#endif -} - void G_CleanupSearchPaths(void) { removesearchpaths_withuser(SEARCHPATH_REMOVE); diff --git a/source/common/filesystem/file_directory.cpp b/source/common/filesystem/file_directory.cpp index fb95f64bb..3bc15b951 100644 --- a/source/common/filesystem/file_directory.cpp +++ b/source/common/filesystem/file_directory.cpp @@ -119,15 +119,14 @@ FDirectory::FDirectory(const char * directory) int FDirectory::AddDirectory(const char *dirpath) { - struct _finddata_t fileinfo; + auto dirmatch = WideString(dirpath); + struct _wfinddata_t fileinfo; intptr_t handle; - FString dirmatch; int count = 0; - dirmatch = dirpath; dirmatch += '*'; - if ((handle = _findfirst(dirmatch, &fileinfo)) == -1) + if ((handle = _wfindfirst(wdirmatch, &fileinfo)) == -1) { Printf("Could not scan '%s': %s\n", dirpath, strerror(errno)); } @@ -141,18 +140,19 @@ int FDirectory::AddDirectory(const char *dirpath) // info from being included.) continue; } + FString fi = FString(fileinfo.name); if (fileinfo.attrib & _A_SUBDIR) { - if (fileinfo.name[0] == '.' && - (fileinfo.name[1] == '\0' || - (fileinfo.name[1] == '.' && fileinfo.name[2] == '\0'))) + if (fi[0] == '.' && + (fi[1] == '\0' || + (fi[1] == '.' && fi[2] == '\0'))) { // Do not record . and .. directories. continue; } FString newdir = dirpath; - newdir << fileinfo.name << '/'; + newdir << fi << '/'; count += AddDirectory(newdir); } else @@ -163,10 +163,10 @@ int FDirectory::AddDirectory(const char *dirpath) continue; } - AddEntry(FString(dirpath) + fileinfo.name, fileinfo.size); + AddEntry(FString(dirpath) + fi, fileinfo.size); count++; } - } while (_findnext(handle, &fileinfo) == 0); + } while (_wfindnext(handle, &fileinfo) == 0); _findclose(handle); } return count; diff --git a/source/common/gameconfigfile.cpp b/source/common/gameconfigfile.cpp index 08788ecb2..dd5c5f57f 100644 --- a/source/common/gameconfigfile.cpp +++ b/source/common/gameconfigfile.cpp @@ -87,12 +87,15 @@ FGameConfigFile::FGameConfigFile () SetValueForKey ("Path", "./*", true); #ifdef __APPLE__ SetValueForKey ("Path", user_docs + "/*", true); - SetValueForKey ("Path", user_app_support + "/*", true); + SetValueForKey ("Path", user_app_support + "/EDuke32", true); + SetValueForKey ("Path", user_app_support + "/JFDuke32", true); + SetValueForKey ("Path", user_app_support + "/NBlood", true); SetValueForKey ("Path", "$PROGDIR", true); SetValueForKey ("Path", "$PROGDIR/*", true); - SetValueForKey ("Path", local_app_support + "/*", true); + SetValueForKey ("Path", local_app_support + "/EDuke32", true); + SetValueForKey ("Path", local_app_support + "/JFDuke32", true); + SetValueForKey ("Path", local_app_support + "/NBlood", true); #elif !defined(__unix__) - SetValueForKey ("Path", "$HOME/*", true); SetValueForKey ("Path", "$PROGDIR", true); SetValueForKey ("Path", "$PROGDIR/*", true); #else @@ -100,11 +103,15 @@ FGameConfigFile::FGameConfigFile () // Arch Linux likes them in /usr/share/doom // Debian likes them in /usr/share/games/doom // I assume other distributions don't do anything radically different - SetValueForKey ("Path", "/usr/local/share", true); - SetValueForKey ("Path", "/usr/local/share/games", true); - SetValueForKey ("Path", "/usr/share/doom", true); - SetValueForKey ("Path", "/usr/share/games", true); + SetValueForKey ("Path", "/usr/share/games/jfduke3d", true); + SetValueForKey ("Path", "/usr/local/share/games/jfduke3d", true); + SetValueForKey ("Path", "/usr/share/games/eduke32", true); + SetValueForKey ("Path", "/usr/local/share/games/eduke32", true); + SetValueForKey ("Path", "/usr/share/games/nblood", true); + SetValueForKey ("Path", "/usr/local/share/games/nblood", true); + #endif + SetValueForKey ("Path", "$STEAM", true); // also covers GOG. } // Set default search paths if none present @@ -122,10 +129,12 @@ FGameConfigFile::FGameConfigFile () #else SetValueForKey ("Path", "$HOME/" GAME_DIR, true); SetValueForKey ("Path", SHARE_DIR, true); - SetValueForKey ("Path", "/usr/local/share/doom", true); - SetValueForKey ("Path", "/usr/local/share/games/doom", true); - SetValueForKey ("Path", "/usr/share/doom", true); - SetValueForKey ("Path", "/usr/share/games/doom", true); + SetValueForKey ("Path", "/usr/share/games/jfduke3d", true); + SetValueForKey ("Path", "/usr/local/share/games/jfduke3d", true); + SetValueForKey ("Path", "/usr/share/games/eduke32", true); + SetValueForKey ("Path", "/usr/local/share/games/eduke32", true); + SetValueForKey ("Path", "/usr/share/games/nblood", true); + SetValueForKey ("Path", "/usr/local/share/games/nblood", true); #endif } diff --git a/source/common/searchpaths.cpp b/source/common/searchpaths.cpp new file mode 100644 index 000000000..2feaa321a --- /dev/null +++ b/source/common/searchpaths.cpp @@ -0,0 +1,657 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010-2019 EDuke32 developers and contributors +Copyright (C) 2019 Nuke.YKT +Copyright (C) 2019 Christoph Oelckers + + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +// +// Search path management +// + + +#if defined _WIN32 +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize) +{ + // KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds + REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY }; + + for (auto &wow64key : wow64keys) + { + HKEY hkey; + LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey); + + if (keygood != ERROR_SUCCESS) + continue; + + LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize); + + RegCloseKey(hkey); + + if (retval == ERROR_SUCCESS) + return 1; + } + + return 0; +} +#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__) || defined (__linux__) +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +static void G_AddSteamPaths(TArray &searchpaths, const char *basepath) +{ + FString path; + + // Duke Nukem 3D: Megaton Edition (Steam) + path.Format("%s/steamapps/common/Duke Nukem 3D/gameroot", basepath); + searchpaths.Push(path); + path.Format("%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath); + searchpaths.Push(path); + path.Format("%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath); + searchpaths.Push(path); + path.Format("%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath); + searchpaths.Push(path); + + // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) +#ifdef __APPLE__ + path.Format("%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath); + searchpaths.Push(path); +#endif + + // NAM (Steam) +#ifdef __APPLE__ + path.Format("%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath); +#else + path.Format("%s/steamapps/common/Nam/NAM", basepath); +#endif + searchpaths.Push(path); + + // WWII GI (Steam) + path.Format("%s/steamapps/common/World War II GI/WW2GI", basepath); + searchpaths.Push(path); +} + +//------------------------------------------------------------------------- +// +// A bare-bones "parser" for Valve's KeyValues VDF format. +// There is no guarantee this will function properly with ill-formed files. +// +//------------------------------------------------------------------------- + +static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend) +{ + while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend) + (*vdfbuf)++; + + // comments + if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/') + { + while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend) + (*vdfbuf)++; + + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); + } +} +static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend) +{ + (*vdfbuf)++; + while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend) + (*vdfbuf)++; +} +static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend) +{ + while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend) + (*vdfbuf)++; +} +static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend) +{ + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); + + if (*vdfbuf == vdfbufend) + return; + + if ((*vdfbuf)[0] == '{') + { + (*vdfbuf)++; + do + { + KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); + } + while ((*vdfbuf)[0] != '}'); + (*vdfbuf)++; + } + else if ((*vdfbuf)[0] == '\"') + KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); + else if ((*vdfbuf)[0] != '}') + KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); + + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); +} +static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend) +{ + char *token = *vdfbuf; + + if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend) + { + token++; + + KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); + (*vdfbuf)[0] = '\0'; + + // account for escape sequences + char *writeseeker = token, *readseeker = token; + while (readseeker <= *vdfbuf) + { + if (readseeker[0] == '\\') + readseeker++; + + writeseeker[0] = readseeker[0]; + + writeseeker++; + readseeker++; + } + + return token; + } + + KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); + (*vdfbuf)[0] = '\0'; + + return token; +} +static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token) +{ + char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); + if (token != NULL) // pass in NULL to find the next key instead of a specific one + while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend) + { + KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); + ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); + } + + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); +} +static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token) +{ + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); + + // end of scope + if ((*vdfbuf)[0] == '}') + return 0; + + KeyValues_FindKey(vdfbuf, vdfbufend, token); + + // ignore the wrong type + while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend) + { + KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); + KeyValues_FindKey(vdfbuf, vdfbufend, token); + } + + if (*vdfbuf == vdfbufend) + return 0; + + return 1; +} +static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token) +{ + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); + + // end of scope + if ((*vdfbuf)[0] == '}') + return NULL; + + KeyValues_FindKey(vdfbuf, vdfbufend, token); + + // ignore the wrong type + while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend) + { + KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); + KeyValues_FindKey(vdfbuf, vdfbufend, token); + } + + KeyValues_SkipWhitespace(vdfbuf, vdfbufend); + + if (*vdfbuf == vdfbufend) + return NULL; + + return KeyValues_NormalizeToken(vdfbuf, vdfbufend); +} + +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +static void G_ParseSteamKeyValuesForPaths(TArray &searchpaths, const char *vdf) +{ + FileReader fr; + if (fr.Open(vdf)) + { + auto data = fr.Read(); + if (data.Size() == 0) return; + } + + auto vdfvuf = (char*)data.Data(); + auto vdfbufend = vdfbuf + data.Size(); + + if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders")) + { + char *result; + vdfbuf++; + while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL) + G_AddSteamPaths(searchpaths, result); + } +} +#endif + + +#if defined (__FreeBSD__) || defined(__OpenBSD__) || defined (__linux__) + +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +void G_AddExternalSearchPaths(TArray &searchpaths) +{ + FString path; + char *homepath = Bgethomedir(); + + path.Format("%s/.steam/steam", homepath); + G_AddSteamPaths(searchpaths, buf); + + path.Format("%s/.steam/steam/steamapps/libraryfolders.vdf", homepath); + G_ParseSteamKeyValuesForPaths(searchpaths, buf); +} + +#elif defined __APPLE__ + +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +void G_AddExternalSearchPaths(TArray &searchpaths) +{ + char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) }; + char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) }; + + FString path; + + char buf[BMAX_PATH]; + int32_t i; + + for (i = 0; i < 2; i++) + { + path.Format("%s/Steam", support[i]); + G_AddSteamPaths(searchpaths, buf); + + path.Format("%s/Steam/steamapps/libraryfolders.vdf", support[i]); + G_ParseSteamKeyValuesForPaths(searchpaths, buf); + + // Duke Nukem 3D: Atomic Edition (GOG.com) + path.Format("%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]); + searchpaths.Push(path); + } + + for (i = 0; i < 2; i++) + { + Xfree(applications[i]); + Xfree(support[i]); + } +} + +#elif defined (_WIN32) + +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +void G_AddExternalSearchPaths(TArray &searchpaths) +{ + + char buf[BMAX_PATH] = {0}; + DWORD bufsize; + + // Duke Nukem 3D: 20th Anniversary World Tour (Steam) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Duke Nukem 3D: Megaton Edition (Steam) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + strncpy(suffix, "/gameroot", remaining); + searchpaths.Push(buf); + strncpy(suffix, "/gameroot/addons/dc", remaining); + searchpaths.Push(buf); + strncpy(suffix, "/gameroot/addons/nw", remaining); + searchpaths.Push(buf); + strncpy(suffix, "/gameroot/addons/vacation", remaining); + searchpaths.Push(buf); + } + + // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + strncpy(suffix, "/Duke Nukem 3D", remaining); + searchpaths.Push(buf); + } + + // Duke Nukem 3D: Atomic Edition (GOG.com) + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Duke Nukem 3D (3D Realms Anthology) + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + Bstrncpy(suffix, "/Duke Nukem 3D", remaining); + searchpaths.Push(buf); + } + + // 3D Realms Anthology + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + Bstrncpy(suffix, "/Duke Nukem 3D", remaining); + searchpaths.Push(buf); + } + + // NAM (Steam) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + Bstrncpy(suffix, "/NAM", remaining); + searchpaths.Push(buf); + } + + // WWII GI (Steam) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize)) + { + char * const suffix = buf + bufsize - 1; + size_t const remaining = sizeof(buf) - bufsize; + + Bstrncpy(suffix, "/WW2GI", remaining); + searchpaths.Push(buf); + } + + // Redneck Rampage (GOG.com) + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGREDNECKRAMPAGE", "PATH", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Redneck Rampage Rides Again (GOG.com) + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGCREDNECKRIDESAGAIN", "PATH", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Blood: One Unit Whole Blood (Steam) + bufsize = sizeof(buf); + if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 299030)", "InstallLocation", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Blood: One Unit Whole Blood (GOG.com) + bufsize = sizeof(buf); + if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGONEUNITONEBLOOD", "PATH", buf, &bufsize)) + { + searchpaths.Push(buf); + } + + // Blood: Fresh Supply (Steam) + bufsize = sizeof(buf); + if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 1010750)", "InstallLocation", buf, &bufsize)) + { + searchpaths.Push(buf); + strncat(buf, R"(\addons\Cryptic Passage)", 23); + searchpaths.Push(buf); + } + + // Blood: Fresh Supply (GOG.com) + bufsize = sizeof(buf); + if (!found && G_ReadRegistryValue(R"(SOFTWARE\Wow6432Node\GOG.com\Games\1374469660)", "path", buf, &bufsize)) + { + searchpaths.Push(buf); + strncat(buf, R"(\addons\Cryptic Passage)", 23); + searchpaths.Push(buf); + } +} +#endif + +//------------------------------------------------------------------------- +// +// +// +//------------------------------------------------------------------------- + +void AddExpandedPath(TArray &searchpaths, const char *basepath) +{ + +} + +#ifdef _WIN32 +//========================================================================== +// +// Windows version +// +//========================================================================== + +void CollectSubdirectories(TArray &searchpath, const char *dirmatch) +{ + struct _wfinddata_t fileinfo; + intptr_t handle; + FString dirpath; + int count = 0; + auto wdirmatch = WideString(dirmatch); + + dirpath.Truncate(dirpath.Len()-1); // remove the '*' + + if ((handle = _wfindfirst(wdirmatch, &fileinfo)) == -1) + { + // silently ignore non-existent paths + return; + } + else + { + do + { + if (fileinfo.attrib & _A_HIDDEN) + { + // Skip hidden files and directories. (Prevents SVN bookkeeping + // info from being included.) + continue; + } + FString fi = FString(fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { + + if (fi[0] == '.' && + (fi[1] == '\0' || + (fi[1] == '.' && fi[2] == '\0'))) + { + // Do not record . and .. directories. + continue; + } + FString newdir = dirpath + fi; + count += AddDirectory(newdir); + } + } while (_wfindnext(handle, &fileinfo) == 0); + _findclose(handle); + } + return count; +} + +#else + +//========================================================================== +// +// add_dirs +// 4.4BSD version +// +//========================================================================== + +void FDirectory::AddDirectory(const char *dirpath) +{ + char *argv [2] = { NULL, NULL }; + argv[0] = new char[strlen(dirpath)+1]; + strcpy(argv[0], dirpath); + FTS *fts; + FTSENT *ent; + + fts = fts_open(argv, FTS_LOGICAL, NULL); + if (fts == NULL) + { + return 0; + } + + const size_t namepos = strlen(dirpath); + FString pathfix; + + while ((ent = fts_read(fts)) != NULL) + { + if (ent->fts_info != FTS_D) + { + // We're only interested in getting directories. + continue; + } + fts_set(fts, ent, FTS_SKIP); + if (ent->fts_name[0] == '.') + { + // Skip hidden directories. (Prevents SVN bookkeeping + // info from being included.) + } + + // Some implementations add an extra separator between + // root of the hierarchy and entity's path. + // It needs to be removed in order to resolve + // lumps' relative paths properly. + const char* path = ent->fts_path; + + if ('/' == path[namepos]) + { + pathfix = FString(path, namepos); + pathfix.AppendCStrPart(&path[namepos + 1], ent->fts_pathlen - namepos - 1); + + path = pathfix.GetChars(); + } + + searchpaths.Push(path); + } + fts_close(fts); + delete[] argv[0]; +} +#endif + +//========================================================================== +// +// CollectSearchPaths +// +// collect all paths in a local array for easier management +// +//========================================================================== + +TArray CollectSearchPaths() +{ + TArray searchpths; + + if (GameConfig->SetSection("GameSearch.Directories")) + { + const char *key; + const char *value; + + while (GameConfig->NextInSection(key, value)) + { + if (stricmp(key, "Path") == 0) + { + FString nice = NicePath(value); + if (nice.Len() > 0) + { +#ifdef _WIN32 + if (isalpha(nice[0] && nice[1] == ':' && nice[2] != '/') continue; // ignore drive relative paths because they are meaningless. +#endif + // A path ending with "/*" means to add all subdirectories. + if (nice[nice.Len()-2] == '/' && nice[nice.Len()-1] == '*') + { + AddExpandedPath(searchpaths, nice); + } + // Checking Steam via a list entry allows easy removal if not wanted. + else if (nice.CompareNoCase("$STEAM")) + { + G_AddExternalSearchPaths(searchpaths); + } + else + { + mSearchPaths.Push(nice); + } + } + } + } + } + // Unify and remove trailing slashes + for (auto &str : mSearchPaths) + { + str.Substitute("\\", "/"); + if (str.Back() == '/') str.Truncate(str.Len() - 1); + } +} + diff --git a/source/duke3d/src/common.cpp b/source/duke3d/src/common.cpp index 2969cf3e4..31cb75a15 100644 --- a/source/duke3d/src/common.cpp +++ b/source/duke3d/src/common.cpp @@ -315,20 +315,6 @@ void G_ExtInit(void) Xfree(homedir); } } - - // JBF 20031220: Because it's annoying renaming GRP files whenever I want to test different game data -#ifndef EDUKE32_STANDALONE - if (g_grpNamePtr == NULL) - { - const char *cp = getenv("DUKE3DGRP"); - if (cp) - { - clearGrpNamePtr(); - g_grpNamePtr = dup_filename(cp); - initprintf("Using \"%s\" as main GRP file\n", g_grpNamePtr); - } - } -#endif } void G_ScanGroups(void) @@ -492,31 +478,7 @@ void G_LoadGroups() pathsearchmode = bakpathsearchmode; } -#if defined _WIN32 && !defined EDUKE32_STANDALONE -static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize) -{ - // KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds - REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY }; - for (auto &wow64key : wow64keys) - { - HKEY hkey; - LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey); - - if (keygood != ERROR_SUCCESS) - continue; - - LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize); - - RegCloseKey(hkey); - - if (retval == ERROR_SUCCESS) - return 1; - } - - return 0; -} -#endif static void G_LoadAddon(void) { @@ -545,357 +507,6 @@ static void G_LoadAddon(void) #endif } -#ifndef EDUKE32_STANDALONE -#ifndef EDUKE32_TOUCH_DEVICES -#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD -static void G_AddSteamPaths(const char *basepath) -{ - char buf[BMAX_PATH]; - - // Duke Nukem 3D: Megaton Edition (Steam) - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath); - addsearchpath(buf); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - - // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) -#if defined EDUKE32_OSX - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); -#endif - - // NAM (Steam) -#if defined EDUKE32_OSX - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath); -#else - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/NAM", basepath); -#endif - addsearchpath_user(buf, SEARCHPATH_NAM); - - // WWII GI (Steam) - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/World War II GI/WW2GI", basepath); - addsearchpath_user(buf, SEARCHPATH_WW2GI); -} - -// A bare-bones "parser" for Valve's KeyValues VDF format. -// There is no guarantee this will function properly with ill-formed files. -static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend) -{ - while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - // comments - if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/') - { - while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - } -} -static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend) -{ - (*vdfbuf)++; - while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend) -{ - while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return; - - if ((*vdfbuf)[0] == '{') - { - (*vdfbuf)++; - do - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - } - while ((*vdfbuf)[0] != '}'); - (*vdfbuf)++; - } - else if ((*vdfbuf)[0] == '\"') - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - else if ((*vdfbuf)[0] != '}') - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend) -{ - char *token = *vdfbuf; - - if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend) - { - token++; - - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - // account for escape sequences - char *writeseeker = token, *readseeker = token; - while (readseeker <= *vdfbuf) - { - if (readseeker[0] == '\\') - readseeker++; - - writeseeker[0] = readseeker[0]; - - writeseeker++; - readseeker++; - } - - return token; - } - - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - return token; -} -static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - if (token != NULL) // pass in NULL to find the next key instead of a specific one - while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return 0; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - if (*vdfbuf == vdfbufend) - return 0; - - return 1; -} -static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return NULL; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return NULL; - - return KeyValues_NormalizeToken(vdfbuf, vdfbufend); -} - -static void G_ParseSteamKeyValuesForPaths(const char *vdf) -{ - buildvfs_fd fd = buildvfs_open_read(vdf); - int32_t size = buildvfs_length(fd); - char *vdfbufstart, *vdfbuf, *vdfbufend; - - if (size <= 0) - return; - - vdfbufstart = vdfbuf = (char*)Xmalloc(size); - size = (int32_t)buildvfs_read(fd, vdfbuf, size); - buildvfs_close(fd); - vdfbufend = vdfbuf + size; - - if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders")) - { - char *result; - vdfbuf++; - while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL) - G_AddSteamPaths(result); - } - - Xfree(vdfbufstart); -} -#endif -#endif -#endif - -void G_AddSearchPaths(void) -{ -#ifndef EDUKE32_STANDALONE -#ifndef EDUKE32_TOUCH_DEVICES -#if defined __linux__ || defined EDUKE32_BSD - char buf[BMAX_PATH]; - char *homepath = Bgethomedir(); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath); - G_ParseSteamKeyValuesForPaths(buf); - - Xfree(homepath); - - addsearchpath("/usr/share/games/jfduke3d"); - addsearchpath("/usr/local/share/games/jfduke3d"); - addsearchpath("/usr/share/games/eduke32"); - addsearchpath("/usr/local/share/games/eduke32"); -#elif defined EDUKE32_OSX - char buf[BMAX_PATH]; - int32_t i; - char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) }; - char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) }; - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]); - G_ParseSteamKeyValuesForPaths(buf); - - // Duke Nukem 3D: Atomic Edition (GOG.com) - Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/JFDuke3D", support[i]); - addsearchpath(buf); - Bsnprintf(buf, sizeof(buf), "%s/EDuke32", support[i]); - addsearchpath(buf); - } - - for (i = 0; i < 2; i++) - { - Xfree(applications[i]); - Xfree(support[i]); - } -#elif defined (_WIN32) - char buf[BMAX_PATH] = {0}; - DWORD bufsize; - - // Duke Nukem 3D: 20th Anniversary World Tour (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D: Megaton Edition (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/gameroot", remaining); - addsearchpath(buf); - Bstrncpy(suffix, "/gameroot/addons/dc", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bstrncpy(suffix, "/gameroot/addons/nw", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bstrncpy(suffix, "/gameroot/addons/vacation", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D: Atomic Edition (GOG.com) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D (3D Realms Anthology) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // 3D Realms Anthology - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // NAM (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/NAM", remaining); - addsearchpath_user(buf, SEARCHPATH_NAM); - } - - // WWII GI (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/WW2GI", remaining); - addsearchpath_user(buf, SEARCHPATH_WW2GI); - } -#endif -#endif -#endif -} void G_CleanupSearchPaths(void) { diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index 806080ed8..672f3efec 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -6289,7 +6289,7 @@ int app_main(int argc, const char * const*argv) initprintf(HEAD2 " %s\n", s_buildRev); PrintBuildInfo(); - G_AddSearchPaths(); + //G_AddSearchPaths(); g_skillCnt = 4; ud.multimode = 1; diff --git a/source/rr/src/common.cpp b/source/rr/src/common.cpp index d0a717042..1c534e2b8 100644 --- a/source/rr/src/common.cpp +++ b/source/rr/src/common.cpp @@ -448,31 +448,6 @@ void G_LoadGroups() pathsearchmode = bakpathsearchmode; } -#if defined _WIN32 -static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize) -{ - // KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds - REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY }; - - for (auto &wow64key : wow64keys) - { - HKEY hkey; - LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey); - - if (keygood != ERROR_SUCCESS) - continue; - - LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize); - - RegCloseKey(hkey); - - if (retval == ERROR_SUCCESS) - return 1; - } - - return 0; -} -#endif static void G_LoadAddon(void) { @@ -499,371 +474,8 @@ static void G_LoadAddon(void) g_selectedGrp = grp; } -#ifndef EDUKE32_TOUCH_DEVICES -#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD -static void G_AddSteamPaths(const char *basepath) -{ - char buf[BMAX_PATH]; - // Duke Nukem 3D: Megaton Edition (Steam) - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath); - addsearchpath(buf); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) -#if defined EDUKE32_OSX - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath); - addsearchpath_user(buf, SEARCHPATH_REMOVE); -#endif - - // NAM (Steam) -#if defined EDUKE32_OSX - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath); -#else - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/NAM", basepath); -#endif - addsearchpath_user(buf, SEARCHPATH_NAM); - -#if 0 - // WWII GI (Steam) - Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/World War II GI/WW2GI", basepath); - addsearchpath_user(buf, SEARCHPATH_WW2GI); -#endif -} - -// A bare-bones "parser" for Valve's KeyValues VDF format. -// There is no guarantee this will function properly with ill-formed files. -static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend) -{ - while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - // comments - if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/') - { - while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend) - (*vdfbuf)++; - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - } -} -static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend) -{ - (*vdfbuf)++; - while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend) -{ - while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend) - (*vdfbuf)++; -} -static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return; - - if ((*vdfbuf)[0] == '{') - { - (*vdfbuf)++; - do - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - } - while ((*vdfbuf)[0] != '}'); - (*vdfbuf)++; - } - else if ((*vdfbuf)[0] == '\"') - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - else if ((*vdfbuf)[0] != '}') - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend) -{ - char *token = *vdfbuf; - - if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend) - { - token++; - - KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - // account for escape sequences - char *writeseeker = token, *readseeker = token; - while (readseeker <= *vdfbuf) - { - if (readseeker[0] == '\\') - readseeker++; - - writeseeker[0] = readseeker[0]; - - writeseeker++; - readseeker++; - } - - return token; - } - - KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend); - (*vdfbuf)[0] = '\0'; - - return token; -} -static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - if (token != NULL) // pass in NULL to find the next key instead of a specific one - while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); -} -static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return 0; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - if (*vdfbuf == vdfbufend) - return 0; - - return 1; -} -static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token) -{ - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - // end of scope - if ((*vdfbuf)[0] == '}') - return NULL; - - KeyValues_FindKey(vdfbuf, vdfbufend, token); - - // ignore the wrong type - while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend) - { - KeyValues_SkipNextWhatever(vdfbuf, vdfbufend); - KeyValues_FindKey(vdfbuf, vdfbufend, token); - } - - KeyValues_SkipWhitespace(vdfbuf, vdfbufend); - - if (*vdfbuf == vdfbufend) - return NULL; - - return KeyValues_NormalizeToken(vdfbuf, vdfbufend); -} - -static void G_ParseSteamKeyValuesForPaths(const char *vdf) -{ - buildvfs_fd fd = buildvfs_open_read(vdf); - int32_t size = buildvfs_length(fd); - char *vdfbufstart, *vdfbuf, *vdfbufend; - - if (size <= 0) - return; - - vdfbufstart = vdfbuf = (char*)Xmalloc(size); - size = (int32_t)buildvfs_read(fd, vdfbuf, size); - buildvfs_close(fd); - vdfbufend = vdfbuf + size; - - if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders")) - { - char *result; - vdfbuf++; - while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL) - G_AddSteamPaths(result); - } - - Xfree(vdfbufstart); -} -#endif -#endif - -void G_AddSearchPaths(void) -{ -#ifndef EDUKE32_TOUCH_DEVICES -#if defined __linux__ || defined EDUKE32_BSD - char buf[BMAX_PATH]; - char *homepath = Bgethomedir(); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath); - G_ParseSteamKeyValuesForPaths(buf); - - Bfree(homepath); - - addsearchpath("/usr/share/games/jfduke3d"); - addsearchpath("/usr/local/share/games/jfduke3d"); - addsearchpath("/usr/share/games/eduke32"); - addsearchpath("/usr/local/share/games/eduke32"); -#elif defined EDUKE32_OSX - char buf[BMAX_PATH]; - int32_t i; - char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) }; - char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) }; - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]); - G_AddSteamPaths(buf); - - Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]); - G_ParseSteamKeyValuesForPaths(buf); - - // Duke Nukem 3D: Atomic Edition (GOG.com) - Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - for (i = 0; i < 2; i++) - { - Bsnprintf(buf, sizeof(buf), "%s/JFDuke3D", support[i]); - addsearchpath(buf); - Bsnprintf(buf, sizeof(buf), "%s/EDuke32", support[i]); - addsearchpath(buf); - } - - for (i = 0; i < 2; i++) - { - Bfree(applications[i]); - Bfree(support[i]); - } -#elif defined (_WIN32) - char buf[BMAX_PATH] = {0}; - DWORD bufsize; - - // Duke Nukem 3D: 20th Anniversary World Tour (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D: Megaton Edition (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/gameroot", remaining); - addsearchpath(buf); - Bstrncpy(suffix, "/gameroot/addons/dc", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bstrncpy(suffix, "/gameroot/addons/nw", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - Bstrncpy(suffix, "/gameroot/addons/vacation", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D: Atomic Edition (GOG.com) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Duke Nukem 3D (3D Realms Anthology) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // 3D Realms Anthology - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/Duke Nukem 3D", remaining); - addsearchpath_user(buf, SEARCHPATH_REMOVE); - } - - // Redneck Rampage (GOG.com) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGREDNECKRAMPAGE", "PATH", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_RR); - } - - // Redneck Rampage Rides Again (GOG.com) - bufsize = sizeof(buf); - if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGCREDNECKRIDESAGAIN", "PATH", buf, &bufsize)) - { - addsearchpath_user(buf, SEARCHPATH_RRRA); - } - - // NAM (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/NAM", remaining); - addsearchpath_user(buf, SEARCHPATH_NAM); - } - -#if 0 - // WWII GI (Steam) - bufsize = sizeof(buf); - if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize)) - { - char * const suffix = buf + bufsize - 1; - DWORD const remaining = sizeof(buf) - bufsize; - - Bstrncpy(suffix, "/WW2GI", remaining); - addsearchpath_user(buf, SEARCHPATH_WW2GI); - } -#endif -#endif -#endif -} void G_CleanupSearchPaths(void) { diff --git a/source/rr/src/game.cpp b/source/rr/src/game.cpp index d8bf2ff56..eb1b892b3 100644 --- a/source/rr/src/game.cpp +++ b/source/rr/src/game.cpp @@ -7664,7 +7664,7 @@ int app_main(int argc, char const * const * argv) initprintf(HEAD2 " %s\n", s_buildRev); PrintBuildInfo(); - G_AddSearchPaths(); + //G_AddSearchPaths(); g_skillCnt = 4; ud.multimode = 1;