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
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 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;

View file

@ -590,3 +590,53 @@ void FGAICarrier::UpdateJBD(double dt, double jbd_transition_time) {
return;
} // 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,
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:
/// Is sufficient to be private, stores a possible position to place an
/// aircraft on start

View file

@ -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<FGAICarrier> 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)
{

View file

@ -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;

View file

@ -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()) {

View file

@ -23,11 +23,15 @@
#endif
#include <boost/tuple/tuple.hpp>
#include <osgViewer/Viewer>
#include <osg/PagedLOD>
// simgear
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/scene/model/CheckSceneryVisitor.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include "globals.hxx"
#include "fg_props.hxx"
@ -38,14 +42,25 @@
#include <Airports/dynamics.hxx>
#include <Airports/groundnetwork.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::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<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
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