X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fglobals.cxx;h=51f202b4960d72f2785ed5498c32a2478f8a8c4f;hb=33425c671d20fc7a7fbb87c2db28aef455b5b5dd;hp=2e72e8276565171aa6ef24a8aa7e8c2c9428ea94;hpb=e0aef846e30d9cda73c4e0e10fb13e2b845db5d7;p=flightgear.git diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index 2e72e8276..51f202b49 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -24,34 +24,37 @@ # include #endif +#include +#include + #include #include #include #include #include -#include #include #include #include #include #include +#include +#include #include #include -#include +#include #include -#include -#include -#include -#include +#include +#include #include #include #include #include +#include +#include #include "globals.hxx" -#include "renderer.hxx" -#include "viewmgr.hxx" +#include "locale.hxx" #include "fg_props.hxx" #include "fg_io.hxx" @@ -82,7 +85,7 @@ public: } if (r.exists()) { - SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " via /sim/aircraft-dir: " << r.str()); + SG_LOG(SG_IO, SG_DEBUG, "found path:" << aResource << " via /sim/aircraft-dir: " << r.str()); return r; } } @@ -94,7 +97,7 @@ public: for (; it != dirs.end(); ++it) { SGPath p(*it, res); if (p.exists()) { - SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " in aircraft dir: " << *it); + SG_LOG(SG_IO, SG_DEBUG, "found path:" << aResource << " in aircraft dir: " << *it); return p; } } // of aircraft path iteration @@ -103,6 +106,23 @@ public: } }; +class CurrentAircraftDirProvider : public simgear::ResourceProvider +{ +public: + CurrentAircraftDirProvider() : + simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH) + { + } + + virtual SGPath resolve(const std::string& aResource, SGPath&) const + { + const char* aircraftDir = fgGetString("/sim/aircraft-dir"); + SGPath p(aircraftDir); + p.append(aResource); + return p.exists() ? p : SGPath(); + } +}; + //////////////////////////////////////////////////////////////////////// // Implementation of FGGlobals. //////////////////////////////////////////////////////////////////////// @@ -115,100 +135,99 @@ FGGlobals *globals; FGGlobals::FGGlobals() : props( new SGPropertyNode ), initial_state( NULL ), - locale( NULL ), + locale( new FGLocale(props) ), renderer( new FGRenderer ), subsystem_mgr( new SGSubsystemMgr ), event_mgr( new SGEventMgr ), - soundmgr( new SGSoundMgr ), sim_time_sec( 0.0 ), fg_root( "" ), + fg_home( "" ), time_params( NULL ), ephem( NULL ), - mag( NULL ), matlib( NULL ), route_mgr( NULL ), - current_panel( NULL ), - ATC_mgr( NULL ), + ATIS_mgr( NULL ), controls( NULL ), viewmgr( NULL ), commands( SGCommandMgr::instance() ), - acmodel( NULL ), - model_mgr( NULL ), channel_options_list( NULL ), initial_waypoints( NULL ), scenery( NULL ), tile_mgr( NULL ), fontcache ( new FGFontCache ), - navlist( NULL ), - loclist( NULL ), - gslist( NULL ), - dmelist( NULL ), - tacanlist( NULL ), - carrierlist( NULL ), - channellist( NULL ) + channellist( NULL ), + haveUserSettings(false) { - simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider()); + simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider); + simgear::ResourceManager::instance()->addProvider(new CurrentAircraftDirProvider); + simgear::PropertyObjectBase::setDefaultRoot(props); + + positionLon = props->getNode("position/longitude-deg", true); + positionLat = props->getNode("position/latitude-deg", true); + positionAlt = props->getNode("position/altitude-ft", true); + + viewLon = props->getNode("sim/current-view/viewer-lon-deg", true); + viewLat = props->getNode("sim/current-view/viewer-lat-deg", true); + viewAlt = props->getNode("sim/current-view/viewer-elev-ft", true); + + orientPitch = props->getNode("orientation/pitch-deg", true); + orientHeading = props->getNode("orientation/heading-deg", true); + orientRoll = props->getNode("orientation/roll-deg", true); } - // Destructor FGGlobals::~FGGlobals() { - delete renderer; - renderer = NULL; - -// The AIModels manager performs a number of actions upon + // save user settings (unless already saved) + saveUserSettings(); + + // The AIModels manager performs a number of actions upon // Shutdown that implicitly assume that other subsystems // are still operational (Due to the dynamic allocation and // deallocation of AIModel objects. To ensure we can safely // shut down all subsystems, make sure we take down the // AIModels system first. - SGSubsystem* ai = subsystem_mgr->remove("ai_model"); + SGSubsystem* ai = subsystem_mgr->remove("ai-model"); if (ai) { ai->unbind(); delete ai; } - + SGSubsystem* sound = subsystem_mgr->remove("sound"); + subsystem_mgr->shutdown(); subsystem_mgr->unbind(); delete subsystem_mgr; + delete renderer; + renderer = NULL; + delete time_params; - delete mag; delete matlib; delete route_mgr; - delete current_panel; - delete ATC_mgr; - delete controls; + delete ATIS_mgr; delete channel_options_list; delete initial_waypoints; delete scenery; delete fontcache; - delete navlist; - delete loclist; - delete gslist; - delete dmelist; - delete tacanlist; - delete carrierlist; delete channellist; + delete sound; - soundmgr->unbind(); - delete soundmgr; + delete locale; + locale = NULL; } - // set the fg_root path -void FGGlobals::set_fg_root (const string &root) { - fg_root = root; +void FGGlobals::set_fg_root (const std::string &root) { + SGPath tmp(root); + fg_root = tmp.realpath(); // append /data to root if it exists - SGPath tmp( fg_root ); tmp.append( "data" ); tmp.append( "version" ); - if ( ulFileExists( tmp.c_str() ) ) { + if ( tmp.exists() ) { fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root); fg_root += "/data"; fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root); @@ -227,26 +246,86 @@ void FGGlobals::set_fg_root (const string &root) { simgear::ResourceManager::PRIORITY_DEFAULT); } -void FGGlobals::set_fg_scenery (const string &scenery) +// set the fg_home path +void FGGlobals::set_fg_home (const std::string &home) { + SGPath tmp(home); + fg_home = tmp.realpath(); +} + +PathList FGGlobals::get_data_paths() const +{ + PathList r(additional_data_paths); + r.push_back(SGPath(fg_root)); + return r; +} + +PathList FGGlobals::get_data_paths(const std::string& suffix) const +{ + PathList r; + BOOST_FOREACH(SGPath p, get_data_paths()) { + p.append(suffix); + if (p.exists()) { + r.push_back(p); + } + } + + return r; +} + +void FGGlobals::append_data_path(const SGPath& path) { - SGPath s; - if (scenery.empty()) { - s.set( fg_root ); - s.append( "Scenery" ); - } else - s.set( scenery ); + if (!path.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "adding non-existant data path:" << path); + } + + additional_data_paths.push_back(path); +} - string_list path_list = sgPathSplit( s.str() ); - fg_scenery.clear(); +SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const +{ + BOOST_FOREACH(SGPath p, additional_data_paths) { + p.append(pathSuffix); + if (p.exists()) { + return p; + } + } + + SGPath rootPath(fg_root); + rootPath.append(pathSuffix); + if (rootPath.exists()) { + return rootPath; + } + + SG_LOG(SG_GENERAL, SG_WARN, "dir not found in any data path:" << pathSuffix); + return SGPath(); +} - for (unsigned i = 0; i < path_list.size(); i++) { - SGPath path(path_list[i]); - if (!path.exists()) { - SG_LOG(SG_GENERAL, SG_WARN, "scenery path not found:" << path.str()); +void FGGlobals::append_fg_scenery (const std::string &paths) +{ +// fg_scenery.clear(); + SGPropertyNode* sim = fgGetNode("/sim", true); + + // find first unused fg-scenery property in /sim + int propIndex = 0; + while (sim->getChild("fg-scenery", propIndex) != NULL) { + ++propIndex; + } + + BOOST_FOREACH(const SGPath& path, sgPathSplit( paths )) { + SGPath abspath(path.realpath()); + if (!abspath.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "scenery path not found:" << abspath.str()); continue; } - simgear::Dir dir(path); + // check for duplicates + string_list::const_iterator ex = std::find(fg_scenery.begin(), fg_scenery.end(), abspath.str()); + if (ex != fg_scenery.end()) { + SG_LOG(SG_GENERAL, SG_INFO, "skipping duplicate add of scenery path:" << abspath.str()); + continue; + } + + simgear::Dir dir(abspath); SGPath terrainDir(dir.file("Terrain")); SGPath objectsDir(dir.file("Objects")); @@ -254,7 +333,7 @@ void FGGlobals::set_fg_scenery (const string &scenery) // Terrain and Objects subdirs, but the conditional logic was commented // out, such that all three dirs are added. Unfortunately there's // no information as to why the change was made. - fg_scenery.push_back(path.str()); + fg_scenery.push_back(abspath.str()); if (terrainDir.exists()) { fg_scenery.push_back(terrainDir.str()); @@ -268,6 +347,11 @@ void FGGlobals::set_fg_scenery (const string &scenery) // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "", // "B/Terrain", "B/Objects", ""] fg_scenery.push_back(""); + + // make scenery dirs available to Nasal + SGPropertyNode* n = sim->getChild("fg-scenery", propIndex++, true); + n->setStringValue(abspath.str()); + n->setAttribute(SGPropertyNode::WRITE, false); } // of path list iteration } @@ -278,15 +362,16 @@ void FGGlobals::append_aircraft_path(const std::string& path) SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path); return; } + std::string abspath = dirPath.realpath(); unsigned int index = fg_aircraft_dirs.size(); - fg_aircraft_dirs.push_back(path); + fg_aircraft_dirs.push_back(abspath); // make aircraft dirs available to Nasal SGPropertyNode* sim = fgGetNode("/sim", true); sim->removeChild("fg-aircraft", index, false); SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); - n->setStringValue(path); + n->setStringValue(abspath); n->setAttribute(SGPropertyNode::WRITE, false); } @@ -308,6 +393,12 @@ SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const return simgear::ResourceManager::instance()->findPath(branch); } +SGPath FGGlobals::resolve_resource_path(const std::string& branch) const +{ + return simgear::ResourceManager::instance() + ->findPath(branch, SGPath(fgGetString("/sim/aircraft-dir"))); +} + FGRenderer * FGGlobals::get_renderer () const { @@ -338,7 +429,10 @@ FGGlobals::add_subsystem (const char * name, SGSoundMgr * FGGlobals::get_soundmgr () const { - return soundmgr; + if (subsystem_mgr) + return (SGSoundMgr*) subsystem_mgr->get_subsystem("sound"); + + return NULL; } SGEventMgr * @@ -347,6 +441,40 @@ FGGlobals::get_event_mgr () const return event_mgr; } +SGGeod +FGGlobals::get_aircraft_position() const +{ + return SGGeod::fromDegFt(positionLon->getDoubleValue(), + positionLat->getDoubleValue(), + positionAlt->getDoubleValue()); +} + +SGVec3d +FGGlobals::get_aircraft_position_cart() const +{ + return SGVec3d::fromGeod(get_aircraft_position()); +} + +void FGGlobals::get_aircraft_orientation(double& heading, double& pitch, double& roll) +{ + heading = orientHeading->getDoubleValue(); + pitch = orientPitch->getDoubleValue(); + roll = orientRoll->getDoubleValue(); +} + +SGGeod +FGGlobals::get_view_position() const +{ + return SGGeod::fromDegFt(viewLon->getDoubleValue(), + viewLat->getDoubleValue(), + viewAlt->getDoubleValue()); +} + +SGVec3d +FGGlobals::get_view_position_cart() const +{ + return SGVec3d::fromGeod(get_view_position()); +} // Save the current state as the initial state. void @@ -354,18 +482,18 @@ FGGlobals::saveInitialState () { initial_state = new SGPropertyNode(); - if (!copyProperties(props, initial_state)) + // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd + int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ + SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; + int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; + if (!copyProperties(props, initial_state, expected, checked)) SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state"); // delete various properties from the initial state, since we want to // preserve their values even if doing a restore - + // => Properties should now use the PRESERVE flag to protect their values + // on sim-reset. Remove some specific properties for backward compatibility. SGPropertyNode* sim = initial_state->getChild("sim"); - sim->removeChild("presets"); - SGPropertyNode* simStartup = sim->getChild("startup"); - simStartup->removeChild("xsize"); - simStartup->removeChild("ysize"); - SGPropertyNode* cameraGroupNode = sim->getNode("rendering/camera-group"); if (cameraGroupNode) { cameraGroupNode->removeChild("camera"); @@ -373,6 +501,17 @@ FGGlobals::saveInitialState () } } +static std::string autosaveName() +{ + std::ostringstream os; + string_list versionParts = simgear::strutils::split(VERSION, "."); + if (versionParts.size() < 2) { + return "autosave.xml"; + } + + os << "autosave_" << versionParts[0] << "_" << versionParts[1] << ".xml"; + return os.str(); +} // Restore the saved initial state, if any void @@ -383,8 +522,11 @@ FGGlobals::restoreInitialState () "No initial state available to restore!!!"); return; } - - if ( copyProperties(initial_state, props) ) { + // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd + int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ + SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; + int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; + if ( copyProperties(initial_state, props, expected, checked)) { SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" ); } else { SG_LOG( SG_GENERAL, SG_INFO, @@ -393,6 +535,53 @@ FGGlobals::restoreInitialState () } +// Load user settings from autosave.xml +void +FGGlobals::loadUserSettings(const SGPath& dataPath) +{ + // remember that we have (tried) to load any existing autsave.xml + haveUserSettings = true; + + SGPath autosaveFile = simgear::Dir(dataPath).file(autosaveName()); + SGPropertyNode autosave; + if (autosaveFile.exists()) { + SG_LOG(SG_INPUT, SG_INFO, "Reading user settings from " << autosaveFile.str()); + try { + readProperties(autosaveFile.str(), &autosave, SGPropertyNode::USERARCHIVE); + } catch (sg_exception& e) { + SG_LOG(SG_INPUT, SG_WARN, "failed to read user settings:" << e.getMessage() + << "(from " << e.getOrigin() << ")"); + } + } + copyProperties(&autosave, globals->get_props()); +} + +// Save user settings in autosave.xml +void +FGGlobals::saveUserSettings() +{ + // only save settings when we have (tried) to load the previous + // settings (otherwise user data was lost) + if (!haveUserSettings) + return; + + if (fgGetBool("/sim/startup/save-on-exit")) { + // don't save settings more than once on shutdown + haveUserSettings = false; + + SGPath autosaveFile(globals->get_fg_home()); + autosaveFile.append(autosaveName()); + autosaveFile.create_dir( 0700 ); + SG_LOG(SG_IO, SG_INFO, "Saving user settings to " << autosaveFile.str()); + try { + writeProperties(autosaveFile.str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE); + } catch (const sg_exception &e) { + guiErrorMessage("Error writing autosave:", e); + } + SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings"); + } +} + FGViewer * FGGlobals::get_current_view () const { @@ -418,5 +607,5 @@ void FGGlobals::set_warp_delta( long int d ) { fgSetInt("/sim/time/warp-delta", d); } - + // end of globals.cxx