/*! * \brief Rebuilds the PHYSFS searchPath with mode specific subdirs * * Priority: * maps > mods > base > base.wz */ bool rebuildSearchPath( searchPathMode mode, bool force ) { static searchPathMode current_mode = mod_clean; static std::string current_current_map; wzSearchPath * curSearchPath = searchPathRegistry; char tmpstr[PATH_MAX] = "\0"; if (mode != current_mode || (current_map != NULL? current_map : "") != current_current_map || force || (use_override_mods && strcmp(override_mod_list, getModList()))) { if (mode != mod_clean) { rebuildSearchPath( mod_clean, false ); } current_mode = mode; current_current_map = current_map != NULL? current_map : ""; // Start at the lowest priority while( curSearchPath->lowerPriority ) curSearchPath = curSearchPath->lowerPriority; switch ( mode ) { case mod_clean: debug(LOG_WZ, "Cleaning up"); clearLoadedMods(); while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Removing [%s] from search path", curSearchPath->path); #endif // DEBUG // Remove maps and mods removeSubdirs( curSearchPath->path, "maps", NULL ); removeSubdirs( curSearchPath->path, "mods/music", NULL ); removeSubdirs( curSearchPath->path, "mods/global", NULL ); removeSubdirs( curSearchPath->path, "mods/campaign", NULL ); removeSubdirs( curSearchPath->path, "mods/multiplay", NULL ); removeSubdirs( curSearchPath->path, "mods/autoload", NULL ); // Remove multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_removeFromSearchPath( tmpstr ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_removeFromSearchPath( tmpstr ); // Remove plain dir PHYSFS_removeFromSearchPath( curSearchPath->path ); // Remove base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_removeFromSearchPath( tmpstr ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_removeFromSearchPath( tmpstr ); // remove video search path as well sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_removeFromSearchPath( tmpstr ); curSearchPath = curSearchPath->higherPriority; } break; case mod_campaign: debug(LOG_WZ, "*** Switching to campaign mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) curSearchPath = curSearchPath->lowerPriority; while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and campaign mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods?override_mods:campaign_mods, true ); if (!PHYSFS_removeFromSearchPath( curSearchPath->path )) { debug(LOG_WZ, "* Failed to remove path %s again", curSearchPath->path); } // Add plain dir PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); curSearchPath = curSearchPath->higherPriority; } break; case mod_multiplay: debug(LOG_WZ, "*** Switching to multiplay mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } // Add the selected map first, for mapmod support if (current_map != NULL) { std::string realPathAndDir = std::string(PHYSFS_getRealDir(current_map)) + current_map; PHYSFS_addToSearchPath(realPathAndDir.c_str(), PHYSFS_APPEND); } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) curSearchPath = curSearchPath->lowerPriority; while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and multiplay mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods?override_mods:multiplay_mods, true ); PHYSFS_removeFromSearchPath( curSearchPath->path ); // Add multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); // Add plain dir PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); curSearchPath = curSearchPath->higherPriority; } break; default: debug(LOG_ERROR, "Can't switch to unknown mods %i", mode); return false; } if (use_override_mods && mode != mod_clean) { if (strcmp(getModList(),override_mod_list)) { debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list); } clearOverrideMods(); current_mode = mod_override; } // User's home dir must be first so we allways see what we write PHYSFS_removeFromSearchPath(PHYSFS_getWriteDir()); PHYSFS_addToSearchPath( PHYSFS_getWriteDir(), PHYSFS_PREPEND ); #ifdef DEBUG printSearchPath(); #endif // DEBUG } else if (use_override_mods) { // override mods are already the same as current mods, so no need to do anything clearOverrideMods(); } return true; }
/*! * \brief Adds default data dirs * * Priority: * Lower loads first. Current: * -datadir > User's home dir > source tree data > AutoPackage > BaseDir > DEFAULT_DATADIR * * Only -datadir and home dir are allways examined. Others only if data still not found. * * We need ParseCommandLine, before we can add any mods... * * \sa rebuildSearchPath */ static void scanDataDirs( void ) { char tmpstr[PATH_MAX], prefix[PATH_MAX]; char* separator; #if defined(WZ_OS_MAC) // version-independent location for video files registerSearchPath("/Library/Application Support/Warzone 2100/", 1); #endif // Find out which PREFIX we are in... sstrcpy(prefix, PHYSFS_getBaseDir()); separator = strrchr(prefix, *PHYSFS_getDirSeparator()); if (separator) { *separator = '\0'; // Trim ending '/', which getBaseDir always provides separator = strrchr(prefix, *PHYSFS_getDirSeparator()); if (separator) { *separator = '\0'; // Skip the last dir from base dir } } // Commandline supplied datadir if( strlen( datadir ) != 0 ) registerSearchPath( datadir, 1 ); // User's home dir registerSearchPath( PHYSFS_getWriteDir(), 2 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Data in source tree sstrcpy(tmpstr, prefix); sstrcat(tmpstr, "/data/"); registerSearchPath( tmpstr, 3 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Relocation for AutoPackage sstrcpy(tmpstr, prefix); sstrcat(tmpstr, "/share/warzone2100/"); registerSearchPath( tmpstr, 4 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Program dir registerSearchPath( PHYSFS_getBaseDir(), 5 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Guessed fallback default datadir on Unix registerSearchPath( WZ_DATADIR, 6 ); rebuildSearchPath( mod_multiplay, true ); } } } } #ifdef WZ_OS_MAC if( !PHYSFS_exists("gamedesc.lev") ) { CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); char resourcePath[PATH_MAX]; if( CFURLGetFileSystemRepresentation( resourceURL, true, (UInt8 *) resourcePath, PATH_MAX) ) { chdir( resourcePath ); registerSearchPath( "data", 7 ); rebuildSearchPath( mod_multiplay, true ); } else { debug( LOG_ERROR, "Could not change to resources directory." ); } if( resourceURL != NULL ) { CFRelease( resourceURL ); } } #endif /** Debugging and sanity checks **/ printSearchPath(); if( PHYSFS_exists("gamedesc.lev") ) { debug( LOG_WZ, "gamedesc.lev found at %s", PHYSFS_getRealDir( "gamedesc.lev" ) ); } else { debug( LOG_FATAL, "Could not find game data. Aborting." ); exit(1); } }
static MapFileList listMapFiles() { MapFileList ret, filtered, oldSearchPath; char **subdirlist = PHYSFS_enumerateFiles("maps"); for (char **i = subdirlist; *i != nullptr; ++i) { std::string wzfile = *i; if (*i[0] == '.' || wzfile.substr(wzfile.find_last_of('.') + 1) != "wz") { continue; } std::string realFileName = std::string("maps/") + *i; ret.push_back(realFileName); } PHYSFS_freeList(subdirlist); // save our current search path(s) debug(LOG_WZ, "Map search paths:"); char **searchPath = PHYSFS_getSearchPath(); for (char **i = searchPath; *i != nullptr; i++) { debug(LOG_WZ, " [%s]", *i); oldSearchPath.push_back(*i); WZ_PHYSFS_unmount(*i); } PHYSFS_freeList(searchPath); for (const auto &realFileName : ret) { std::string realFilePathAndName = PHYSFS_getWriteDir() + realFileName; if (PHYSFS_mount(realFilePathAndName.c_str(), NULL, PHYSFS_APPEND)) { int unsafe = 0; char **filelist = PHYSFS_enumerateFiles("multiplay/maps"); for (char **file = filelist; *file != nullptr; ++file) { std::string isDir = std::string("multiplay/maps/") + *file; if (WZ_PHYSFS_isDirectory(isDir.c_str())) { continue; } std::string checkfile = *file; debug(LOG_WZ, "checking ... %s", *file); if (checkfile.substr(checkfile.find_last_of('.') + 1) == "gam") { if (unsafe++ > 1) { debug(LOG_ERROR, "Map packs are not supported! %s NOT added.", realFilePathAndName.c_str()); break; } } } PHYSFS_freeList(filelist); if (unsafe < 2) { filtered.push_back(realFileName); } WZ_PHYSFS_unmount(realFilePathAndName.c_str()); } else { debug(LOG_POPUP, "Could not mount %s, because: %s.\nPlease delete or move the file specified.", realFilePathAndName.c_str(), WZ_PHYSFS_getLastError()); } } // restore our search path(s) again for (const auto &restorePaths : oldSearchPath) { PHYSFS_mount(restorePaths.c_str(), NULL, PHYSFS_APPEND); } debug(LOG_WZ, "Search paths restored"); printSearchPath(); return filtered; }
static MapFileList listMapFiles() { MapFileList ret, filtered, oldSearchPath; char **subdirlist = PHYSFS_enumerateFiles("maps"); for (char **i = subdirlist; *i != NULL; ++i) { std::string wzfile = *i; if (*i[0] == '.' || wzfile.substr(wzfile.find_last_of(".")+1) != "wz") { continue; } std::string realFileName = std::string("maps/") + *i; ret.push_back(realFileName); } PHYSFS_freeList(subdirlist); // save our current search path(s) debug(LOG_WZ, "Map search paths:"); char **searchPath = PHYSFS_getSearchPath(); for (char **i = searchPath; *i != NULL; i++) { debug(LOG_WZ, " [%s]", *i); oldSearchPath.push_back(*i); PHYSFS_removeFromSearchPath(*i); } PHYSFS_freeList(searchPath); for (MapFileList::iterator realFileName = ret.begin(); realFileName != ret.end(); ++realFileName) { std::string realFilePathAndName = PHYSFS_getWriteDir() + *realFileName; PHYSFS_addToSearchPath(realFilePathAndName.c_str(), PHYSFS_APPEND); int unsafe = 0; char **filelist = PHYSFS_enumerateFiles("multiplay/maps"); for (char **file = filelist; *file != NULL; ++file) { std::string isDir = std::string("multiplay/maps/") + *file; if (PHYSFS_isDirectory(isDir.c_str())) continue; std::string checkfile = *file; debug(LOG_WZ,"checking ... %s", *file); if (checkfile.substr(checkfile.find_last_of(".")+ 1) == "gam") { if (unsafe++ > 1) { debug(LOG_ERROR, "Map packs are not supported! %s NOT added.", realFilePathAndName.c_str()); break; } } } PHYSFS_freeList(filelist); if (unsafe < 2) { filtered.push_back(realFileName->c_str()); } PHYSFS_removeFromSearchPath(realFilePathAndName.c_str()); } // restore our search path(s) again for (MapFileList::iterator restorePaths = oldSearchPath.begin(); restorePaths != oldSearchPath.end(); ++restorePaths) { PHYSFS_addToSearchPath(restorePaths->c_str(), PHYSFS_APPEND); } debug(LOG_WZ, "Search paths restored"); printSearchPath(); return filtered; }
/*! * \brief Rebuilds the PHYSFS searchPath with mode specific subdirs * * Priority: * maps > mods > base > base.wz */ bool rebuildSearchPath(searchPathMode mode, bool force, const char *current_map) { static searchPathMode current_mode = mod_clean; static std::string current_current_map; wzSearchPath *curSearchPath = searchPathRegistry; char tmpstr[PATH_MAX] = "\0"; if (mode != current_mode || (current_map != nullptr ? current_map : "") != current_current_map || force || (use_override_mods && override_mod_list != getModList())) { if (mode != mod_clean) { rebuildSearchPath(mod_clean, false); } current_mode = mode; current_current_map = current_map != nullptr ? current_map : ""; // Start at the lowest priority while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } switch (mode) { case mod_clean: debug(LOG_WZ, "Cleaning up"); clearLoadedMods(); while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Removing [%s] from search path", curSearchPath->path); #endif // DEBUG // Remove maps and mods removeSubdirs(curSearchPath->path, "maps"); removeSubdirs(curSearchPath->path, "mods/music"); removeSubdirs(curSearchPath->path, "mods/global"); removeSubdirs(curSearchPath->path, "mods"); removeSubdirs(curSearchPath->path, "mods/autoload"); removeSubdirs(curSearchPath->path, "mods/campaign"); removeSubdirs(curSearchPath->path, "mods/multiplay"); removeSubdirs(curSearchPath->path, "mods/downloads"); // Remove multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); WZ_PHYSFS_unmount(tmpstr); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); WZ_PHYSFS_unmount(tmpstr); // Remove plain dir WZ_PHYSFS_unmount(curSearchPath->path); // Remove base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); WZ_PHYSFS_unmount(tmpstr); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); WZ_PHYSFS_unmount(tmpstr); // remove video search path as well sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); WZ_PHYSFS_unmount(tmpstr); curSearchPath = curSearchPath->higherPriority; } break; case mod_campaign: debug(LOG_WZ, "*** Switching to campaign mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and campaign mods PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); addSubdirs(curSearchPath->path, "mods/music", PHYSFS_APPEND, nullptr, false); addSubdirs(curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods ? &override_mods : nullptr, true); addSubdirs(curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods ? &override_mods : &campaign_mods, true); if (!WZ_PHYSFS_unmount(curSearchPath->path)) { debug(LOG_WZ, "* Failed to remove path %s again", curSearchPath->path); } // Add plain dir PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } break; case mod_multiplay: debug(LOG_WZ, "*** Switching to multiplay mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } // Add the selected map first, for mapmod support if (current_map != nullptr) { WzString realPathAndDir = WzString::fromUtf8(PHYSFS_getRealDir(current_map)) + current_map; realPathAndDir.replace("/", PHYSFS_getDirSeparator()); // Windows fix PHYSFS_mount(realPathAndDir.toUtf8().c_str(), NULL, PHYSFS_APPEND); } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and multiplay mods PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); addSubdirs(curSearchPath->path, "mods/music", PHYSFS_APPEND, nullptr, false); if (NetPlay.isHost || !NetPlay.bComms) { addSubdirs(curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods ? &override_mods : nullptr, true); addSubdirs(curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods ? &override_mods : &multiplay_mods, true); } else { std::vector<std::string> hashList; for (Sha256 &hash : game.modHashes) { hashList = {hash.toString()}; addSubdirs(curSearchPath->path, "mods/downloads", PHYSFS_APPEND, &hashList, true); } } WZ_PHYSFS_unmount(curSearchPath->path); // Add multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); // Add plain dir PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } break; default: debug(LOG_ERROR, "Can't switch to unknown mods %i", mode); return false; } if (use_override_mods && mode != mod_clean) { if (getModList() != override_mod_list) { debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list.c_str()); } clearOverrideMods(); current_mode = mod_override; } // User's home dir must be first so we always see what we write WZ_PHYSFS_unmount(PHYSFS_getWriteDir()); PHYSFS_mount(PHYSFS_getWriteDir(), NULL, PHYSFS_PREPEND); #ifdef DEBUG printSearchPath(); #endif // DEBUG } else if (use_override_mods) { // override mods are already the same as current mods, so no need to do anything clearOverrideMods(); } return true; }