diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index 1ae4f5f98..2356e371d 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -939,3 +939,14 @@ bool FGAIBase::isValid() { //Either no flightplan or it is valid return !fp || fp->isValidPlan(); } + +osg::PagedLOD* FGAIBase::getSceneBranch() const +{ + return _model; +} + +SGGeod FGAIBase::getGeodPos() const +{ + return pos; +} + diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index da27569c1..fd88c6fd0 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -109,6 +109,8 @@ public: bool getDie(); bool isValid(); + + SGGeod getGeodPos() const; SGVec3d getCartPosAt(const SGVec3d& off) const; SGVec3d getCartPos() const; @@ -121,6 +123,7 @@ public: double _getCartPosY() const; double _getCartPosZ() const; + osg::PagedLOD* getSceneBranch() const; protected: double _elevation_m; diff --git a/src/AIModel/AICarrier.cxx b/src/AIModel/AICarrier.cxx index 1a0908c93..a6f323d63 100644 --- a/src/AIModel/AICarrier.cxx +++ b/src/AIModel/AICarrier.cxx @@ -590,3 +590,53 @@ void FGAICarrier::UpdateJBD(double dt, double jbd_transition_time) { return; } // end UpdateJBD + +std::pair FGAICarrier::initialPositionForCarrier(const std::string& namePennant) +{ + SGPropertyNode_ptr aiRoot = fgGetNode("/sim/ai", true); + for (const auto scenarioFileNode : aiRoot->getChildren("scenario")) { + SGPropertyNode_ptr s = FGAIManager::loadScenarioFile(scenarioFileNode->getStringValue()); + if (!s || !s->hasChild("scenario")) { + continue; + } + + const std::string carrierType("carrier"); + SGPropertyNode_ptr scenario = s->getChild("scenario"); + for (int i = 0; i < scenario->nChildren(); i++) { + SGPropertyNode* c = scenario->getChild(i); + if (c->getStringValue("type") != carrierType) { + continue; + } + + const auto pennant = c->getStringValue("pennant-number"); + const auto name = c->getStringValue("name"); + if (pennant == namePennant || name == namePennant) { + SGSharedPtr carrier = new FGAICarrier; + carrier->readFromScenario(c); + return std::make_pair(true, carrier->getGeodPos()); + } + } // of objects in scenario iteration + } // of scenario files iteration + + return std::make_pair(false, SGGeod()); +} + +SGSharedPtr FGAICarrier::findCarrierByNameOrPennant(const std::string& namePennant) +{ + const FGAIManager* aiManager = globals->get_subsystem(); + if (!aiManager) { + return {}; + } + + for (const auto aiObject : aiManager->get_ai_list()) { + if (aiObject->isa(FGAIBase::otCarrier)) { + SGSharedPtr c = static_cast(aiObject.get()); + if ((c->sign == namePennant) || (c->_getName() == namePennant)) { + return c; + } + } + } // of all objects iteration + + return {}; +} + diff --git a/src/AIModel/AICarrier.hxx b/src/AIModel/AICarrier.hxx index 970cd7cea..072599579 100644 --- a/src/AIModel/AICarrier.hxx +++ b/src/AIModel/AICarrier.hxx @@ -70,7 +70,13 @@ public: bool getParkPosition(const string& id, SGGeod& geodPos, double& hdng, SGVec3d& uvw); - + + /** + * @brief type-safe wrapper around AIManager::getObjectFromProperty + */ + static SGSharedPtr findCarrierByNameOrPennant(const std::string& namePennant); + + static std::pair initialPositionForCarrier(const std::string& namePennant); private: /// Is sufficient to be private, stores a possible position to place an /// aircraft on start diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 7baf44f20..1131ebcf2 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -519,45 +519,6 @@ FGAIManager::loadScenarioFile(const std::string& filename) return 0; } -bool -FGAIManager::getStartPosition(const string& id, const string& pid, - SGGeod& geodPos, double& hdng, SGVec3d& uvw) -{ - bool found = false; - SGPropertyNode* root = fgGetNode("sim/ai", true); - if (!root->getNode("enabled", true)->getBoolValue()) - return found; - - for (int i = 0 ; (!found) && i < root->nChildren() ; i++) { - SGPropertyNode *aiEntry = root->getChild( i ); - if ( !strcmp( aiEntry->getName(), "scenario" ) ) { - const string& filename = aiEntry->getStringValue(); - SGPropertyNode_ptr scenarioTop = loadScenarioFile(filename); - if (scenarioTop) { - SGPropertyNode* scenarios = scenarioTop->getChild("scenario"); - if (scenarios) { - for (int i = 0; i < scenarios->nChildren(); i++) { - SGPropertyNode* scEntry = scenarios->getChild(i); - const std::string& type = scEntry->getStringValue("type"); - const std::string& pnumber = scEntry->getStringValue("pennant-number"); - const std::string& name = scEntry->getStringValue("name"); - if (type == "carrier" && (pnumber == id || name == id)) { - SGSharedPtr carrier = new FGAICarrier; - carrier->readFromScenario(scEntry); - - if (carrier->getParkPosition(pid, geodPos, hdng, uvw)) { - found = true; - break; - } - } - } - } - } - } - } - return found; -} - const FGAIBase * FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range) { diff --git a/src/AIModel/AIManager.hxx b/src/AIModel/AIManager.hxx index 91fe06f84..df2923a2a 100644 --- a/src/AIModel/AIManager.hxx +++ b/src/AIModel/AIManager.hxx @@ -62,12 +62,9 @@ public: inline double get_user_agl() const { return user_altitude_agl; } bool loadScenario( const std::string &filename ); - + static SGPropertyNode_ptr loadScenarioFile(const std::string& filename); - static bool getStartPosition(const std::string& id, const std::string& pid, - SGGeod& geodPos, double& hdng, SGVec3d& uvw); - FGAIBasePtr addObject(const SGPropertyNode* definition); bool isVisible(const SGGeod& pos) const; diff --git a/src/FDM/fdm_shell.cxx b/src/FDM/fdm_shell.cxx index 75e2b3a86..b164e71db 100644 --- a/src/FDM/fdm_shell.cxx +++ b/src/FDM/fdm_shell.cxx @@ -179,7 +179,8 @@ void FDMShell::update(double dt) double range = 1000.0; // in meters SGGeod geod = SGGeod::fromDeg(lon, lat); - if (globals->get_scenery()->scenery_available(geod, range)) { + const auto startUpPositionFialized = fgGetBool("/sim/position-finalized", false); + if (startUpPositionFialized && globals->get_scenery()->scenery_available(geod, range)) { SG_LOG(SG_FLIGHT, SG_INFO, "Scenery loaded, will init FDM"); _impl->init(); if (_impl->get_bound()) { diff --git a/src/Main/positioninit.cxx b/src/Main/positioninit.cxx index 0df06d8e7..0f34a50c9 100644 --- a/src/Main/positioninit.cxx +++ b/src/Main/positioninit.cxx @@ -23,11 +23,15 @@ #endif #include +#include +#include // simgear #include #include #include +#include +#include #include "globals.hxx" #include "fg_props.hxx" @@ -38,14 +42,25 @@ #include #include #include -#include +#include +#include +#include +#include using std::endl; using std::string; namespace flightgear { + + + enum InitPosResult { + ExactPosition, + VicinityPosition, + ContinueWaiting, + Failure + }; /// to avoid blocking when metar-fetch is enabled, but the network is /// unresponsive, we need a timeout value. This value is reset on initPosition, @@ -446,53 +461,95 @@ static bool fgSetPosFromNAV( const string& id, return true; } +static InitPosResult setInitialPosFromCarrier( const string& carrier ) +{ +#if !defined(FG_TESTLIB) + const auto initialPos = FGAICarrier::initialPositionForCarrier(carrier); + if (initialPos.first) { + // set these so scenery system has a vicinity to work with, and + // so our PagedLOD is loaded + fgSetDouble("/sim/presets/longitude-deg", initialPos.second.getLongitudeDeg()); + fgSetDouble("/sim/presets/latitude-deg", initialPos.second.getLatitudeDeg()); + SG_LOG( SG_GENERAL, SG_INFO, "Initial carrier pos = " << initialPos.second ); + return VicinityPosition; + } + + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " << carrier ); +#endif + return Failure; +} + // Set current_options lon/lat given an aircraft carrier id -static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) +static InitPosResult setFinalPosFromCarrier( const string& carrier, const string& posid ) { -#ifndef FG_TESTLIB +#if !defined(FG_TESTLIB) + SGSharedPtr carrierRef = FGAICarrier::findCarrierByNameOrPennant(carrier); + if (!carrierRef) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " + << carrier ); + return Failure; + } + + SGVec3d cartPos = carrierRef->getCartPos(); + auto framestamp = globals->get_renderer()->getViewer()->getFrameStamp(); + simgear::CheckSceneryVisitor csnv(globals->get_scenery()->getPager(), + toOsg(cartPos), + 100.0 /* range in metres */, + framestamp); - // set initial position from runway and heading - SGGeod geodPos; - double heading; - SGVec3d uvw; + // currently the PagedLODs will not be loaded by the DatabasePager + // while the splashscreen is there, so CheckSceneryVisitor force-loads + // missing objects in the main thread + carrierRef->getSceneBranch()->accept(csnv); + if (!csnv.isLoaded()) { + return ContinueWaiting; + } + + // and then wait for the load to actually be synced to the main thread + if (carrierRef->getSceneBranch()->getNumChildren() < 1) { + return ContinueWaiting; + } + + SGGeod geodPos; + double heading; + SGVec3d uvw; + if (carrierRef->getParkPosition(posid, geodPos, heading, uvw)) { + + //////// + double lon = geodPos.getLongitudeDeg(); + double lat = geodPos.getLatitudeDeg(); + double alt = geodPos.getElevationFt() + 2.0; + + SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " + << carrier << " at lat = " << lat << ", lon = " << lon + << ", alt = " << alt << ", heading = " << heading); + + fgSetDouble("/sim/presets/longitude-deg", lon); + fgSetDouble("/sim/presets/latitude-deg", lat); + fgSetDouble("/sim/presets/altitude-ft", alt); + fgSetDouble("/sim/presets/heading-deg", heading); + fgSetDouble("/position/longitude-deg", lon); + fgSetDouble("/position/latitude-deg", lat); + fgSetDouble("/position/altitude-ft", alt); + fgSetDouble("/orientation/heading-deg", heading); + + fgSetString("/sim/presets/speed-set", "UVW"); + fgSetDouble("/velocities/uBody-fps", uvw(0)); + fgSetDouble("/velocities/vBody-fps", uvw(1)); + fgSetDouble("/velocities/wBody-fps", uvw(2)); + fgSetDouble("/sim/presets/uBody-fps", uvw(0)); + fgSetDouble("/sim/presets/vBody-fps", uvw(1)); + fgSetDouble("/sim/presets/wBody-fps", uvw(2)); + + fgSetBool("/sim/presets/onground", true); - if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) { - double lon = geodPos.getLongitudeDeg(); - double lat = geodPos.getLatitudeDeg(); - double alt = geodPos.getElevationFt(); - - SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " - << carrier << " at lat = " << lat << ", lon = " << lon - << ", alt = " << alt << ", heading = " << heading); - - fgSetDouble("/sim/presets/longitude-deg", lon); - fgSetDouble("/sim/presets/latitude-deg", lat); - fgSetDouble("/sim/presets/altitude-ft", alt); - fgSetDouble("/sim/presets/heading-deg", heading); - fgSetDouble("/position/longitude-deg", lon); - fgSetDouble("/position/latitude-deg", lat); - fgSetDouble("/position/altitude-ft", alt); - fgSetDouble("/orientation/heading-deg", heading); - - fgSetString("/sim/presets/speed-set", "UVW"); - fgSetDouble("/velocities/uBody-fps", uvw(0)); - fgSetDouble("/velocities/vBody-fps", uvw(1)); - fgSetDouble("/velocities/wBody-fps", uvw(2)); - fgSetDouble("/sim/presets/uBody-fps", uvw(0)); - fgSetDouble("/sim/presets/vBody-fps", uvw(1)); - fgSetDouble("/sim/presets/wBody-fps", uvw(2)); - - fgSetBool("/sim/presets/onground", true); - - return true; - } else + ///////// + return ExactPosition; + } #endif - { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " - << carrier ); - return false; - } + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " << carrier ); + return Failure; } // Set current_options lon/lat given a fix ident and GUID @@ -588,6 +645,15 @@ bool initPosition() if (hdg > 9990.0) hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270); + if ( !set_pos && !carrier.empty() ) { + // an aircraft carrier is requested + const auto result = setInitialPosFromCarrier( carrier ); + if (result != Failure) { + // we at least found the carrier + set_pos = true; + } + } + if (apt_req && !rwy_req) { // ensure that if the users asks for a specific airport, but not a runway, // presumably because they want automatic selection, we do not look @@ -648,13 +714,6 @@ bool initPosition() } } - if ( !set_pos && !carrier.empty() ) { - // an aircraft carrier is requested - if ( fgSetPosFromCarrier( carrier, parkpos ) ) { - set_pos = true; - } - } - if ( !set_pos && !fix.empty() ) { // a Fix is requested if ( fgSetPosFromFix( fix, navaidId ) ) { @@ -766,11 +825,20 @@ void finalizePosition() 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); - initPosition(); + const auto res = setFinalPosFromCarrier(carrier, parkpos); + if (res == ExactPosition) { + done = true; + } else if (res == Failure) { + SG_LOG(SG_GENERAL, SG_ALERT, "secondary carrier init failed"); + done = true; + } else { + done = false; + // 60 second timeout on waiting for the carrier to load + if (global_finalizeTime.elapsedMSec() > 60000) { + done = true; + } + } + } else if (!apt.empty() && !parkpos.empty()) { // parking position depends on ATC / dynamics code to assign spaces, // so we wait until this point to initialise