1
0
Fork 0

Fix carrier starts

Rewrite the position-init code for carrier starts, to precisely wait
on the carrier model being loaded, before proceeding with FDM init.
This allows the FDM to see the correct carrier model in the ground
cache, and hence avoids starting in the water.

To implement this, the CheckSceneryVisitor is used to force the carrier
model to be loaded while the splash-screen is visible.
This commit is contained in:
James Turner 2017-09-08 22:31:22 +01:00
parent 91d3229514
commit bf2c363e50
8 changed files with 196 additions and 99 deletions

View file

@ -939,3 +939,14 @@ bool FGAIBase::isValid() {
//Either no flightplan or it is valid //Either no flightplan or it is valid
return !fp || fp->isValidPlan(); return !fp || fp->isValidPlan();
} }
osg::PagedLOD* FGAIBase::getSceneBranch() const
{
return _model;
}
SGGeod FGAIBase::getGeodPos() const
{
return pos;
}

View file

@ -109,6 +109,8 @@ public:
bool getDie(); bool getDie();
bool isValid(); bool isValid();
SGGeod getGeodPos() const;
SGVec3d getCartPosAt(const SGVec3d& off) const; SGVec3d getCartPosAt(const SGVec3d& off) const;
SGVec3d getCartPos() const; SGVec3d getCartPos() const;
@ -121,6 +123,7 @@ public:
double _getCartPosY() const; double _getCartPosY() const;
double _getCartPosZ() const; double _getCartPosZ() const;
osg::PagedLOD* getSceneBranch() const;
protected: protected:
double _elevation_m; double _elevation_m;

View file

@ -590,3 +590,53 @@ void FGAICarrier::UpdateJBD(double dt, double jbd_transition_time) {
return; return;
} // end UpdateJBD } // end UpdateJBD
std::pair<bool, SGGeod> 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<FGAICarrier> 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> FGAICarrier::findCarrierByNameOrPennant(const std::string& namePennant)
{
const FGAIManager* aiManager = globals->get_subsystem<FGAIManager>();
if (!aiManager) {
return {};
}
for (const auto aiObject : aiManager->get_ai_list()) {
if (aiObject->isa(FGAIBase::otCarrier)) {
SGSharedPtr<FGAICarrier> c = static_cast<FGAICarrier*>(aiObject.get());
if ((c->sign == namePennant) || (c->_getName() == namePennant)) {
return c;
}
}
} // of all objects iteration
return {};
}

View file

@ -70,7 +70,13 @@ public:
bool getParkPosition(const string& id, SGGeod& geodPos, bool getParkPosition(const string& id, SGGeod& geodPos,
double& hdng, SGVec3d& uvw); double& hdng, SGVec3d& uvw);
/**
* @brief type-safe wrapper around AIManager::getObjectFromProperty
*/
static SGSharedPtr<FGAICarrier> findCarrierByNameOrPennant(const std::string& namePennant);
static std::pair<bool, SGGeod> initialPositionForCarrier(const std::string& namePennant);
private: private:
/// Is sufficient to be private, stores a possible position to place an /// Is sufficient to be private, stores a possible position to place an
/// aircraft on start /// aircraft on start

View file

@ -519,45 +519,6 @@ FGAIManager::loadScenarioFile(const std::string& filename)
return 0; 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<FGAICarrier> carrier = new FGAICarrier;
carrier->readFromScenario(scEntry);
if (carrier->getParkPosition(pid, geodPos, hdng, uvw)) {
found = true;
break;
}
}
}
}
}
}
}
return found;
}
const FGAIBase * const FGAIBase *
FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range) FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range)
{ {

View file

@ -62,12 +62,9 @@ public:
inline double get_user_agl() const { return user_altitude_agl; } inline double get_user_agl() const { return user_altitude_agl; }
bool loadScenario( const std::string &filename ); bool loadScenario( const std::string &filename );
static SGPropertyNode_ptr loadScenarioFile(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); FGAIBasePtr addObject(const SGPropertyNode* definition);
bool isVisible(const SGGeod& pos) const; bool isVisible(const SGGeod& pos) const;

View file

@ -179,7 +179,8 @@ void FDMShell::update(double dt)
double range = 1000.0; // in meters double range = 1000.0; // in meters
SGGeod geod = SGGeod::fromDeg(lon, lat); 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"); SG_LOG(SG_FLIGHT, SG_INFO, "Scenery loaded, will init FDM");
_impl->init(); _impl->init();
if (_impl->get_bound()) { if (_impl->get_bound()) {

View file

@ -23,11 +23,15 @@
#endif #endif
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <osgViewer/Viewer>
#include <osg/PagedLOD>
// simgear // simgear
#include <simgear/props/props_io.hxx> #include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/structure/event_mgr.hxx> #include <simgear/structure/event_mgr.hxx>
#include <simgear/scene/model/CheckSceneryVisitor.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include "globals.hxx" #include "globals.hxx"
#include "fg_props.hxx" #include "fg_props.hxx"
@ -38,14 +42,25 @@
#include <Airports/dynamics.hxx> #include <Airports/dynamics.hxx>
#include <Airports/groundnetwork.hxx> #include <Airports/groundnetwork.hxx>
#include <AIModel/AIManager.hxx> #include <AIModel/AIManager.hxx>
#include <GUI/MessageBox.hxx> #include <AIModel/AICarrier.hxx>
#include <Scenery/scenery.hxx>
#include <GUI/MessageBox.hxx>
#include <Viewer/renderer.hxx>
using std::endl; using std::endl;
using std::string; using std::string;
namespace flightgear namespace flightgear
{ {
enum InitPosResult {
ExactPosition,
VicinityPosition,
ContinueWaiting,
Failure
};
/// to avoid blocking when metar-fetch is enabled, but the network is /// to avoid blocking when metar-fetch is enabled, but the network is
/// unresponsive, we need a timeout value. This value is reset on initPosition, /// unresponsive, we need a timeout value. This value is reset on initPosition,
@ -446,53 +461,95 @@ static bool fgSetPosFromNAV( const string& id,
return true; 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 // 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<FGAICarrier> 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 // currently the PagedLODs will not be loaded by the DatabasePager
SGGeod geodPos; // while the splashscreen is there, so CheckSceneryVisitor force-loads
double heading; // missing objects in the main thread
SGVec3d uvw; 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(); return ExactPosition;
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
#endif #endif
{ SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " << carrier );
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " return Failure;
<< carrier );
return false;
}
} }
// Set current_options lon/lat given a fix ident and GUID // Set current_options lon/lat given a fix ident and GUID
@ -588,6 +645,15 @@ bool initPosition()
if (hdg > 9990.0) if (hdg > 9990.0)
hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270); 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) { if (apt_req && !rwy_req) {
// ensure that if the users asks for a specific airport, but not a runway, // ensure that if the users asks for a specific airport, but not a runway,
// presumably because they want automatic selection, we do not look // 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() ) { if ( !set_pos && !fix.empty() ) {
// a Fix is requested // a Fix is requested
if ( fgSetPosFromFix( fix, navaidId ) ) { if ( fgSetPosFromFix( fix, navaidId ) ) {
@ -766,11 +825,20 @@ void finalizePosition()
if (!carrier.empty()) if (!carrier.empty())
{ {
SG_LOG(SG_GENERAL, SG_INFO, "finalizePositioned: re-init-ing position on carrier"); const auto res = setFinalPosFromCarrier(carrier, parkpos);
// clear preset location and re-trigger position setup if (res == ExactPosition) {
fgSetDouble("/sim/presets/longitude-deg", 9999); done = true;
fgSetDouble("/sim/presets/latitude-deg", 9999); } else if (res == Failure) {
initPosition(); 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()) { } else if (!apt.empty() && !parkpos.empty()) {
// parking position depends on ATC / dynamics code to assign spaces, // parking position depends on ATC / dynamics code to assign spaces,
// so we wait until this point to initialise // so we wait until this point to initialise