Modify startup sequence, so position can be modified late in the startup process, right before the scenery load starts. This allows two ugly hacks to move to a permanent, less hacky location. If other position init modes required similar late evaluation in the future, this can be accommodated now.
This is a somewhat high-risk change - I've tested both carrier starts and runway-selection based on realwx METAR, but please look out for other position-init issues and test before / after this patch.
{
_timeToLive -= dt;
_pollingTimer -= dt;
- if( _timeToLive < 0.0 ) {
+ if( _timeToLive <= 0.0 ) {
_timeToLive = 0.0;
std::string stationId = getStationId();
if( stationId.empty() ) return;
void BasicRealWxController::init()
{
_wasEnabled = false;
+
+ checkNearbyMetar();
update(0); // fetch data ASAP
globals->get_event_mgr()->addTask("checkNearbyMetar", this,
SG_LOG(SG_ENVIRONMENT, SG_WARN, "metar download failed:" << url() << ": reason:" << responseReason());
}
}
+
+ virtual void failed()
+ {
+ SG_LOG(SG_ENVIRONMENT, SG_INFO, "metar download failure");
+ }
// bool fromMetarProxy() const
// { return _fromProxy; }
exit(-1);
}
-
+ globals->add_subsystem( "http", new FGHTTPClient );
+
////////////////////////////////////////////////////////////////////
// Initialize the scenery management subsystem.
////////////////////////////////////////////////////////////////////
// Initialize the Input-Output subsystem
////////////////////////////////////////////////////////////////////
globals->add_subsystem( "io", new FGIO );
- globals->add_subsystem( "http", new FGHTTPClient );
////////////////////////////////////////////////////////////////////
// Create and register the logger.
globals->get_subsystem_mgr()->postinit();
SG_LOG(SG_GENERAL, SG_INFO, "Subsystems postinit took:" << st.elapsedMSec());
- ////////////////////////////////////////////////////////////////////
- // TODO FIXME! UGLY KLUDGE!
- ////////////////////////////////////////////////////////////////////
- {
- /* Scenarios require Nasal, so FGAIManager loads the scenarios,
- * including its models such as a/c carriers, in its 'postinit',
- * which is the very last thing we do.
- * flightgear::initPosition is called very early in main.cxx/fgIdleFunction,
- * one of the first things we do, long before scenarios/carriers are
- * loaded. => When requested "initial preset position" relates to a
- * carrier, recalculate the 'initial' position here (how have things
- * ever worked before this hack - this init sequence has always been
- * this way...?)*/
- std::string carrier = fgGetString("/sim/presets/carrier","");
- if (carrier != "")
- {
- // clear preset location and re-trigger position setup
- fgSetDouble("/sim/presets/longitude-deg", 9999);
- fgSetDouble("/sim/presets/latitude-deg", 9999);
- flightgear::initPosition();
- }
- }
-
////////////////////////////////////////////////////////////////////////
// End of subsystem initialization.
////////////////////////////////////////////////////////////////////
}
} else if ( idle_state == 10 ) {
- idle_state = 900;
+ idle_state = 800;
fgPostInitSubsystems();
-
- // Torsten Dreyer:
- // ugly hack for automatic runway selection on startup based on
- // metar data. Makes startup.nas obsolete and guarantees the same
- // runway selection as for AI traffic. However, this code belongs to
- // somewhere(?) else - if I only new where...
- if( true == fgGetBool( "/environment/metar/valid" ) ) {
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
- // the realwx_ctrl fetches metar in the foreground on init,
- // If it was able to fetch a metar or one was given on the commandline,
- // the valid flag is set here, otherwise it is false
- double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
- string apt = fgGetString( "/sim/startup/options/airport" );
- string rwy = fgGetString( "/sim/startup/options/runway" );
- double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
- string parkpos = fgGetString( "/sim/presets/parkpos" );
- bool onground = fgGetBool( "/sim/presets/onground", false );
- // don't check for wind-speed < 1kt, this belongs to the runway-selection code
- // the other logic is taken from former startup.nas
- if( hdg < 360.0 && apt.length() > 0 && strthdg > 360.0 && rwy.length() == 0 && onground && parkpos.length() == 0 ) {
- extern bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg );
- flightgear::setPosFromAirportIDandHdg( apt, hdg );
- }
+ } else if ( idle_state == 800 ) {
+ if (flightgear::finalizePosition()) {
+ idle_state = 900;
+ fgSplashProgress("init-graphics");
} else {
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "No METAR available to pick active runway" );
+ fgSplashProgress("finalize-position");
}
-
- fgSplashProgress("init-graphics");
-
} else if ( idle_state == 900 ) {
idle_state = 1000;
namespace flightgear
{
+
+/// to avoid blocking when metar-fetch is enabled, but the network is
+/// unresponsive, we need a timeout value. This value is reset on initPosition,
+/// and tracked through each call to finalizePosition.
+static SGTimeStamp global_finalizeTime;
// Set current tower position lon/lat given an airport id
static bool fgSetTowerPosFromAirportID( const string& id) {
}
// Set current_options lon/lat given an airport id and heading (degrees)
-bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
+static bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
if ( id.empty() )
return false;
// Set the initial position based on presets (or defaults)
bool initPosition()
{
- // cout << "initPosition()" << endl;
+ global_finalizeTime = SGTimeStamp(); // reset to invalid
+
double gs = fgGetDouble("/sim/presets/glideslope-deg")
* SG_DEGREES_TO_RADIANS ;
double od = fgGetDouble("/sim/presets/offset-distance-nm");
return true;
}
+bool finalizePosition()
+{
+ // first call to finalize after an initPosition call
+ if (global_finalizeTime.get_usec() == 0) {
+ global_finalizeTime = SGTimeStamp::now();
+ }
+
+ /* Scenarios require Nasal, so FGAIManager loads the scenarios,
+ * including its models such as a/c carriers, in its 'postinit',
+ * which is the very last thing we do.
+ * flightgear::initPosition is called very early in main.cxx/fgIdleFunction,
+ * one of the first things we do, long before scenarios/carriers are
+ * loaded. => When requested "initial preset position" relates to a
+ * carrier, recalculate the 'initial' position here
+ */
+ std::string carrier = fgGetString("/sim/presets/carrier","");
+ if (!carrier.empty())
+ {
+ SG_LOG(SG_GENERAL, SG_INFO, "finalizePositioned: re-init-ing position on carrier");
+ // clear preset location and re-trigger position setup
+ fgSetDouble("/sim/presets/longitude-deg", 9999);
+ fgSetDouble("/sim/presets/latitude-deg", 9999);
+ return initPosition();
+ }
+
+ double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
+ string apt = fgGetString( "/sim/startup/options/airport" );
+ string rwy = fgGetString( "/sim/startup/options/runway" );
+ double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
+ string parkpos = fgGetString( "/sim/presets/parkpos" );
+ bool onground = fgGetBool( "/sim/presets/onground", false );
+// this logic is taken from former startup.nas
+ bool needMetar = (hdg < 360.0) && !apt.empty() && (strthdg > 360.0) &&
+ rwy.empty() && onground && parkpos.empty();
+
+ if (needMetar) {
+ // timeout so we don't spin forever if the network is down
+ if (global_finalizeTime.elapsedMSec() > fgGetInt("/sim/startup/metar-fetch-timeout-msec", 5000)) {
+ SG_LOG(SG_GENERAL, SG_WARN, "finalizePosition: timed out waiting for METAR fetch");
+ return true;
+ }
+
+ if (!fgGetBool( "/environment/metar/valid" )) {
+ // bit hacky - run these two subsystems. We can't run the whole
+ // lot since some view things aren't initialised and hence FGLight
+ // crashes.
+ globals->get_subsystem("http")->update(0.0);
+ globals->get_subsystem("environment")->update(0.0);
+ return false;
+ }
+
+ SG_LOG(SG_ENVIRONMENT, SG_INFO,
+ "Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
+ setPosFromAirportIDandHdg( apt, hdg );
+ // fall through to return true
+ } // of need-metar case
+
+ return true;
+}
+
} // of namespace flightgear
// Set the initial position based on presets (or defaults)
bool initPosition();
-
+/**
+ * finalize the position once subsystems, Nasal and scenarios are loaded;
+ * all of which can potentially affect the position.
+ * returns true if the position is finally set, or false if more time
+ * is required to finalize the position (eg, awaiting METAR to set the
+ * active runway)
+ */
+bool finalizePosition();
+
// Listen to /sim/tower/airport-id and set tower view position accordingly
void initTowerLocationListener();
-// FIXME - only public becuase of the evil runway-selection hack in main.cxx
-bool setPosFromAirportIDandHdg( const std::string& id, double tgt_hdg );
-
} // of namespace flightgear
#endif // of FG_POSITION_INIT_HXX