From b8d173c3e4b299c90ae7d3dcd581c81a9a2bbba8 Mon Sep 17 00:00:00 2001 From: portree_kid Date: Sun, 20 Nov 2022 21:55:25 +0100 Subject: [PATCH] #2358 AI Aircraft not taking off --- src/AIModel/AIAircraft.cxx | 64 ++++++++++++++++++++++++------- src/AIModel/AIAircraft.hxx | 27 +++++++++---- src/AIModel/AIManager.cxx | 35 +++++++++-------- src/ATC/ATCController.hxx | 29 ++++++++++++++ src/ATC/GroundController.cxx | 18 ++++----- src/ATC/TowerController.cxx | 12 +++--- src/ATC/atc_mgr.cxx | 73 +++++++++++++++++++++++++++++------- src/ATC/atc_mgr.hxx | 6 +-- src/ATC/trafficcontrol.cxx | 5 +-- 9 files changed, 195 insertions(+), 74 deletions(-) diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index 932aa0acc..5f6009ca4 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -102,7 +102,7 @@ FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI A _performance = PerformanceData::getDefaultData(); } - takeOffStatus = 0; + takeOffStatus = AITakeOffStatus::NONE; timeElapsed = 0; trackCache.remainingLength = 0; @@ -195,7 +195,7 @@ void FGAIAircraft::setPerformance(const std::string& acType, const std::string& } } - void FGAIAircraft::Run(double dt) +void FGAIAircraft::Run(double dt) { // We currently have one situation in which an AIAircraft object is used that is not attached to the // AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world. @@ -213,23 +213,25 @@ void FGAIAircraft::setPerformance(const std::string& acType, const std::string& if (outOfSight) { return; } + } else { + updateUserFlightPlan(dt); } - if (!flightplanActive) { + if (!flightplanActive) { groundTargetSpeed = 0; - } + } - handleATCRequests(dt); // ATC also has a word to say - updateSecondaryTargetValues(dt); // target roll, vertical speed, pitch - updateActualState(dt); + handleATCRequests(dt); // ATC also has a word to say + updateSecondaryTargetValues(dt); // target roll, vertical speed, pitch + updateActualState(dt); - updateModelProperties(dt); + updateModelProperties(dt); - if (!isUserAircraft) { - UpdateRadar(manager); - invisible = !manager->isVisible(pos); - } + if (!isUserAircraft) { + UpdateRadar(manager); + invisible = !manager->isVisible(pos); + } } @@ -1047,7 +1049,7 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) { scheduleForATCTowerDepartureControl(1); } if (prev->contains(string("Accel"))) { - takeOffStatus = 3; + takeOffStatus = AITakeOffStatus::CLEARED_FOR_TAKEOFF; } // This is the last taxi waypoint, and marks the the end of the flight plan @@ -1405,6 +1407,42 @@ void FGAIAircraft::handleATCRequests(double dt) } } +void FGAIAircraft::updateUserFlightPlan(double dt) +{ + // If the aircraft leaves the airport proximity increase the flightplan leg to sign off + // from the tower controller and free the runway #2358 The user doesn't + // need to fly out straight + if (fp) { + switch (fp->getLeg()) + { + case AILeg::TAKEOFF: + { + auto current = fp->getCurrentWaypoint(); + auto last = fp->getLastWaypoint(); + int legDistance = SGGeodesy::distanceM(current->getPos(), last->getPos()); + int currDist = SGGeodesy::distanceM(getGeodPos(), current->getPos()); + int lastDist = SGGeodesy::distanceM(getGeodPos(), last->getPos()); + SG_LOG(SG_ATC, SG_BULK, "Signing off from Tower " + << "\t currDist\t" << currDist + << "\t legDistance\t" << legDistance + << "\t" << lastDist + << "\t" << getGeodPos().getLatitudeDeg() + << "\t" << getGeodPos().getLongitudeDeg() + << "\t" << current->getPos().getLatitudeDeg() + << "\t" << current->getPos().getLongitudeDeg()); + if ( currDist>legDistance ) { + // We are definetly beyond the airport + fp->incrementLeg(); + } + } + break; + default: + break; + } + //TODO + } +} + void FGAIAircraft::updateActualState(double dt) { //update current state diff --git a/src/AIModel/AIAircraft.hxx b/src/AIModel/AIAircraft.hxx index 0e6fe5d9e..0393bef2d 100644 --- a/src/AIModel/AIAircraft.hxx +++ b/src/AIModel/AIAircraft.hxx @@ -50,6 +50,17 @@ namespace AILeg }; } +// 1 = joined departure queue; 2 = Passed DepartureHold waypoint; handover control to tower; 0 = any other state. +namespace AITakeOffStatus +{ + enum Type + { + NONE = 0, + QUEUED = 1, // joined departure queue + CLEARED_FOR_TAKEOFF = 2 // Passed DepartureHold waypoint; handover control to tower; + }; +} + class FGAIAircraft : public FGAIBaseAircraft { public: @@ -86,7 +97,7 @@ public: void ClimbTo(double altitude); void TurnTo(double heading); - + void getGroundElev(double dt); //TODO these 3 really need to be public? void doGroundAltitude(); bool loadNextLeg (double dist=0); @@ -106,7 +117,7 @@ public: bool getTaxiClearanceRequest() { return needsTaxiClearance; }; FGAISchedule * getTrafficRef() { return trafficRef; }; void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; }; - void resetTakeOffStatus() { takeOffStatus = 0;}; + void resetTakeOffStatus() { takeOffStatus = AITakeOffStatus::NONE;}; void setTakeOffStatus(int status) { takeOffStatus = status; }; int getTakeOffStatus() { return takeOffStatus; }; void setTakeOffSlot(time_t timeSlot) { takeOffTimeSlot = timeSlot;}; @@ -133,7 +144,7 @@ public: double calcVerticalSpeed(double vert_ft, double dist_m, double speed, double error); FGATCController * getATCController() { return controller; }; - + void clearATCController(); bool isBlockedBy(FGAIAircraft* other); void dumpCSVHeader(std::unique_ptr &o); @@ -164,7 +175,7 @@ private: SGPropertyNode_ptr refuel_node; SGPropertyNode_ptr tcasThreatNode; SGPropertyNode_ptr tcasRANode; - + // helpers for Run //TODO sort out which ones are better protected virtuals to allow //subclasses to override specific behaviour @@ -177,7 +188,7 @@ private: void controlHeading(FGAIWaypoint* curr, FGAIWaypoint* next); void controlSpeed(FGAIWaypoint* curr, FGAIWaypoint* next); - + void updatePrimaryTargetValues(double dt, bool& flightplanActive, bool& aiOutOfSight); void updateSecondaryTargetValues(double dt); void updateHeading(double dt); @@ -186,13 +197,15 @@ private: void updatePitchAngleTarget(); void updateActualState(double dt); void updateModelProperties(double dt); + /**Handle special cases for the User AI shadow*/ + void updateUserFlightPlan(double dt); void handleATCRequests(double dt); inline bool isStationary() { return ((fabs(speed) <= 0.0001) && (fabs(tgt_speed) <= 0.0001)); } - + inline bool needGroundElevation() { if (!isStationary()) _needsGroundElevation = true; @@ -218,7 +231,7 @@ private: int stuckCounter = 0; bool tracked = false; /** - * Signals a reset to leg 1 at a different airport. + * Signals a reset to leg 1 at a different airport. * The leg loading happens at a different place than the parking loading. * */ bool repositioned = false; diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 9bb14c7cb..94dc3fbeb 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -150,7 +150,7 @@ FGAIManager::init() { globals->get_commands()->addCommand("remove-aiobject", this, &FGAIManager::removeObjectCommand); _environmentVisiblity = fgGetNode("/environment/visibility-m"); _groundSpeedKts_node = fgGetNode("/velocities/groundspeed-kt", true); - + // Create an (invisible) AIAircraft representation of the current // users's aircraft, that mimicks the user aircraft's behavior. @@ -160,7 +160,7 @@ FGAIManager::init() { _userAircraft->setPerformance("", "jet_transport"); _userAircraft->setHeading(fgGetDouble("/orientation/heading-deg")); _userAircraft->setSpeed(_groundSpeedKts_node->getDoubleValue()); - + // radar properties _simRadarControl = fgGetNode("/sim/controls/radar", true); if (!_simRadarControl->hasValue()) { @@ -187,13 +187,13 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root) static_haveRegisteredScenarios = true; root = globals->get_props(); } - + // find all scenarios at standard locations (for driving the GUI) std::vector scenarioSearchPaths; scenarioSearchPaths.push_back(globals->get_fg_root() / "AI"); scenarioSearchPaths.push_back(globals->get_fg_home() / "Scenarios"); scenarioSearchPaths.push_back(SGPath(fgGetString("/sim/aircraft-dir")) / "Scenarios"); - + // add-on scenario directories const auto& addonsManager = flightgear::addons::AddonManager::instance(); if (addonsManager) { @@ -213,7 +213,7 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root) for (auto p : scenarioSearchPaths) { if (!p.exists()) continue; - + simgear::Dir dir(p); for (auto xmlPath : dir.children(simgear::Dir::TYPE_FILE, ".xml")) { registerScenarioFile(root, xmlPath); @@ -224,7 +224,7 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root) SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, const SGPath& xmlPath) { if (!xmlPath.exists()) return {}; - + auto scenariosNode = root->getNode("/sim/ai/scenarios", true); SGPropertyNode_ptr sNode; @@ -233,18 +233,18 @@ SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, co try { SGPropertyNode_ptr scenarioProps(new SGPropertyNode); readProperties(xmlPath, scenarioProps); - + for (auto xs : scenarioProps->getChildren("scenario")) { if (!xs->hasChild("name") || !xs->hasChild("description")) { SG_LOG(SG_AI, SG_DEV_WARN, "Scenario is missing name/description:" << xmlPath); } - + sNode = scenariosNode->addChild("scenario"); - + const auto bareName = xmlPath.file_base(); sNode->setStringValue("id", bareName); sNode->setStringValue("path", xmlPath.utf8Str()); - + if (xs->hasChild("name")) { sNode->setStringValue("name", xs->getStringValue("name")); } else { @@ -253,11 +253,11 @@ SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, co // auto s = simgear::strutils::srep sNode->setStringValue("name", cleanedName); } - + if (xs->hasChild("description")) { sNode->setStringValue("description", xs->getStringValue("description")); } - + FGAICarrier::extractCarriersFromScenario(xs, sNode); } // of scenarios in the XML file } catch (sg_exception& e) { @@ -332,7 +332,7 @@ FGAIManager::shutdown() } static_haveRegisteredScenarios = false; - + globals->get_commands()->removeCommand("load-scenario"); globals->get_commands()->removeCommand("unload-scenario"); globals->get_commands()->removeCommand("add-aiobject"); @@ -377,12 +377,12 @@ FGAIManager::update(double dt) return; fetchUserState(dt); - + // fetch radar state. Ensure we only do this once per frame. _radarEnabled = _simRadarControl->getBoolValue(); _radarDebugMode = _radarDebugNode->getBoolValue(); _radarRangeM = _radarRangeNode->getDoubleValue() * SG_NM_TO_METER; - + // partition the list into dead followed by alive auto firstAlive = std::stable_partition(ai_list.begin(), ai_list.end(), std::mem_fn(&FGAIBase::getDie)); @@ -467,7 +467,6 @@ FGAIManager::getNumAiObjects() const void FGAIManager::fetchUserState( double dt ) { - globals->get_aircraft_orientation(user_heading, user_pitch, user_roll); user_speed = user_speed_node->getDoubleValue() * 0.592484; wind_from_east = wind_from_east_node->getDoubleValue(); @@ -540,7 +539,7 @@ bool FGAIManager::addObjectCommand(const SGPropertyNode* arg, const SGPropertyNo FGAIBasePtr FGAIManager::addObject(const SGPropertyNode* definition) { const std::string& type = definition->getStringValue("type", "aircraft"); - + FGAIBase* ai = nullptr; if (type == "tanker") { // refueling scenarios ai = new FGAITanker; @@ -702,7 +701,7 @@ FGAIManager::loadScenarioFile(const std::string& scenarioName, SGPath& outPath) } } } - + return {}; } diff --git a/src/ATC/ATCController.hxx b/src/ATC/ATCController.hxx index 7ce8c20e1..036d32043 100644 --- a/src/ATC/ATCController.hxx +++ b/src/ATC/ATCController.hxx @@ -35,6 +35,35 @@ #include +namespace ATCMessageState +{ + enum Type + { +// 0 = Normal; no action required +NORMAL = 0, +// 1 = "Acknowledge "Hold position +ACK_HOLD = 1, +// 2 = "Acknowledge "Resume taxi". +ACK_RESUME_TAXI = 2, +// 3 = "Issue TaxiClearance" +TAXI_CLEARED = 3, +// 4 = Acknowledge Taxi Clearance" +ACK_TAXI_CLEARED = 4, +// 5 = Post acknowlegde taxiclearance: Start taxiing +START_TAXI = 5, +// 6 = Report runway +REPORT_RUNWAY = 6, +// 7 = Acknowledge report runway +ACK_REPORT_RUNWAY = 7, +// 8 = Switch tower frequency +SWITCH_TOWER = 8, +// 9 = Acknowledge switch tower frequency +ACK_SWITCH_TOWER = 9, +// 10 = Cleared for takeoff +CLEARED_TAKEOFF = 10, + }; +} + /** * class FGATCController * NOTE: this class serves as an abstraction layer for all sorts of ATC controllers. diff --git a/src/ATC/GroundController.cxx b/src/ATC/GroundController.cxx index 5b77efbac..c2ab6021f 100644 --- a/src/ATC/GroundController.cxx +++ b/src/ATC/GroundController.cxx @@ -222,16 +222,16 @@ void FGGroundController::updateAircraftInformation(int id, SGGeod geod, available = true; } if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { - current->setState(3); + current->setState(ATCMessageState::TAXI_CLEARED); } if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) { - current->setState(4); + current->setState(ATCMessageState::ACK_TAXI_CLEARED); } if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { - current->setState(5); + current->setState(ATCMessageState::START_TAXI); } if ((state == 5) && available) { - current->setState(0); + current->setState(ATCMessageState::NORMAL); current->getAircraft()->setTaxiClearanceRequest(false); current->setHoldPosition(false); available = false; @@ -491,11 +491,11 @@ void FGGroundController::checkHoldPosition(int id, double lat, if (currStatus == true) { // No has a hold short instruction transmit(&(*current), parent, MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true); SG_LOG(SG_ATC, SG_DEBUG, "Transmitting hold short instruction " << currStatus << " " << available); - current->setState(1); + current->setState(ATCMessageState::ACK_HOLD); } else { transmit(&(*current), parent, MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true); SG_LOG(SG_ATC, SG_DEBUG, "Transmitting resume instruction " << currStatus << " " << available); - current->setState(2); + current->setState(ATCMessageState::ACK_RESUME_TAXI); } lastTransmission = now; available = false; @@ -512,16 +512,16 @@ void FGGroundController::checkHoldPosition(int id, double lat, //int state = current->getState(); if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) { - current->setState(0); + current->setState(ATCMessageState::NORMAL); current->setHoldPosition(true); } if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) { - current->setState(0); + current->setState(ATCMessageState::NORMAL); current->setHoldPosition(false); } if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) { SG_LOG(SG_ATC, SG_DEBUG, "Scheduling " << current->getAircraft()->getCallSign() << " for hold short"); - current->setState(6); + current->setState(ATCMessageState::REPORT_RUNWAY); } if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) { } diff --git a/src/ATC/TowerController.cxx b/src/ATC/TowerController.cxx index 2a78a4db2..487957c42 100644 --- a/src/ATC/TowerController.cxx +++ b/src/ATC/TowerController.cxx @@ -181,15 +181,15 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod, // only bother with aircraft that have a takeoff status of 2, since those are essentially under tower control auto ac = rwy->getFirstAircraftInDepartureQueue(); if (ac) { - if (ac->getTakeOffStatus() == 1) { + if (ac->getTakeOffStatus() == AITakeOffStatus::QUEUED) { // transmit takeoff clearance - ac->setTakeOffStatus(2); + ac->setTakeOffStatus(AITakeOffStatus::CLEARED_FOR_TAKEOFF); transmit(&(*i), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true); - i->setState(10); + i->setState(ATCMessageState::CLEARED_TAKEOFF); } } //FIXME Make it an member of traffic record - if (current.getAircraft()->getTakeOffStatus() == 2) { + if (current.getAircraft()->getTakeOffStatus() == AITakeOffStatus::CLEARED_FOR_TAKEOFF) { current.setHoldPosition(false); } else { current.setHoldPosition(true); @@ -200,7 +200,7 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod, SG_LOG(SG_ATC, SG_BULK, "Unset Hold " << clearanceId << " for " << rwy->getRunwayName()); current.setHoldPosition(false); } else { - SG_LOG(SG_ATC, SG_WARN, "Not cleared " << id << " " << clearanceId); + SG_LOG(SG_ATC, SG_WARN, "Not cleared " << id << " Currently cleared " << clearanceId); } } else { if (current.getAircraft() == rwy->getFirstAircraftInDepartureQueue()) { @@ -209,7 +209,7 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod, rwy->setCleared(id); auto ac = rwy->getFirstOfStatus(1); if (ac) { - ac->setTakeOffStatus(2); + ac->setTakeOffStatus(AITakeOffStatus::QUEUED); // transmit takeoff clearacne? But why twice? } } else { diff --git a/src/ATC/atc_mgr.cxx b/src/ATC/atc_mgr.cxx index 208e7edd9..283306d0b 100644 --- a/src/ATC/atc_mgr.cxx +++ b/src/ATC/atc_mgr.cxx @@ -154,7 +154,7 @@ void FGATCManager::postinit() SG_LOG(SG_ATC, SG_DEBUG, "Setting radio frequency to : " << stationFreq); fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0)); } - leg = 1; + leg = AILeg::STARTUP_PUSHBACK; //double, lat, lon, head; // Unused variables; //int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head); aircraftRadius = pk.parking()->getRadius(); @@ -186,11 +186,11 @@ void FGATCManager::postinit() fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0)); } fp.reset(new FGAIFlightPlan); - leg = 3; + leg = AILeg::TAKEOFF; string fltType = "ga"; fp->setRunway(runway); - fp->createTakeOff(userAircraft, false, dcs->parent(), {}, 0, fltType); - userAircraft->setTakeOffStatus(2); + fp->createTakeOff(userAircraft, false, dcs->parent(), userAircraft->getGeodPos(), 0, fltType); + userAircraft->setTakeOffStatus(AITakeOffStatus::QUEUED); } else { // We're on the ground somewhere. Handle this case later. @@ -210,7 +210,7 @@ void FGATCManager::postinit() fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend")); } } else { - controller = 0; + controller = nullptr; } // Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to @@ -347,20 +347,21 @@ void FGATCManager::update ( double time ) { #endif } if (fp) { - SG_LOG(SG_ATC, SG_DEBUG, "User aircraft currently at leg : " << fp->getLeg()); + SG_LOG(SG_ATC, SG_BULK, "User aircraft currently at leg : " << fp->getLeg()); } // Call getATCController method; returns what FGATCController presently controls the user aircraft // - e.g. FGStartupController - controller = user_ai_ac->getATCController(); + // controller = user_ai_ac->getATCController(); + // FIXME the AIAircraft currently doesn't set this for the user aircraft // Update the ATC dialog //FGATCDialogNew::instance()->update(time); // Controller manager - if controller is set, then will update controller if (controller) { - SG_LOG(SG_ATC, SG_DEBUG, "name of previous waypoint : " << fp->getPreviousWaypoint()->getName()); - SG_LOG(SG_ATC, SG_DEBUG, "Currently under control of " << controller->getName()); +// SG_LOG(SG_ATC, SG_DEBUG, "name of previous waypoint : " << fp->getPreviousWaypoint()->getName()); + SG_LOG(SG_ATC, SG_BULK, "Currently under control of " << controller->getName()); // update aircraft information (simulates transponder) @@ -370,6 +371,49 @@ void FGATCManager::update ( double time ) { user_ai_ac->getSpeed(), user_ai_ac->getAltitude(), time); + if (fp) { + switch (fp->getLeg()) { + case AILeg::STARTUP_PUSHBACK: // Startup and Push back + if (userAircraftTrafficRef->getDepartureAirport()->getDynamics()) + controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getStartupController(); + break; + case AILeg::TAXI: // Taxiing to runway + if (userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getGroundController()->exists()) + controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getGroundController(); + break; + case AILeg::TAKEOFF: //Take off tower controller + if (userAircraftTrafficRef->getDepartureAirport()->getDynamics()) { + controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getTowerController(); + } else { + SG_LOG(SG_AI, SG_BULK, "Error: Could not find Dynamics at airport : " << userAircraftTrafficRef->getDepartureAirport()->getId()); + } + break; + /* TODO link up with state system? + case AILeg::APPROACH: + if (userAircraftTrafficRef->getArrivalAirport()->getDynamics()) { + controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController(); + } + break; + case AILeg::PARKING_TAXI: // Taxiing for parking + if (trafficRef->getArrivalAirport()->getDynamics()->getGroundController()->exists()) + controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundController(); + break; + */ + default: + if(prevController) { + SG_LOG(SG_AI, SG_BULK, "Will be signing off user ai " << user_ai_ac->getID() << " from " << prevController->getName()); + } + controller = nullptr; + break; + } + + if ((controller != prevController) && prevController && !user_ai_ac->getDie()) { + //If we are dead we are automatically erased + prevController->signOff(user_ai_ac->getID()); + } + prevController = controller; + } + //string airport = fgGetString("/sim/presets/airport-id"); //FGAirport *apt = FGAirport::findByIdent(airport); // AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading. @@ -392,14 +436,15 @@ void FGATCManager::update ( double time ) { prevController->render(false); } - // render the path for the present controller if the ground network is set to visible - controller->render(networkVisible); - - SG_LOG(SG_ATC, SG_BULK, "Adding ground network to the scenegraph::update"); + if (controller) { + // render the path for the present controller if the ground network is set to visible + controller->render(networkVisible); + SG_LOG(SG_ATC, SG_BULK, "Adding ground network to the scenegraph::update"); + } // reset previous controller for next update() iteration prevController = controller; - } + } // update the active ATC stations for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); ++atc) { diff --git a/src/ATC/atc_mgr.hxx b/src/ATC/atc_mgr.hxx index 9e7a20dd0..8f41f8c3b 100644 --- a/src/ATC/atc_mgr.hxx +++ b/src/ATC/atc_mgr.hxx @@ -67,15 +67,13 @@ public: void postinit() override; void shutdown() override; void update(double time) override; - - - + // Subsystem identification. static const char* staticSubsystemClassId() { return "ATC"; } void addController(FGATCController *controller); void removeController(FGATCController* controller); - + void reposition(); }; diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index f379a277d..6531b4212 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -264,7 +264,7 @@ FGTrafficRecord::~FGTrafficRecord() void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan * route) { - SG_LOG(SG_ATC, SG_DEBUG, "Position: " << pos); + SG_LOG(SG_AI, SG_DEBUG, "Traffic record position: " << pos); currentPos = pos; if (!intentions.empty()) { intVecIterator i = intentions.begin(); @@ -276,8 +276,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos, } else { //FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint(); int size = route->getNrOfWayPoints(); - SG_LOG(SG_ATC, SG_DEBUG, "Setting pos" << currentPos); - SG_LOG(SG_ATC, SG_DEBUG, "Setting intentions"); + SG_LOG(SG_ATC, SG_DEBUG, "Setting pos to " << currentPos << " and intentions"); for (int i = 2; i < size; i++) { int val = route->getRouteIndex(i); intentions.push_back(val);