From 32f57d0dc168d2b11e19b39d369a9d6a877d0fec Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 11 Jun 2014 18:19:41 +0100 Subject: [PATCH] Aircraft switching command and formal support. - /sim/aircraft can be set to package ID, including qualified package ID. If not matching package is found, falls back to traditional search of fg-aircraft for -set.xml files --- src/Main/fg_commands.cxx | 14 +++++++ src/Main/fg_init.cxx | 91 ++++++++++++++++++++++++++++------------ src/Main/globals.cxx | 23 ++++++---- src/Main/globals.hxx | 13 +++++- src/Main/options.cxx | 4 -- 5 files changed, 105 insertions(+), 40 deletions(-) diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index 9daf6db74..175a9dd86 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -209,6 +209,19 @@ do_reset (const SGPropertyNode * arg) return true; } + +/** + * Change aircraft + */ +static bool +do_switch_aircraft (const SGPropertyNode * arg) +{ + fgSetString("/sim/aircraft", arg->getStringValue("aircraft")); + // start a reset + fgResetIdleState(); + return true; +} + /** */ static bool @@ -1462,6 +1475,7 @@ static struct { { "exit", do_exit }, { "reset", do_reset }, { "reposition", do_reposition }, + { "switch-aircraft", do_switch_aircraft }, { "pause", do_pause }, { "load", do_load }, { "save", do_save }, diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 0f90d8e6d..20c2a210f 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -70,6 +70,9 @@ #include #include +#include +#include +#include #include #include @@ -483,37 +486,71 @@ int fgInitConfig ( int argc, char **argv, bool reinit ) return flightgear::FG_OPTIONS_OK; } +static void initAircraftDirsNasalSecurity() +{ + SGPropertyNode* sim = fgGetNode("/sim", true); + sim->removeChildren("fg-aircraft"); + string_list::const_iterator it; + int index = 0; + for (it = globals->get_aircraft_paths().begin(); + it != globals->get_aircraft_paths().end(); ++it, ++index) + { + SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); + n->setStringValue(*it); + n->setAttribute(SGPropertyNode::WRITE, false); + } +} + int fgInitAircraft(bool reinit) { - // FIXME - use Documents/FlightGear/Aircraft - SGPath userAircraftDir = globals->get_fg_home(); - userAircraftDir.append("Aircraft"); - - SGSharedPtr pkgRoot(new Root(userAircraftDir, FLIGHTGEAR_VERSION)); - // set the http client later (too early in startup right now) - globals->setPackageRoot(pkgRoot); - - // Scan user config files and command line for a specified aircraft. - if (reinit) { - SGPropertyNode* sim = fgGetNode("/sim", true); - sim->removeChildren("fg-aircraft"); - // after reset, add aircraft dirs to props, needed for Nasal IO rules - string_list::const_iterator it; - int index = 0; - for (it = globals->get_aircraft_paths().begin(); - it != globals->get_aircraft_paths().end(); ++it, ++index) - { - SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); - n->setStringValue(*it); - n->setAttribute(SGPropertyNode::WRITE, false); - } - - SGPropertyNode* aircraftProp = fgGetNode("/sim/aircraft", true); - aircraftProp->setAttribute(SGPropertyNode::PRESERVE, true); - } else { + if (!reinit) { + // FIXME - use Documents/FlightGear/Aircraft + SGPath userAircraftDir = globals->get_fg_home(); + userAircraftDir.append("Aircraft"); + + SGSharedPtr pkgRoot(new Root(userAircraftDir, FLIGHTGEAR_VERSION)); + // set the http client later (too early in startup right now) + globals->setPackageRoot(pkgRoot); + } + + SGSharedPtr pkgRoot(globals->packageRoot()); + SGPropertyNode* aircraftProp = fgGetNode("/sim/aircraft", true); + aircraftProp->setAttribute(SGPropertyNode::PRESERVE, true); + + if (!reinit) { flightgear::Options::sharedInstance()->initAircraft(); } - + + PackageRef acftPackage = pkgRoot->getPackageById(aircraftProp->getStringValue()); + if (acftPackage) { + if (!acftPackage->isInstalled()) { + // naturally the better option would be to on-demand install it! + flightgear::fatalMessageBox("Aircraft not installed", + "Requested aircraft is not currently installed.", + aircraftProp->getStringValue()); + + return flightgear::FG_OPTIONS_ERROR; + } + + SG_LOG(SG_GENERAL, SG_INFO, "Loading aircraft from " << acftPackage->id()); + + // set catalog path so intra-package dependencies within the catalog + // are resolved correctly. + globals->set_catalog_aircraft_path(acftPackage->catalog()->installRoot()); + + // set aircraft-dir to short circuit the search process + InstallRef acftInstall = acftPackage->install(); + fgSetString("/sim/aircraft-dir", acftInstall->path().c_str()); + + // overwrite the fully qualified ID with the aircraft one, so the + // code in FindAndCacheAircraft works as normal + + aircraftProp->setStringValue(acftPackage->id()); + // run the traditional-code path below + } + + initAircraftDirsNasalSecurity(); + FindAndCacheAircraft f(globals->get_props()); if (!f.loadAircraft()) { return flightgear::FG_OPTIONS_ERROR; diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index 2efb4ec74..af88f381e 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -400,6 +400,22 @@ void FGGlobals::clear_fg_scenery() fg_scenery.clear(); } +void FGGlobals::set_catalog_aircraft_path(const SGPath& path) +{ + catalog_aircraft_dir = path; +} + +string_list FGGlobals::get_aircraft_paths() const +{ + string_list r; + if (!catalog_aircraft_dir.isNull()) { + r.push_back(catalog_aircraft_dir.str()); + } + + r.insert(r.end(), fg_aircraft_dirs.begin(), fg_aircraft_dirs.end()); + return r; +} + void FGGlobals::append_aircraft_path(const std::string& path) { SGPath dirPath(path); @@ -419,13 +435,6 @@ void FGGlobals::append_aircraft_path(const std::string& path) std::string abspath = dirPath.realpath(); unsigned int index = fg_aircraft_dirs.size(); fg_aircraft_dirs.push_back(abspath); - -// make aircraft dirs available to Nasal - SGPropertyNode* sim = fgGetNode("/sim", true); - sim->removeChild("fg-aircraft", index); - SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); - n->setStringValue(abspath); - n->setAttribute(SGPropertyNode::WRITE, false); } void FGGlobals::append_aircraft_paths(const std::string& path) diff --git a/src/Main/globals.hxx b/src/Main/globals.hxx index 17708c3f7..cf8680ac3 100644 --- a/src/Main/globals.hxx +++ b/src/Main/globals.hxx @@ -150,6 +150,7 @@ private: /// roots of Aircraft trees string_list fg_aircraft_dirs; + SGPath catalog_aircraft_dir; bool haveUserSettings; @@ -226,8 +227,16 @@ public: void append_fg_scenery (const std::string &scenery); void clear_fg_scenery(); - - const string_list& get_aircraft_paths() const { return fg_aircraft_dirs; } + + /** + * specify a path we'll prepend to the aircraft paths list if non-empty. + * This is used with packaged aircraft, to ensure their catalog (and hence, + * dependency packages) are found correctly. + */ + void set_catalog_aircraft_path(const SGPath& path); + + string_list get_aircraft_paths() const; + void append_aircraft_path(const std::string& path); void append_aircraft_paths(const std::string& path); diff --git a/src/Main/options.cxx b/src/Main/options.cxx index d055b968a..991b39c36 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -1931,10 +1931,6 @@ void Options::initAircraft() } else { SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" ); } - -// persist across reset - SGPropertyNode* aircraftProp = fgGetNode("/sim/aircraft", true); - aircraftProp->setAttribute(SGPropertyNode::PRESERVE, true); if (p->showAircraft) { fgOptLogLevel( "alert" ); -- 2.39.5