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:
parent
91d3229514
commit
bf2c363e50
8 changed files with 196 additions and 99 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue