10#include <simgear/compiler.h>
18#if defined(SG_WINDOWS)
23# define isatty _isatty
26# include <sys/types.h>
34#include <osgViewer/Viewer>
36#include <simgear/canvas/Canvas.hxx>
37#include <simgear/constants.h>
38#include <simgear/debug/logstream.hxx>
39#include <simgear/structure/commands.hxx>
40#include <simgear/structure/exception.hxx>
41#include <simgear/structure/event_mgr.hxx>
42#include <simgear/structure/SGPerfMon.hxx>
43#include <simgear/misc/sg_path.hxx>
44#include <simgear/misc/sg_dir.hxx>
45#include <simgear/io/iostreams/sgstream.hxx>
46#include <simgear/misc/strutils.hxx>
47#include <simgear/embedded_resources/EmbeddedResourceManager.hxx>
48#include <simgear/props/props_io.hxx>
49#include <simgear/scene/tsync/terrasync.hxx>
50#include <simgear/timing/sg_time.hxx>
52#include <simgear/scene/material/Effect.hxx>
53#include <simgear/scene/material/matlib.hxx>
54#include <simgear/scene/model/modellib.hxx>
55#include <simgear/scene/model/particles.hxx>
56#include <simgear/scene/tgdb/TreeBin.hxx>
57#include <simgear/scene/tgdb/userdata.hxx>
58#include <simgear/scene/tgdb/VPBTechnique.hxx>
59#include <simgear/scene/tsync/terrasync.hxx>
62#include <simgear/io/torrent.hxx>
65#include <simgear/package/Root.hxx>
66#include <simgear/package/Package.hxx>
67#include <simgear/package/Install.hxx>
68#include <simgear/package/Catalog.hxx>
114#if defined(ENABLE_SWIFT)
163 sg_gzifstream in(
p );
176 SGPath
p = path /
"base_package.json";
186 const auto content = in.read_all();
187 cJSON* json = cJSON_Parse(content.c_str());
190 r.
buildDate = cJSON_GetObjectItem(json,
"build-date")->valuestring;
191 r.
gitRevision = cJSON_GetObjectItem(json,
"fgdata-sha")->valuestring;
202 _cache = autoSave->getNode(
"sim/startup/path-cache",
true);
207 _didUseLauncher = didUseLauncher;
218 const std::string aircraftDir =
fgGetString(
"/sim/aircraft-dir",
"");
219 if (aircraftDir.empty()) {
223 const std::string aircraft =
fgGetString(
"/sim/aircraft",
"");
224 SGPath setFile = SGPath::fromUtf8(aircraftDir) / (aircraft +
"-set.xml");
225 return setFile.exists();
230 std::string aircraft =
fgGetString(
"/sim/aircraft",
"");
231 if (aircraft.empty()) {
233 "No aircraft was specified");
234 SG_LOG(SG_GENERAL, SG_ALERT,
"no aircraft specified");
238 _searchAircraft = aircraft +
"-set.xml";
239 std::string aircraftDir =
fgGetString(
"/sim/aircraft-dir",
"");
240 if (!aircraftDir.empty()) {
242 simgear::Dir acPath(aircraftDir);
243 SGPath setFile = acPath.file(_searchAircraft);
244 if (setFile.exists()) {
245 SG_LOG(SG_GENERAL, SG_INFO,
"found aircraft in dir: " << aircraftDir );
248 readProperties(setFile,
globals->get_props());
249 }
catch (
const sg_exception &e ) {
250 SG_LOG(SG_IO, SG_ALERT,
251 "Error reading aircraft: " << e.getFormattedMessage());
253 SG_LOG(SG_IO, SG_ALERT,
"aircraft dir is:" << aircraftDir);
255 "Error reading aircraft",
256 "An error occured reading the requested aircraft (" + aircraft +
")",
257 e.getFormattedMessage());
261 checkAircraftMinVersion();
262 checkAircraftDirName();
268 SG_LOG(SG_GENERAL, SG_ALERT,
"aircraft '" << _searchAircraft <<
269 "' not found in specified dir:" << aircraftDir);
272 "Aircraft not found",
273 "The requested aircraft (" + aircraft +
") could not be found "
274 "in the specified location. (" +
285 SGPropertyNode* n = _cache->getNode(
"fg-root",
true);
286 n->setStringValue(
globals->get_fg_root().utf8Str());
287 n->setAttribute(SGPropertyNode::USERARCHIVE,
true);
288 n = _cache->getNode(
"fg-aircraft",
true);
289 n->setStringValue(getAircraftPaths().c_str());
290 n->setAttribute(SGPropertyNode::USERARCHIVE,
true);
291 _cache->removeChildren(
"aircraft");
296 if (_foundPath.isNull()) {
297 SG_LOG(SG_GENERAL, SG_ALERT,
298 "Cannot find the specified aircraft: '" << aircraft <<
"'");
302 SG_LOG(SG_GENERAL, SG_ALERT,
"\tin paths:" << SGPath::join(
globals->get_aircraft_paths(),
";"));
304 std::string notFoundMessage;
307 bool reportToSentry = _didUseLauncher;
309 if (
globals->get_aircraft_paths().empty()) {
310 notFoundMessage =
"The requested aircraft (" + aircraft +
") could not be found. No aircraft paths are configured.";
311 reportToSentry =
false;
313 notFoundMessage =
"The requested aircraft (" + aircraft +
") could not be found in any of the search paths.";
317 "Aircraft not found",
324 SG_LOG(SG_GENERAL, SG_INFO,
"Loading aircraft -set file from:" << _foundPath);
325 fgSetString(
"/sim/aircraft-dir", _foundPath.dir().c_str());
326 if (!_foundPath.exists()) {
327 SG_LOG(SG_GENERAL, SG_ALERT,
"Unable to find -set file:" << _foundPath);
333 readProperties(_foundPath,
globals->get_props());
334 }
catch (
const sg_exception &e ) {
335 SG_LOG(SG_INPUT, SG_ALERT,
336 "Error reading aircraft: " << e.getFormattedMessage());
338 "Error reading aircraft",
339 "An error occured reading the requested aircraft (" + aircraft +
")",
340 e.getFormattedMessage());
347 checkAircraftMinVersion();
348 checkAircraftDirName();
354 std::string getAircraftPaths()
356 return SGPath::join(
globals->get_aircraft_paths(),
";");
365 if (getAircraftPaths() != _cache->getStringValue(
"fg-aircraft",
"")) {
369 std::vector<SGPropertyNode_ptr> cache = _cache->getChildren(
"aircraft");
370 for (
unsigned int i = 0;
i < cache.size();
i++) {
371 const std::string
name = cache[
i]->getStringValue(
"file",
"");
372 if (!simgear::strutils::iequals(_searchAircraft,
name)) {
392 SGPath realPath =
p.realpath();
396 if (!_cache->getChild(
"aircraft",
i++,
false))
400 SGPropertyNode *n, *entry = _cache->getChild(
"aircraft", --
i,
true);
402 std::string fileName(realPath.file());
403 n = entry->getNode(
"file",
true);
404 n->setStringValue(fileName);
405 n->setAttribute(SGPropertyNode::USERARCHIVE,
true);
407 n = entry->getNode(
"path",
true);
408 n->setStringValue(realPath.dir());
409 n->setAttribute(SGPropertyNode::USERARCHIVE,
true);
411 if (simgear::strutils::iequals(fileName, _searchAircraft)) {
412 _foundPath = realPath;
419 bool checkAircraftMinVersion()
421 SGPropertyNode* minVersionNode =
globals->
get_props()->getNode(
"/sim/minimum-fg-version");
422 if (minVersionNode) {
423 std::string minVersion = minVersionNode->getStringValue();
424 const int c = simgear::strutils::compare_versions(FLIGHTGEAR_VERSION, minVersion, 2);
426 SG_LOG(SG_AIRCRAFT, SG_DEV_ALERT,
"Aircraft minimum version (" << minVersion <<
427 ") is higher than FG version:" << FLIGHTGEAR_VERSION);
429 "The selected aircraft requires FlightGear version " + minVersion
430 +
" to work correctly. Some features may not work as expected, or the aircraft may not load at all.");
434 SG_LOG(SG_AIRCRAFT, SG_DEV_ALERT,
"Aircraft does not specify a minimum FG version: please add one at /sim/minimum-fg-version");
437 auto compatNodes =
globals->
get_props()->getNode(
"/sim")->getChildren(
"compatible-fg-version");
438 if (!compatNodes.empty()) {
439 bool showCompatWarning =
true;
442 for (
const auto& cn : compatNodes) {
443 const auto v = cn->getStringValue();
444 if (simgear::strutils::compareVersionToWildcard(FLIGHTGEAR_VERSION, v)) {
445 showCompatWarning =
false;
450 if (showCompatWarning) {
452 "The selected aircraft has not been checked for compatability with this version of FlightGear (" FLIGHTGEAR_VERSION
"). "
453 "Some aircraft features might not work, or might be displayed incorrectly.");
460 bool checkAircraftDirName()
462 auto expectedDirNode =
globals->
get_props()->getNode(
"/sim/expected-aircraft-dir-name");
463 const string aircraftId =
fgGetString(
"/sim/aircraft");
464 if (aircraftId !=
fgGetString(
"/sim/aircraft-id")){
469 if (expectedDirNode) {
470 const string expectedDir = expectedDirNode->getStringValue();
471 const SGPath dir(
fgGetString(
"/sim/aircraft-dir"));
472 if (dir.file() != expectedDirNode->getStringValue()) {
474 "The folder of the selected aircraft must be named '" + expectedDir +
475 "' (instead of '" + dir.file() +
"') to work correctly. If you downloaded it yourself, " +
476 "please ensure the folder is called '" +
477 expectedDir +
"' and re-name if necessary.");
487 std::string _searchAircraft;
489 SGPropertyNode* _cache =
nullptr;
490 bool _didUseLauncher =
false;
496 SGPath appDataPath = SGPath::fromEnv(
"APPDATA");
498 if (appDataPath.isNull()) {
500 "FlightGear",
"Unable to get the value of APPDATA.",
501 "FlightGear is unable to retrieve the value of the APPDATA environment "
502 "variable. This is quite unexpected on Windows platforms, and FlightGear "
503 "can't continue its execution without this value, sorry.");
506 return appDataPath /
"flightgear.org";
516 return SGPath::home() /
".fgfs";
520#if defined(SG_WINDOWS)
521static HANDLE static_fgHomeWriteMutex =
nullptr;
532 globals->set_fg_home(dataPath);
534 simgear::Dir fgHome(dataPath);
535 if (!fgHome.exists()) {
539 if (!fgHome.exists()) {
541 "Problem setting up user data",
542 "Unable to create the user-data storage folder at '" +
543 dataPath.utf8Str() +
"'.");
547 if (
fgGetBool(
"/sim/fghome-readonly",
false)) {
549 SG_LOG(SG_GENERAL, SG_INFO,
"Running with FG_HOME readonly");
554#if defined(SG_WINDOWS)
559 static_fgHomeWriteMutex = CreateMutexA(
nullptr, FALSE,
"org.flightgear.fgfs.primary");
560 if (static_fgHomeWriteMutex ==
nullptr) {
561 printf(
"CreateMutex error: %d\n", GetLastError());
562 SG_LOG(SG_GENERAL, SG_ALERT,
"Failed to create mutex for multi-app protection");
564 }
else if (GetLastError() == ERROR_ALREADY_EXISTS) {
565 SG_LOG(SG_GENERAL, SG_POPUP,
"flightgear instance already running, switching to FG_HOME read-only.");
569 SG_LOG(SG_GENERAL, SG_INFO,
"Created multi-app mutex, we are in writeable mode");
574 SGPath pidPath(dataPath,
"fgfs_lock.pid");
575 std::string ps = pidPath.utf8Str();
577 if (pidPath.exists()) {
578 int fd = ::open(ps.c_str(), O_RDONLY, 0644);
580 SG_LOG(SG_GENERAL, SG_ALERT,
"failed to open local file:" << pidPath
581 <<
"\n\tdue to:" << simgear::strutils::error_string(errno));
585 int err = ::flock(fd, LOCK_EX | LOCK_NB);
587 if ( errno == EWOULDBLOCK) {
588 SG_LOG(SG_GENERAL, SG_ALERT,
"flightgear instance already running, switching to FG_HOME read-only. ");
589 SG_LOG(SG_GENERAL, SG_ALERT,
"Couldn't flock() file at:" << pidPath);
596 SG_LOG(SG_GENERAL, SG_ALERT,
"failed to lock file:" << pidPath
597 <<
"\n\tdue to:" << simgear::strutils::error_string(errno));
606 std::string ps = pidPath.utf8Str();
608 ssize_t len = snprintf(buf, 16,
"%d\n", getpid());
609 int fd = ::open(ps.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
611 SG_LOG(SG_GENERAL, SG_ALERT,
"failed to open local file:" << pidPath
612 <<
"\n\tdue to:" << simgear::strutils::error_string(errno));
616 int err = write(fd, buf, len);
618 SG_LOG(SG_GENERAL, SG_ALERT,
"failed to write to lock file:" << pidPath
619 <<
"\n\tdue to:" << simgear::strutils::error_string(errno));
623 err = flock(fd, LOCK_EX);
625 SG_LOG(SG_GENERAL, SG_ALERT,
"failed to lock file:" << pidPath
626 <<
"\n\tdue to:" << simgear::strutils::error_string(errno));
633 fgSetBool(
"/sim/fghome-readonly",
false);
639#if defined(SG_WINDOWS)
640 if (static_fgHomeWriteMutex) {
641 CloseHandle(static_fgHomeWriteMutex);
644 if (
fgGetBool(
"/sim/fghome-readonly") ==
false) {
645 SGPath pidPath =
globals->get_fg_home() /
"fgfs_lock.pid";
653#if defined(SG_WINDOWS)
656 SGPath pidPath =
globals->get_fg_home() /
"fgfs_lock.pid";
663 SGPath addonStorageBasePath = exportDir /
"Addons";
664 if (addonStorageBasePath.exists()) {
665 if (!addonStorageBasePath.isDir()) {
667 "Unable to create add-on storage base directory, because the entry "
668 "already exists but is not a directory: '" +
669 addonStorageBasePath.utf8Str() +
"'");
672 simgear::Dir(addonStorageBasePath).create(0777);
682 bool fileLine = node->getBoolValue();
683 sglog().setFileLine(fileLine);
690 SGPath dataPath =
globals->get_fg_home();
692 simgear::Dir exportDir(simgear::Dir(dataPath).file(
"Export"));
693 if (!exportDir.exists()) {
694 exportDir.create(0755);
704 SGPropertyNode *home =
fgGetNode(
"/sim",
true);
705 home->removeChild(
"fg-home", 0);
706 home = home->getChild(
"fg-home", 0,
true);
707 home->setStringValue(dataPath.utf8Str());
708 home->setAttribute(SGPropertyNode::WRITE,
false);
713 auto result =
options->init(argc, argv, dataPath);
720 bool developerMode =
true;
721 if (!strcmp(FG_BUILD_TYPE,
"Release")) {
722 developerMode =
false;
726 const std::optional<bool> devOption =
options->checkBoolOptionSet(
"developer");
727 if (devOption.has_value()) {
728 developerMode = devOption.value();
731 auto node =
fgGetNode(
"/sim/developer-mode",
true);
733 node->setAttribute(SGPropertyNode::PRESERVE,
true);
734 node->setBoolValue(developerMode);
735 sglog().setDeveloperMode(developerMode);
740 SG_LOG(SG_GENERAL, SG_DEBUG,
"Reading global defaults");
741 SGPath defaultsXML =
globals->get_fg_root() /
"defaults.xml";
742 if (!defaultsXML.exists()) {
745 "Couldn't load an essential simulator data file.",
746 defaultsXML.utf8Str());
753 "Couldn't load an essential simulator data file as it is corrupted.",
754 defaultsXML.utf8Str());
756 SG_LOG(SG_GENERAL, SG_DEBUG,
"Finished Reading global defaults");
760 if (
options->isOptionSet(
"restore-defaults") ||
options->isOptionSet(
"ignore-autosave"))
762 SG_LOG(SG_GENERAL, SG_ALERT,
"Ignoring user settings. Restoring defaults.");
764 globals->loadUserSettings(dataPath);
774 SGPropertyNode* sim =
fgGetNode(
"/sim",
true);
775 sim->removeChildren(
"fg-aircraft");
779 for (PathList::const_iterator it = aircraft_paths.begin();
780 it != aircraft_paths.end(); ++it, ++index )
782 SGPropertyNode* n = sim->getChild(
"fg-aircraft", index,
true);
783 n->setStringValue(it->utf8Str());
784 n->setAttribute(SGPropertyNode::WRITE,
false);
794 SGSharedPtr<Root> pkgRoot(
globals->packageRoot());
795 SGPropertyNode* aircraftProp =
fgGetNode(
"/sim/aircraft",
true);
796 aircraftProp->setAttribute(SGPropertyNode::PRESERVE,
true);
815 SGSharedPtr<Root> pkgRoot(
globals->packageRoot());
816 SGPropertyNode* aircraftProp =
fgGetNode(
"/sim/aircraft",
true);
817 SGPropertyNode* aircraftDirProp =
fgGetNode(
"/sim/aircraft-dir",
true);
822 aircraftDirProp->setAttribute(SGPropertyNode::PRESERVE,
true);
824 const string fullyQualifiedAircraftId =
fgGetString(
"/sim/aircraft-id");
825 string aircraftId = fullyQualifiedAircraftId.empty() ? aircraftProp->getStringValue() : fullyQualifiedAircraftId;
829 PackageRef acftPackage;
831 acftPackage = pkgRoot->getPackageById(aircraftId);
835 if (acftPackage->isInstalled()) {
836 SG_LOG(SG_GENERAL, SG_INFO,
"Loading aircraft from package:" << acftPackage->qualifiedId());
838 fgSetString(
"/sim/aircraft-id", acftPackage->qualifiedId());
845 globals->set_catalog_aircraft_path(acftPackage->catalog()->installRoot());
848 InstallRef acftInstall = acftPackage->install();
849 fgSetString(
"/sim/aircraft-dir", acftInstall->path().utf8Str());
854 size_t lastDot = aircraftId.rfind(
'.');
855 if (lastDot != std::string::npos) {
856 aircraftId = aircraftId.substr(lastDot + 1);
858 aircraftProp->setStringValue(aircraftId);
865 "Aircraft not installed",
866 "Requested aircraft is not currently installed.",
895 static bool doingRebuild =
false;
902 static const char* splashIdentsByRebuildPhase[] = {
904 "navdata-reading-apt-dat-files",
905 "navdata-loading-airports",
921 SGTimeStamp::sleepForMSec(50);
927 globals->set_channellist( channellist );
929 SGPath path(
globals->get_fg_root());
930 path.append(
"Navaids/TACAN_freq.dat" );
939 SG_LOG( SG_GENERAL, SG_INFO,
"General Initialization" );
940 SG_LOG( SG_GENERAL, SG_INFO,
"======= ==============" );
942 if (
globals->get_fg_root().isNull() ) {
944 SG_LOG( SG_GENERAL, SG_ALERT,
945 "Cannot continue without a path to the base package "
946 <<
"being defined." );
949 SG_LOG( SG_GENERAL, SG_INFO,
"FG_ROOT = " <<
'"' <<
globals->get_fg_root() <<
'"' << endl );
955 simgear::Dir cwd(simgear::Dir::current());
956 SGPropertyNode *curr =
fgGetNode(
"/sim",
true);
957 curr->removeChild(
"fg-current", 0);
958 curr = curr->getChild(
"fg-current", 0,
true);
959 curr->setStringValue(cwd.path().utf8Str());
960 curr->setAttribute(SGPropertyNode::WRITE,
false);
962 fgSetBool(
"/sim/startup/stdout-to-terminal", isatty(1) != 0 );
963 fgSetBool(
"/sim/startup/stderr-to-terminal", isatty(2) != 0 );
965 sgUserDataInit(
globals->get_props() );
974 SG_LOG( SG_GENERAL, SG_INFO,
"Configuration State" );
975 SG_LOG( SG_GENERAL, SG_INFO,
"============= =====" );
977 SG_LOG( SG_GENERAL, SG_INFO,
"aircraft-dir = " <<
'"' <<
fgGetString(
"/sim/aircraft-dir") <<
'"' );
978 SG_LOG( SG_GENERAL, SG_INFO,
"fghome-dir = " <<
'"' <<
globals->get_fg_home() <<
'"');
979 SG_LOG( SG_GENERAL, SG_INFO,
"download-dir = " <<
'"' <<
fgGetString(
"/sim/paths/download-dir") <<
'"' );
980 SG_LOG( SG_GENERAL, SG_INFO,
"terrasync-dir = " <<
'"' <<
fgGetString(
"/sim/terrasync/scenery-dir") <<
'"' );
982 SG_LOG( SG_GENERAL, SG_INFO,
"aircraft-search-paths = \n\t" << SGPath::join(
globals->get_aircraft_paths(),
"\n\t") );
983 SG_LOG( SG_GENERAL, SG_INFO,
"scenery-search-paths = \n\t" << SGPath::join(
globals->get_fg_scenery(),
"\n\t") );
987static simgear::HTTP::Client* s_getHttpClient()
999 SG_LOG( SG_GENERAL, SG_INFO,
"== Creating Subsystems");
1002 auto mgr =
globals->get_subsystem_mgr();
1004 globals->get_event_mgr()->init();
1005 globals->get_event_mgr()->setRealtimeProperty(
fgGetNode(
"/sim/time/delta-realtime-sec",
true));
1020 mgr->add(
"performance-mon",
1021 new SGPerformanceMonitor(
1023 fgGetNode(
"/sim/performance-monitor",
true)
1028 SGPath mpath(
globals->get_fg_root() );
1029 mpath.append(
fgGetString(
"/sim/rendering/materials-file") );
1031 throw sg_io_exception(
"Error loading materials file", mpath);
1041 mgr->add(simgear::Torrent::staticSubsystemClassId(),
1042 new simgear::Torrent(
1065 mgr->add(
"httpd", httpd);
1109 mgr->get_subsystem<
FGReplay>()->init();
1127 simgear::canvas::Canvas::setSystemAdapter(
1132 auto canvasGui =
new GUIMgr;
1133 mgr->add(
"CanvasGUI", canvasGui, SGSubsystemMgr::DISPLAY);
1135 canvasGui->setGUIViewAndCamera(
globals->get_renderer()->getView(), guiCamera);
1137 #ifdef ENABLE_AUDIO_SUPPORT
1144 mgr->add(
"events",
globals->get_event_mgr(), SGSubsystemMgr::DISPLAY);
1177 auto mgr =
globals->get_subsystem_mgr();
1188 SG_LOG(SG_GENERAL, SG_INFO,
"Subsystems postinit took:" << st.elapsedMSec());
1197 SG_LOG( SG_GENERAL, SG_INFO, endl);
1206 SGPropertyNode *master_freeze =
fgGetNode(
"/sim/freeze/master");
1207 SG_LOG( SG_GENERAL, SG_INFO,
"fgStartReposition()");
1212 bool freeze = master_freeze->getBoolValue();
1214 master_freeze->setBoolValue(
true);
1222 auto mgr =
globals->get_subsystem_mgr();
1224 mgr->get_subsystem<
FDMShell>()->unbind();
1231 auto terraSync = mgr->get_subsystem<simgear::SGTerraSync>();
1233 terraSync->reposition();
1237 mgr->get_subsystem<
FDMShell>()->reinit();
1240 mgr->get_subsystem<
FGReplay>()->reinit();
1248 auto envMgr =
static_cast<SGSubsystemGroup*
>(mgr->get_subsystem<
FGEnvironmentMgr>());
1250 envMgr->get_subsystem(
"realwx")->reinit();
1256 atcManager->reposition();
1260 mgr->get_subsystem<
FDMShell>()->bind();
1266 mgr->get_subsystem(
"xml-autopilot")->reinit();
1269 auto timeManager = mgr->get_subsystem<
TimeManager>();
1271 timeManager->reposition();
1275 fgSetBool(
"/sim/signals/reinit",
false);
1277 master_freeze->setBoolValue(
false);
1292 SGPropertyNode_ptr preserved(
new SGPropertyNode);
1294 if (!copyPropertiesWithAttribute(
globals->get_props(), preserved, SGPropertyNode::PRESERVE))
1295 SG_LOG(SG_GENERAL, SG_ALERT,
"Error saving preserved state");
1304 pager->setAcceptNewDatabaseRequests(
false);
1310 assert(
pager->getDataToMergeListSize() == 0);
1311 assert(
pager->getDataToCompileListSize() == 0);
1314 SGSubsystemMgr* subsystemManger =
globals->get_subsystem_mgr();
1317 subsystemManger->remove(
"nasal");
1319 subsystemManger->shutdown();
1320 subsystemManger->unbind();
1328 for (
int g=0; g<SGSubsystemMgr::MAX_GROUPS; ++g) {
1329 SGSubsystemGroup* grp = subsystemManger->get_group(
static_cast<SGSubsystemMgr::GroupType
>(g));
1330 for (
auto nm : grp->member_names()) {
1331 if ((nm ==
"time") || (nm ==
"terrasync") || (nm ==
"events")
1332 || (nm ==
"lighting")
1341 subsystemManger->remove(nm.c_str());
1342 }
catch (std::exception& e) {
1343 SG_LOG(SG_GENERAL, SG_INFO,
"caught " << e.what() <<
" << shutting down:" << nm);
1345 SG_LOG(SG_GENERAL, SG_INFO,
"caught generic exception shutting down:" << nm);
1358 osg::ref_ptr<osgViewer::CompositeViewer> composite_viewer = render->
getCompositeViewer();
1359 osg::ref_ptr<osgViewer::View> composite_viewer_view;
1360 if (composite_viewer) {
1361 composite_viewer_view = render->
getView();
1372 osgDB::Registry::instance()->clearObjectCache();
1374 sgUserDataInit( NULL );
1378 osg::ref_ptr<flightgear::FGEventHandler> eventHandler = render->
getEventHandler();
1380 eventHandler->
clear();
1388 simgear::clearEffectCache();
1389 simgear::VPBTechnique::clearConstraints();
1390 simgear::SGModelLib::resetPropertyRoot();
1391 simgear::ParticlesGlobalManager::clear();
1392 simgear::UniformFactory::instance()->reset();
1398 globals->get_channel_options_list()->clear();
1418 SGCommandMgr::instance()->setImplicitRoot(
globals->get_props());
1427 const auto& resMgr = simgear::EmbeddedResourceManager::instance();
1429 const string locale =
globals->get_locale()->getPreferredLanguage();
1430 resMgr->selectLocale(locale);
1431 SG_LOG(SG_GENERAL, SG_INFO,
1432 "EmbeddedResourceManager: selected locale '" << locale <<
"'");
1435 if ( copyProperties(preserved,
globals->get_props()) ) {
1436 SG_LOG( SG_GENERAL, SG_INFO,
"Preserved state restored successfully" );
1438 SG_LOG( SG_GENERAL, SG_INFO,
1439 "Some errors restoring preserved state (read-only props?)" );
1445 globals->get_locale()->loadAircraftTranslations();
1446 globals->get_locale()->loadAddonTranslations();
1454 eventHandler->reset();
1455 globals->set_renderer(render);
1457 render->
setView(composite_viewer_view);
1459 unsigned int numDBPagerThreads = std::max(
fgGetNode(
"/sim/rendering/database-pager/threads",
true)->getIntValue(1), 1);
1461 composite_viewer_view->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(
true,
false);
1462 composite_viewer_view->getDatabasePager()->setUpThreads(numDBPagerThreads, 0);
1463 composite_viewer_view->getDatabasePager()->setAcceptNewDatabaseRequests(
true);
1464 composite_viewer_view->setFrameStamp(composite_viewer->getFrameStamp());
1467 osg::GraphicsContext::createNewContextID();
1469 render->
setView(composite_viewer_view);
1471 composite_viewer->startThreading();
1478 globals->get_event_mgr()->init();
1479 globals->get_event_mgr()->setRealtimeProperty(
fgGetNode(
"/sim/time/delta-realtime-sec",
true));
1481 globals->set_matlib(
new SGMaterialLib );
1484 auto terra_sync = subsystemManger->get_subsystem<simgear::SGTerraSync>();
1486 terra_sync->setRoot(
globals->get_props());
1489 fgSetBool(
"/sim/signals/reinit",
false);
1503 packageAircraftDir.append(
"Aircraft");
1505 SG_LOG(SG_GENERAL, SG_INFO,
"init package root at:" << packageAircraftDir);
1507 SGSharedPtr<Root> pkgRoot(
new Root(packageAircraftDir, FLIGHTGEAR_VERSION));
1509 globals->setPackageRoot(pkgRoot);
1516 simgear::Dir fgHome(dataPath);
1517 if (fgHome.exists()) {
1518 if (!fgHome.remove(
true )) {
1519 fprintf(stderr,
"Errors occurred trying to remove FG_HOME");
1520 return EXIT_FAILURE;
1524 if (fgHome.exists()) {
1525 fprintf(stderr,
"unable to remove FG_HOME");
1526 return EXIT_FAILURE;
1529#if defined(SG_WINDOWS)
1534 SGPath terrasyncPath =
p /
"TerraSync";
1535 if (terrasyncPath.exists()) {
1536 simgear::Dir dir(terrasyncPath);
1537 if (!dir.remove(
true )) {
1538 std::cerr <<
"Errors occurred trying to remove " << terrasyncPath << std::endl;
1542 SGPath packagesPath =
p /
"Aircraft";
1543 if (packagesPath.exists()) {
1544 simgear::Dir dir(packagesPath);
1545 if (!dir.remove(
true )) {
1546 std::cerr <<
"Errors occurred trying to remove " << packagesPath << std::endl;
1550 SGPath cachePath =
p /
"TextureCache";
1551 if (cachePath.exists()) {
1552 simgear::Dir dir(cachePath);
1553 if (!dir.remove(
true )) {
1554 std::cerr <<
"Errors occurred trying to remove " << cachePath << std::endl;
1558 return EXIT_SUCCESS;
bool options(int, char **)
VisitResult visitAircraftPaths()
Wrap SGEphemeris in a subsystem/property interface.
Wrap an FDM implementation in a subsystem with standard semantics Notably, deal with the various case...
Manage environment information.
record the history of the aircraft's movements, making it available as a contiguous block.
SGPropertyNode * get_props()
const SGPath & get_fg_root() const
Manage aircraft instruments.
Log any property values to any number of CSV files.
Manage a list of user-specified models.
osgViewer::View * getView()
osg::ref_ptr< osgViewer::CompositeViewer > getCompositeViewer()
Both should only be used on reset.
void setView(osgViewer::View *view)
flightgear::FGEventHandler * getEventHandler()
void init()
Initialize the renderer.
osgViewer::ViewerBase * getViewerBase() const
void setEventHandler(flightgear::FGEventHandler *event_handler)
void postinit()
Called after init() was called, the graphics window has been created and the CameraGroup has been ini...
void setCompositeViewer(osg::ref_ptr< osgViewer::CompositeViewer > composite_viewer)
Top level route manager class.
static flightgear::SceneryPager * getPagerSingleton()
static const char * staticSubsystemClassId()
static FGXMLAutopilotGroup * createInstance(const std::string &nodeName)
bool haveExplicitAircraft() const
haveExplicitAircraft - check if the combination of /sim/aircraft and /sim/aircraft-dir defines an exp...
FindAndCacheAircraft(SGPropertyNode *autoSave)
void setDidUseLauncher(bool didUseLauncher)
XML-configured GUI subsystem.
static CameraGroup * getDefault()
Get the default CameraGroup.
static void buildDefaultGroup(osgViewer::View *view)
Set the default CameraGroup, which is the only one that matters at this time.
static void setDefault(CameraGroup *group)
static const char * staticSubsystemClassId()
void applyInitialPreset()
init() is called too late (after fgOSInit), so we call this method early, to load the initial preset ...
void clearDynamicPositioneds()
static NavDataCache * createInstance()
unsigned int rebuildPhaseCompletionPercentage() const
static NavDataCache * instance()
bool isRebuildRequired()
predicate - check if the cache needs to be rebuilt.
RebuildPhase rebuild()
run the cache rebuild - returns the current phase or 'done'
bool loadTacan(const SGPath &path, FGTACANList *channellist)
OptionResult processOptions()
apply option values to the simulation state (set properties, etc).
void initPaths()
process command line options relating to scenery / aircraft / data paths
SGPath actualDownloadDir()
the actual download dir in use, which may be the default or a user-supplied value
OptionResult initAircraft()
init the aircraft options
static Options * sharedInstance()
static const std::unique_ptr< AddonManager > & createInstance()
static FGHttpd * createInstance(SGPropertyNode_ptr configNode)
void fgPostInitSubsystems()
bool fgInitNav()
Initialize vor/ndb/ils/fix list management and query systems (as well as simple airport db list) This...
int fgInitAircraft(bool reinit, bool didUseLauncher)
static SGPath platformDefaultDataPath()
int fgInitConfig(int argc, char **argv, bool reinit)
void fgCreateSubsystems(bool duringReset)
static void initAircraftDirsNasalSecurity()
string fgBasePackageVersion(const SGPath &base_path)
void fgInitAircraftPaths(bool reinit)
static void createBaseStorageDirForAddons(const SGPath &exportDir)
std::optional< FGBasePackageInfo > fgBasePackageInfo(const SGPath &path)
Parse the base package info JSON.
InitHomeResult fgInitHome()
@ InitHomeExplicitReadOnly
void fgOSResetProperties()
void fgAddChangeListener(SGPropertyChangeListener *listener, const char *path)
Add a listener to a node.
bool fgLoadProps(const std::string &path, SGPropertyNode *props, bool in_fg_root, int default_mode)
Load properties from a file.
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
void fgSetArchivable(const char *name, bool state)
Set the state of the archive attribute for a property.
std::vector< SGPath > PathList
FlightGear Localization Support.
const std::string & getStringValue(const char *spec)
const char * PROPERTY_ROOT
MessageBoxResult modalMessageBox(const std::string &caption, const std::string &msg, const std::string &moreText)
MessageBoxResult fatalMessageBoxWithoutExit(const std::string &caption, const std::string &msg, const std::string &moreText, bool reportToSentry)
SGPath defaultDownloadDir()
return the default platform dependant download directory.
void unregisterMainLoopProperties()
void updateSentryTag(const std::string &, const std::string &)
void addSentryBreadcrumb(const std::string &, const std::string &)
osg::Camera * getGUICamera(CameraGroup *cgroup)
Get the osg::Camera that draws the GUI, if any, from a camera group.
void addSentryTag(const char *, const char *)
void fatalMessageBoxThenExit(const std::string &caption, const std::string &msg, const std::string &moreText, int exitStatus, bool reportToSentry)
@ FG_OPTIONS_SHOW_AIRCRAFT
void fgSetDefaults()
Set a few fail-safe default property values.
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
static osg::ref_ptr< SceneryPager > pager
void fgSplashProgress(const char *identifier, unsigned int percent)
Set progress information.
structure holding parsed info from <base-package>/base_package.json
static void resetStatisticsProperties()
virtual void valueChanged(SGPropertyNode *node)
void fgInitAllowedPaths()
Allowed paths here are absolute, and may contain one *, which matches any string.