From 9e007150797a0d3c97972e059d58fa58530e88c9 Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 30 Jun 2020 17:08:29 +0100 Subject: [PATCH] Allow cmd line & add-ons to supply FGData extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow add-ons to define an FGData subdir, and support multiple —data= command line arguments, to avoid the need to modify FG_ROOT (which might be read-only). Allow additional data paths to be either higher or lower priority than FG_ROOT, so that add-ons cannot replace files in FG_ROOT. --- src/Add-ons/AddonManager.cxx | 13 ++++++++++--- src/Main/globals.cxx | 26 ++++++++++++++++++++++---- src/Main/globals.hxx | 4 +++- src/Main/main.cxx | 2 +- src/Main/options.cxx | 15 +++++++++++++++ src/Network/generic.cxx | 2 +- 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/Add-ons/AddonManager.cxx b/src/Add-ons/AddonManager.cxx index 667b5561d..2eafb76f7 100644 --- a/src/Add-ons/AddonManager.cxx +++ b/src/Add-ons/AddonManager.cxx @@ -204,9 +204,16 @@ AddonManager::registerAddon(const SGPath& addonPath) string msg = "Registered add-on '" + addon->getName() + "' (" + addonId + ") version " + addonVersion(addonId)->str() + "; " "base path is '" + addonRealPath.utf8Str() + "'"; - // This preserves the registration order - _registeredAddons.push_back(std::move(addon)); - SG_LOG(SG_GENERAL, SG_INFO, msg); + + auto dataPath = addonRealPath / "FGData"; + if (dataPath.exists()) { + SG_LOG(SG_GENERAL, SG_INFO, "Registering data path for add-on: " << addon->getName()); + globals->append_data_path(dataPath, true /* after FG_ROOT */); + } + + // This preserves the registration order + _registeredAddons.push_back(addon); + SG_LOG(SG_GENERAL, SG_INFO, msg); return addonId; } diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index eac356cbd..98a1221d1 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -302,6 +302,7 @@ PathList FGGlobals::get_data_paths() const { PathList r(additional_data_paths); r.push_back(fg_root); + r.insert(r.end(), _dataPathsAfterFGRoot.begin(), _dataPathsAfterFGRoot.end()); return r; } @@ -318,13 +319,23 @@ PathList FGGlobals::get_data_paths(const std::string& suffix) const return r; } -void FGGlobals::append_data_path(const SGPath& path) +void FGGlobals::append_data_path(const SGPath& path, bool afterFGRoot) { if (!path.exists()) { SG_LOG(SG_GENERAL, SG_WARN, "adding non-existant data path:" << path); } - additional_data_paths.push_back(path); + using RM = simgear::ResourceManager; + auto resManager = RM::instance(); + if (afterFGRoot) { + _dataPathsAfterFGRoot.push_back(path); + // after FG_ROOT + resManager->addBasePath(path, static_cast(RM::PRIORITY_DEFAULT - 10)); + } else { + additional_data_paths.push_back(path); + // after NORMAL prioirty, but ahead of FG_ROOT + resManager->addBasePath(path, static_cast(RM::PRIORITY_DEFAULT + 10)); + } } SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const @@ -342,8 +353,15 @@ SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const return rootPath; } - SG_LOG(SG_GENERAL, SG_WARN, "dir not found in any data path:" << pathSuffix); - return SGPath(); + for (SGPath p : _dataPathsAfterFGRoot) { + p.append(pathSuffix); + if (p.exists()) { + return p; + } + } + + SG_LOG(SG_IO, SG_WARN, "not found in any data path: '" << pathSuffix << "'"); + return SGPath{}; } void FGGlobals::append_fg_scenery (const PathList &paths) diff --git a/src/Main/globals.hxx b/src/Main/globals.hxx index e8d1c4cf4..87b6a29af 100644 --- a/src/Main/globals.hxx +++ b/src/Main/globals.hxx @@ -101,6 +101,8 @@ private: */ PathList additional_data_paths; + PathList _dataPathsAfterFGRoot; ///< paths with a /lower/ prioirty than FGRoot + // Users home directory for data SGPath fg_home; @@ -216,7 +218,7 @@ public: */ PathList get_data_paths(const std::string& suffix) const; - void append_data_path(const SGPath& path); + void append_data_path(const SGPath& path, bool afterFGRoot = false); /** * Given a path suffix (eg 'Textures' or 'AI/Traffic'), find the diff --git a/src/Main/main.cxx b/src/Main/main.cxx index f54a2c3c9..f623f33e9 100755 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -173,7 +173,7 @@ static void initTerrasync() // add the terrasync root as a data path so data can be retrieved from it // (even if we are in read-only mode) SGPath terraSyncDir(globals->get_terrasync_dir()); - globals->append_data_path(terraSyncDir); + globals->append_data_path(terraSyncDir, false /* = ahead of FG_ROOT */); if (fgGetBool("/sim/fghome-readonly", false)) { return; diff --git a/src/Main/options.cxx b/src/Main/options.cxx index 0f51d5886..ecfdb7e0b 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -727,6 +727,20 @@ fgOptAddon(const char *arg) return FG_OPTIONS_OK; } +static int +fgOptAdditionalDataDir(const char* arg) +{ + const SGPath dataPath = SGPath::fromUtf8(arg); + if (!dataPath.exists()) { + SG_LOG(SG_GENERAL, SG_ALERT, "--data path not found:'" << dataPath << "'"); + flightgear::fatalMessageBoxWithoutExit("FlightGear", "Data path not found"); + return FG_OPTIONS_EXIT; + } + + globals->append_data_path(dataPath, false /* = before FG_ROOT */); + return FG_OPTIONS_OK; +} + static int fgOptVOR( const char * arg ) { @@ -1821,6 +1835,7 @@ struct OptionDesc { {"flight-plan", true, OPTION_STRING, "/autopilot/route-manager/file-path", false, "", NULL }, {"config", true, OPTION_IGNORE | OPTION_MULTI, "", false, "", 0 }, {"addon", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptAddon }, + {"data", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptAdditionalDataDir }, {"aircraft", true, OPTION_STRING, "/sim/aircraft", false, "", 0 }, {"vehicle", true, OPTION_STRING, "/sim/aircraft", false, "", 0 }, {"failure", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptFailure }, diff --git a/src/Network/generic.cxx b/src/Network/generic.cxx index e8199fa1a..6e7013192 100644 --- a/src/Network/generic.cxx +++ b/src/Network/generic.cxx @@ -753,7 +753,7 @@ bool FGGeneric::close() { void FGGeneric::reinit() { - SGPath path = globals->resolve_maybe_aircraft_path("Protocol/" + file_name); + SGPath path = globals->find_data_dir("Protocol/" + file_name); if (!path.exists()) { SG_LOG(SG_NETWORK, SG_WARN, "Couldn't find protocol file for '" << file_name << "'"); return;