]> git.mxchange.org Git - flightgear.git/blobdiff - src/Traffic/TrafficMgr.cxx
Clean up namespace issues
[flightgear.git] / src / Traffic / TrafficMgr.cxx
index 0f9dbc0b3f2606a9b49a549b622441d1398d3ac5..ee8e9c64feaec3169fe0cf7c7e17e23c26511d46 100644 (file)
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/misc/sg_dir.hxx>
 #include <simgear/props/props.hxx>
-#include <simgear/route/waypoint.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/xml/easyxml.hxx>
+#include <simgear/threads/SGThread.hxx>
+#include <simgear/threads/SGGuard.hxx>
 
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
 #include <Airports/simple.hxx>
 #include <Main/fg_init.hxx>
 
-
-
 #include "TrafficMgr.hxx"
 
 using std::sort;
 using std::strcmp;
+using std::endl;
+
+/**
+ * Thread encapsulating parsing the traffic schedules. 
+ */
+class ScheduleParseThread : public SGThread
+{
+public:
+  ScheduleParseThread(FGTrafficManager* traffic) :
+    _trafficManager(traffic),
+    _isFinished(false),
+    _cancelThread(false)
+  {
+    
+  }
+  
+  // if we're destroyed while running, ensure the thread exits cleanly
+  ~ScheduleParseThread()
+  {
+    _lock.lock();
+    if (!_isFinished) {
+      _cancelThread = true; // request cancellation so we don't wait ages
+      _lock.unlock();
+      join();
+    } else {
+      _lock.unlock();
+    }
+  }
+  
+  void setTrafficDir(const SGPath& trafficDirPath)
+  {
+    _trafficDirPath = trafficDirPath;
+  }
+  
+  bool isFinished() const
+  {
+    SGGuard<SGMutex> g(_lock);
+    return _isFinished;
+  }
+  
+  virtual void run()
+  {
+    SGTimeStamp st;
+    st.stamp();
+    
+    simgear::Dir trafficDir(_trafficDirPath);
+    simgear::PathList d = trafficDir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
+    
+    BOOST_FOREACH(SGPath p, d) {
+      simgear::Dir d2(p);
+      simgear::PathList trafficFiles = d2.children(simgear::Dir::TYPE_FILE, ".xml");
+      BOOST_FOREACH(SGPath xml, trafficFiles) {
+        _trafficManager->parseSchedule(xml);
+        if (_cancelThread) {
+          return;
+        }
+      }
+    } // of sub-directories in AI/Traffic iteration
+    
+  //  _trafficManager->parseSchedules(schedulesToRead);
+    SG_LOG(SG_AI, SG_INFO, "parsing traffic schedules took:" << st.elapsedMSec() << "msec");
+    
+    SGGuard<SGMutex> g(_lock);
+    _isFinished = true;
+  }
+private:
+  FGTrafficManager* _trafficManager;
+  mutable SGMutex _lock;
+  bool _isFinished;
+  bool _cancelThread;
+  SGPath _trafficDirPath;
+};
 
 /******************************************************************************
  * TrafficManager
@@ -79,6 +150,7 @@ using std::strcmp;
 FGTrafficManager::FGTrafficManager() :
   inited(false),
   doingInit(false),
+  waitingMetarTime(0.0),
   enabled("/sim/traffic-manager/enabled"),
   aiEnabled("/sim/ai/enabled"),
   realWxEnabled("/environment/realwx/enabled"),
@@ -96,11 +168,20 @@ FGTrafficManager::~FGTrafficManager()
 
 void FGTrafficManager::shutdown()
 {
+    if (!inited) {
+      if (doingInit) {
+        scheduleParser.reset();
+        doingInit = false;
+      }
+      
+      return;
+    }
+  
     // Save the heuristics data
     bool saveData = false;
-    ofstream cachefile;
+    std::ofstream cachefile;
     if (fgGetBool("/sim/traffic-manager/heuristics")) {
-        SGPath cacheData(fgGetString("/sim/fg-home"));
+        SGPath cacheData(globals->get_fg_home());
         cacheData.append("ai");
         string airport = fgGetString("/sim/presets/airport-id");
 
@@ -119,28 +200,34 @@ void FGTrafficManager::shutdown()
             cachefile << "[TrafficManagerCachedata:ref:2011:09:04]" << endl;
         }
     }
-    for (ScheduleVectorIterator sched = scheduledAircraft.begin();
-         sched != scheduledAircraft.end(); sched++) {
+  
+    BOOST_FOREACH(FGAISchedule* acft, scheduledAircraft) {
         if (saveData) {
-            cachefile << (*sched)->getRegistration() << " "
-                << (*sched)->getRunCount() << " "
-                << (*sched)->getHits() << " "
-                << (*sched)->getLastUsed() << endl;
+            cachefile << acft->getRegistration() << " "
+                << acft->getRunCount() << " "
+                << acft->getHits() << " "
+                << acft->getLastUsed() << endl;
         }
-        delete(*sched);
+        delete acft;
     }
     if (saveData) {
         cachefile.close();
     }
     scheduledAircraft.clear();
     flights.clear();
-    releaseList.clear();
 
     currAircraft = scheduledAircraft.begin();
     doingInit = false;
     inited = false;
 }
 
+/// caution - this is run on the helper thread to improve startup
+/// responsiveness - do not access properties or global state from
+/// here, since there's no locking protection at all
+void FGTrafficManager::parseSchedule(const SGPath& path)
+{
+  readXML(path.str(), *this);
+}
 
 void FGTrafficManager::init()
 {
@@ -151,14 +238,9 @@ void FGTrafficManager::init()
     assert(!doingInit);
     doingInit = true;
     if (string(fgGetString("/sim/traffic-manager/datafile")) == string("")) {
-        simgear::Dir trafficDir(SGPath(globals->get_fg_root(), "AI/Traffic"));
-        simgear::PathList d = trafficDir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
-        
-        BOOST_FOREACH(SGPath p, d) {
-          simgear::Dir d2(p);
-          simgear::PathList trafficFiles = d2.children(simgear::Dir::TYPE_FILE, ".xml");
-          schedulesToRead.insert(schedulesToRead.end(), trafficFiles.begin(), trafficFiles.end());
-        }
+        scheduleParser.reset(new ScheduleParseThread(this));
+        scheduleParser->setTrafficDir(SGPath(globals->get_fg_root(), "AI/Traffic"));      
+        scheduleParser->start();
     } else {
         fgSetBool("/sim/traffic-manager/heuristics", false);
         SGPath path = string(fgGetString("/sim/traffic-manager/datafile"));
@@ -180,19 +262,7 @@ void FGTrafficManager::init()
     }
 }
 
-void FGTrafficManager::initStep()
-{
-    assert(doingInit);
-    if (schedulesToRead.empty()) {
-        finishInit();
-        return;
-    }
-    
-    SGPath path = schedulesToRead.front();
-    schedulesToRead.erase(schedulesToRead.begin());
-    SG_LOG(SG_AI, SG_DEBUG, path << " for traffic");
-    readXML(path.str(), *this);
-}
+
 
 void FGTrafficManager::finishInit()
 {
@@ -200,10 +270,9 @@ void FGTrafficManager::finishInit()
     SG_LOG(SG_AI, SG_INFO, "finishing AI-Traffic init");
     loadHeuristics();
     
-    // Do sorting and scoring separately, to take advantage of the "homeport| variable
-    for (currAircraft = scheduledAircraft.begin();
-         currAircraft != scheduledAircraft.end(); currAircraft++) {
-        (*currAircraft)->setScore();
+    // Do sorting and scoring separately, to take advantage of the "homeport" variable
+    BOOST_FOREACH(FGAISchedule* schedule, scheduledAircraft) {
+        schedule->setScore();
     }
     
     sort(scheduledAircraft.begin(), scheduledAircraft.end(),
@@ -224,7 +293,7 @@ void FGTrafficManager::loadHeuristics()
     HeuristicMap heurMap;
     //cerr << "Processing Heuristics" << endl;
     // Load the heuristics data
-    SGPath cacheData(fgGetString("/sim/fg-home"));
+    SGPath cacheData(globals->get_fg_home());
     cacheData.append("ai");
     string airport = fgGetString("/sim/presets/airport-id");
     if ((airport) != "") {
@@ -235,7 +304,7 @@ void FGTrafficManager::loadHeuristics()
       cacheData.append(airport + "-cache.txt");
       string revisionStr;
       if (cacheData.exists()) {
-        ifstream data(cacheData.c_str());
+        std::ifstream data(cacheData.c_str());
         data >> revisionStr;
         if (revisionStr != "[TrafficManagerCachedata:ref:2011:09:04]") {
           SG_LOG(SG_GENERAL, SG_ALERT,"Traffic Manager Warning: discarding outdated cachefile " << 
@@ -269,7 +338,36 @@ void FGTrafficManager::loadHeuristics()
     }
 }
 
-void FGTrafficManager::update(double /*dt */ )
+bool FGTrafficManager::metarReady(double dt)
+{
+    // wait for valid METAR (when realWX is enabled only), since we need
+    // to know the active runway
+    if (metarValid || !realWxEnabled)
+    {
+        waitingMetarTime = 0.0;
+        return true;
+    }
+
+    // METAR timeout: when running offline, remote server is down etc
+    if (waitingMetarStation != fgGetString("/environment/metar/station-id"))
+    {
+        // station has changed: wait for reply, restart timeout
+        waitingMetarTime = 0.0;
+        waitingMetarStation = fgGetString("/environment/metar/station-id");
+        return false;
+    }
+
+    // timeout elapsed (10 seconds)?
+    if (waitingMetarTime > 20.0)
+    {
+        return true;
+    }
+
+    waitingMetarTime += dt;
+    return false;
+}
+
+void FGTrafficManager::update(double dt)
 {
     if (!enabled)
     {
@@ -278,9 +376,8 @@ void FGTrafficManager::update(double /*dt */ )
         return;
     }
 
-    if ((realWxEnabled && !metarValid)) {
+    if (!metarReady(dt))
         return;
-    }
 
     if (!aiEnabled)
     {
@@ -293,18 +390,19 @@ void FGTrafficManager::update(double /*dt */ )
             init();
         }
         
-        initStep();
-        if (!inited) {
-            return; // still more to do on next update() call
+        if (!scheduleParser->isFinished()) {
+          return;
         }
+      
+        finishInit();
     }
         
     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-    if (scheduledAircraft.size() == 0) {
+    if (scheduledAircraft.empty()) {
         return;
     }
 
-    SGVec3d userCart = globals->get_aircraft_positon_cart();
+    SGVec3d userCart = globals->get_aircraft_position_cart();
 
     if (currAircraft == scheduledAircraft.end()) {
         currAircraft = scheduledAircraft.begin();
@@ -316,25 +414,6 @@ void FGTrafficManager::update(double /*dt */ )
     currAircraft++;
 }
 
-void FGTrafficManager::release(int id)
-{
-    releaseList.push_back(id);
-}
-
-bool FGTrafficManager::isReleased(int id)
-{
-    IdListIterator i = releaseList.begin();
-    while (i != releaseList.end()) {
-        if ((*i) == id) {
-            releaseList.erase(i);
-            return true;
-        }
-        i++;
-    }
-    return false;
-}
-
-
 void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
 {
     string model;
@@ -354,7 +433,7 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
     string buffString;
     vector <string> tokens, depTime,arrTime;
     vector <string>::iterator it;
-    ifstream infile(infileName.str().c_str());
+    std::ifstream infile(infileName.str().c_str());
     while (1) {
          infile.getline(buffer, 256);
          if (infile.eof()) {
@@ -390,7 +469,13 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                  FlightType     = tokens[9];
                  radius         = atof(tokens[8].c_str());
                  offset         = atof(tokens[7].c_str());;
-                 SG_LOG(SG_GENERAL, SG_ALERT, "Adding Aircraft" << model << " " << livery << " " << homePort << " " 
+                 
+                 if (!FGAISchedule::validModelPath(model)) {
+                     SG_LOG(SG_GENERAL, SG_WARN, "TrafficMgr: Missing model path:" << 
+                            model << " from " << infileName.str());
+                 } else {
+                 
+                 SG_LOG(SG_GENERAL, SG_INFO, "Adding Aircraft" << model << " " << livery << " " << homePort << " " 
                                                                 << registration << " " << flightReq << " " << isHeavy 
                                                                 << " " << acType << " " << airline << " " << m_class 
                                                                 << " " << FlightType << " " << radius << " " << offset);
@@ -406,6 +491,7 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                                                               FlightType,
                                                               radius,
                                                               offset));
+                 } // of valid model path
              }
              if (tokens[0] == string("FLIGHT")) {
                  //cerr << "Found flight " << buffString << " size is : " << tokens.size() << endl;
@@ -642,78 +728,70 @@ void FGTrafficManager::endElement(const char *name)
                                                                   requiredAircraft));
         requiredAircraft = "";
     } else if (!strcmp(name, "aircraft")) {
-        string isHeavy;
-        if (heavy) {
-            isHeavy = "true";
-        } else {
-            isHeavy = "false"; 
-        }
-        /*
-        cerr << "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
-             << "," << acType << "," << livery << "," 
-             << airline << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl << endl;*/
-        int proportion =
-            (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
-        int randval = rand() & 100;
-        if (randval <= proportion) {
-            if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
-                SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
-                 << "," << acType << "," << livery << "," 
-                 << airline << ","  << m_class << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl);
-            }
-            //scheduledAircraft.push_back(new FGAISchedule(mdl, 
-            //                                     livery, 
-            //                                     registration, 
-            //                                     heavy,
-            //                                     acType, 
-            //                                     airline, 
-            //                                     m_class, 
-            //                                     flighttype,
-            //                                     radius,
-            //                                     offset,
-            //                                     score,
-            //                                     flights));
-            if (requiredAircraft == "") {
-                char buffer[16];
-                snprintf(buffer, 16, "%d", acCounter);
-                requiredAircraft = buffer;
-            }
-            if (homePort == "") {
-                homePort = departurePort;
-            }
-            scheduledAircraft.push_back(new FGAISchedule(mdl,
-                                                         livery,
-                                                         homePort,
-                                                         registration,
-                                                         requiredAircraft,
-                                                         heavy,
-                                                         acType,
-                                                         airline,
-                                                         m_class,
-                                                         flighttype,
-                                                         radius, offset));
-
-            //  while(flights.begin() != flights.end()) {
-//      flights.pop_back();
-//       }
-        } else {
-            cerr << "Skipping : " << randval;
-        }
-        acCounter++;
-        requiredAircraft = "";
-        homePort = "";
-        //for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
-        //  {
-        //    delete (*flt);
-        //  }
-        //flights.clear();
-        SG_LOG(SG_GENERAL, SG_BULK, "Reading aircraft : "
-               << registration << " with prioritization score " << score);
-        score = 0;
+        endAircraft();
     }
+    
     elementValueStack.pop_back();
 }
 
+void FGTrafficManager::endAircraft()
+{
+    string isHeavy = heavy ? "true" : "false";
+
+    if (missingModels.find(mdl) != missingModels.end()) {
+    // don't stat() or warn again
+        requiredAircraft = homePort = "";
+        return;
+    }
+    
+    if (!FGAISchedule::validModelPath(mdl)) {
+        missingModels.insert(mdl);
+        SG_LOG(SG_GENERAL, SG_WARN, "TrafficMgr: Missing model path:" << mdl);
+        requiredAircraft = homePort = "";
+        return;
+    }
+        
+    int proportion =
+        (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
+    int randval = rand() & 100;
+    if (randval > proportion) {
+        requiredAircraft = homePort = "";
+        return;
+    }
+    
+    if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
+               << "," << acType << "," << livery << "," 
+               << airline << ","  << m_class << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl);
+    }
+
+    if (requiredAircraft == "") {
+        char buffer[16];
+        snprintf(buffer, 16, "%d", acCounter);
+        requiredAircraft = buffer;
+    }
+    if (homePort == "") {
+        homePort = departurePort;
+    }
+    
+    scheduledAircraft.push_back(new FGAISchedule(mdl,
+                                                 livery,
+                                                 homePort,
+                                                 registration,
+                                                 requiredAircraft,
+                                                 heavy,
+                                                 acType,
+                                                 airline,
+                                                 m_class,
+                                                 flighttype,
+                                                 radius, offset));
+            
+    acCounter++;
+    requiredAircraft = "";
+    homePort = "";
+    score = 0;
+}
+    
 void FGTrafficManager::data(const char *s, int len)
 {
     string token = string(s, len);