Support for multiple data dirs.
This commit is contained in:
parent
fda64d840e
commit
33425c671d
6 changed files with 390 additions and 295 deletions
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
@ -350,9 +351,11 @@ bool FGAIBase::init(bool search_in_AI_path)
|
|||
osg::ref_ptr<osgDB::ReaderWriter::Options>
|
||||
opt(osg::clone(osgDB::Registry::instance()->getOptions(), osg::CopyOp::SHALLOW_COPY));
|
||||
|
||||
SGPath ai_path(globals->get_fg_root(), "AI");
|
||||
opt->setDatabasePath(ai_path.str());
|
||||
|
||||
osgDB::FilePathList& paths(opt->getDatabasePathList());
|
||||
paths.clear();
|
||||
BOOST_FOREACH(SGPath p, globals->get_data_paths("AI")) {
|
||||
paths.push_back(p.str());
|
||||
}
|
||||
f = osgDB::findDataFile(model_path, opt.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -252,6 +252,54 @@ void FGGlobals::set_fg_home (const std::string &home) {
|
|||
fg_home = tmp.realpath();
|
||||
}
|
||||
|
||||
PathList FGGlobals::get_data_paths() const
|
||||
{
|
||||
PathList r(additional_data_paths);
|
||||
r.push_back(SGPath(fg_root));
|
||||
return r;
|
||||
}
|
||||
|
||||
PathList FGGlobals::get_data_paths(const std::string& suffix) const
|
||||
{
|
||||
PathList r;
|
||||
BOOST_FOREACH(SGPath p, get_data_paths()) {
|
||||
p.append(suffix);
|
||||
if (p.exists()) {
|
||||
r.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void FGGlobals::append_data_path(const SGPath& path)
|
||||
{
|
||||
if (!path.exists()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "adding non-existant data path:" << path);
|
||||
}
|
||||
|
||||
additional_data_paths.push_back(path);
|
||||
}
|
||||
|
||||
SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const
|
||||
{
|
||||
BOOST_FOREACH(SGPath p, additional_data_paths) {
|
||||
p.append(pathSuffix);
|
||||
if (p.exists()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
SGPath rootPath(fg_root);
|
||||
rootPath.append(pathSuffix);
|
||||
if (rootPath.exists()) {
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "dir not found in any data path:" << pathSuffix);
|
||||
return SGPath();
|
||||
}
|
||||
|
||||
void FGGlobals::append_fg_scenery (const std::string &paths)
|
||||
{
|
||||
// fg_scenery.clear();
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <string>
|
||||
|
||||
typedef std::vector<std::string> string_list;
|
||||
typedef std::vector<SGPath> PathList;
|
||||
|
||||
// Forward declarations
|
||||
|
||||
|
@ -93,6 +94,11 @@ private:
|
|||
// Root of FlightGear data tree
|
||||
std::string fg_root;
|
||||
|
||||
/**
|
||||
* locations to search for (non-scenery) data.
|
||||
*/
|
||||
PathList additional_data_paths;
|
||||
|
||||
// Users home directory for data
|
||||
std::string fg_home;
|
||||
|
||||
|
@ -178,6 +184,26 @@ public:
|
|||
inline const std::string &get_fg_root () const { return fg_root; }
|
||||
void set_fg_root (const std::string &root);
|
||||
|
||||
/**
|
||||
* Get list of data locations. fg_root is always the final item in the
|
||||
* result.
|
||||
*/
|
||||
PathList get_data_paths() const;
|
||||
|
||||
/**
|
||||
* Get data locations which contain the file path suffix. Eg pass ing
|
||||
* 'AI/Traffic' to get all data paths which define <path>/AI/Traffic subdir
|
||||
*/
|
||||
PathList get_data_paths(const std::string& suffix) const;
|
||||
|
||||
void append_data_path(const SGPath& path);
|
||||
|
||||
/**
|
||||
* Given a path suffix (eg 'Textures' or 'AI/Traffic'), find the
|
||||
* first data directory which defines it.
|
||||
*/
|
||||
SGPath find_data_dir(const std::string& pathSuffix) const;
|
||||
|
||||
inline const std::string &get_fg_home () const { return fg_home; }
|
||||
void set_fg_home (const std::string &home);
|
||||
|
||||
|
|
|
@ -596,6 +596,16 @@ static naRef f_resolveDataPath(naContext c, naRef me, int argc, naRef* args)
|
|||
return naStr_fromdata(naNewString(c), const_cast<char*>(pdata), strlen(pdata));
|
||||
}
|
||||
|
||||
static naRef f_findDataDir(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc != 1 || !naIsString(args[0]))
|
||||
naRuntimeError(c, "bad arguments to findDataDir()");
|
||||
|
||||
SGPath p = globals->find_data_dir(naStr_data(args[0]));
|
||||
const char* pdata = p.c_str();
|
||||
return naStr_fromdata(naNewString(c), const_cast<char*>(pdata), strlen(pdata));
|
||||
}
|
||||
|
||||
class NasalCommand : public SGCommandMgr::Command
|
||||
{
|
||||
public:
|
||||
|
@ -724,6 +734,7 @@ static struct { const char* name; naCFunction func; } funcs[] = {
|
|||
{ "abort", f_abort },
|
||||
{ "directory", f_directory },
|
||||
{ "resolvepath", f_resolveDataPath },
|
||||
{ "finddata", f_findDataDir },
|
||||
{ "parsexml", f_parsexml },
|
||||
{ "systime", f_systime },
|
||||
{ 0, 0 }
|
||||
|
|
|
@ -76,13 +76,19 @@ using std::endl;
|
|||
/**
|
||||
* Thread encapsulating parsing the traffic schedules.
|
||||
*/
|
||||
class ScheduleParseThread : public SGThread
|
||||
class ScheduleParseThread : public SGThread, public XMLVisitor
|
||||
{
|
||||
public:
|
||||
ScheduleParseThread(FGTrafficManager* traffic) :
|
||||
_trafficManager(traffic),
|
||||
_isFinished(false),
|
||||
_cancelThread(false)
|
||||
_cancelThread(false),
|
||||
cruiseAlt(0),
|
||||
score(0),
|
||||
acCounter(0),
|
||||
radius(0),
|
||||
offset(0),
|
||||
heavy(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -100,9 +106,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setTrafficDir(const SGPath& trafficDirPath)
|
||||
void setTrafficDirs(const PathList& dirs)
|
||||
{
|
||||
_trafficDirPath = trafficDirPath;
|
||||
_trafficDirPaths = dirs;
|
||||
}
|
||||
|
||||
bool isFinished() const
|
||||
|
@ -113,35 +119,289 @@ public:
|
|||
|
||||
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;
|
||||
}
|
||||
BOOST_FOREACH(SGPath p, _trafficDirPaths) {
|
||||
parseTrafficDir(p);
|
||||
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;
|
||||
}
|
||||
|
||||
void startXML()
|
||||
{
|
||||
//cout << "Start XML" << endl;
|
||||
requiredAircraft = "";
|
||||
homePort = "";
|
||||
}
|
||||
|
||||
void endXML()
|
||||
{
|
||||
//cout << "End XML" << endl;
|
||||
}
|
||||
|
||||
void startElement(const char *name,
|
||||
const XMLAttributes & atts)
|
||||
{
|
||||
const char *attval;
|
||||
//cout << "Start element " << name << endl;
|
||||
//FGTrafficManager temp;
|
||||
//for (int i = 0; i < atts.size(); i++)
|
||||
// if (string(atts.getName(i)) == string("include"))
|
||||
attval = atts.getValue("include");
|
||||
if (attval != 0) {
|
||||
//cout << "including " << attval << endl;
|
||||
SGPath path = globals->get_fg_root();
|
||||
path.append("/Traffic/");
|
||||
path.append(attval);
|
||||
readXML(path.str(), *this);
|
||||
}
|
||||
elementValueStack.push_back("");
|
||||
// cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
|
||||
}
|
||||
|
||||
void endElement(const char *name)
|
||||
{
|
||||
//cout << "End element " << name << endl;
|
||||
const string & value = elementValueStack.back();
|
||||
|
||||
if (!strcmp(name, "model"))
|
||||
mdl = value;
|
||||
else if (!strcmp(name, "livery"))
|
||||
livery = value;
|
||||
else if (!strcmp(name, "home-port"))
|
||||
homePort = value;
|
||||
else if (!strcmp(name, "registration"))
|
||||
registration = value;
|
||||
else if (!strcmp(name, "airline"))
|
||||
airline = value;
|
||||
else if (!strcmp(name, "actype"))
|
||||
acType = value;
|
||||
else if (!strcmp(name, "required-aircraft"))
|
||||
requiredAircraft = value;
|
||||
else if (!strcmp(name, "flighttype"))
|
||||
flighttype = value;
|
||||
else if (!strcmp(name, "radius"))
|
||||
radius = atoi(value.c_str());
|
||||
else if (!strcmp(name, "offset"))
|
||||
offset = atoi(value.c_str());
|
||||
else if (!strcmp(name, "performance-class"))
|
||||
m_class = value;
|
||||
else if (!strcmp(name, "heavy")) {
|
||||
if (value == string("true"))
|
||||
heavy = true;
|
||||
else
|
||||
heavy = false;
|
||||
} else if (!strcmp(name, "callsign"))
|
||||
callsign = value;
|
||||
else if (!strcmp(name, "fltrules"))
|
||||
fltrules = value;
|
||||
else if (!strcmp(name, "port"))
|
||||
port = value;
|
||||
else if (!strcmp(name, "time"))
|
||||
timeString = value;
|
||||
else if (!strcmp(name, "departure")) {
|
||||
departurePort = port;
|
||||
departureTime = timeString;
|
||||
} else if (!strcmp(name, "cruise-alt"))
|
||||
cruiseAlt = atoi(value.c_str());
|
||||
else if (!strcmp(name, "arrival")) {
|
||||
arrivalPort = port;
|
||||
arrivalTime = timeString;
|
||||
} else if (!strcmp(name, "repeat"))
|
||||
repeat = value;
|
||||
else if (!strcmp(name, "flight")) {
|
||||
// We have loaded and parsed all the information belonging to this flight
|
||||
// so we temporarily store it.
|
||||
//cerr << "Pusing back flight " << callsign << endl;
|
||||
//cerr << callsign << " " << fltrules << " "<< departurePort << " " << arrivalPort << " "
|
||||
// << cruiseAlt << " " << departureTime<< " "<< arrivalTime << " " << repeat << endl;
|
||||
|
||||
//Prioritize aircraft
|
||||
string apt = fgGetString("/sim/presets/airport-id");
|
||||
//cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
|
||||
//if (departurePort == apt) score++;
|
||||
//flights.push_back(new FGScheduledFlight(callsign,
|
||||
// fltrules,
|
||||
// departurePort,
|
||||
// arrivalPort,
|
||||
// cruiseAlt,
|
||||
// departureTime,
|
||||
// arrivalTime,
|
||||
// repeat));
|
||||
if (requiredAircraft == "") {
|
||||
char buffer[16];
|
||||
snprintf(buffer, 16, "%d", acCounter);
|
||||
requiredAircraft = buffer;
|
||||
}
|
||||
SG_LOG(SG_AI, SG_DEBUG, "Adding flight: " << callsign << " "
|
||||
<< fltrules << " "
|
||||
<< departurePort << " "
|
||||
<< arrivalPort << " "
|
||||
<< cruiseAlt << " "
|
||||
<< departureTime << " "
|
||||
<< arrivalTime << " " << repeat << " " << requiredAircraft);
|
||||
// For database maintainance purposes, it may be convenient to
|
||||
//
|
||||
if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
|
||||
SG_LOG(SG_AI, SG_ALERT, "Traffic Dump FLIGHT," << callsign << ","
|
||||
<< fltrules << ","
|
||||
<< departurePort << ","
|
||||
<< arrivalPort << ","
|
||||
<< cruiseAlt << ","
|
||||
<< departureTime << ","
|
||||
<< arrivalTime << "," << repeat << "," << requiredAircraft);
|
||||
}
|
||||
|
||||
_trafficManager->flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
|
||||
fltrules,
|
||||
departurePort,
|
||||
arrivalPort,
|
||||
cruiseAlt,
|
||||
departureTime,
|
||||
arrivalTime,
|
||||
repeat,
|
||||
requiredAircraft));
|
||||
requiredAircraft = "";
|
||||
} else if (!strcmp(name, "aircraft")) {
|
||||
endAircraft();
|
||||
}
|
||||
|
||||
elementValueStack.pop_back();
|
||||
}
|
||||
|
||||
|
||||
void data(const char *s, int len)
|
||||
{
|
||||
string token = string(s, len);
|
||||
//cout << "Character data " << string(s,len) << endl;
|
||||
elementValueStack.back() += token;
|
||||
}
|
||||
|
||||
void pi(const char *target, const char *data)
|
||||
{
|
||||
//cout << "Processing instruction " << target << ' ' << data << endl;
|
||||
}
|
||||
|
||||
void warning(const char *message, int line, int column)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN,
|
||||
"Warning: " << message << " (" << line << ',' << column << ')');
|
||||
}
|
||||
|
||||
void error(const char *message, int line, int column)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_ALERT,
|
||||
"Error: " << message << " (" << line << ',' << column << ')');
|
||||
}
|
||||
|
||||
private:
|
||||
void 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_AI, 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_AI, 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;
|
||||
}
|
||||
|
||||
// caution, modifying the scheduled aircraft strucutre from the
|
||||
// 'wrong' thread. This is safe becuase FGTrafficManager won't touch
|
||||
// the structure while we exist.
|
||||
_trafficManager->scheduledAircraft.push_back(new FGAISchedule(mdl,
|
||||
livery,
|
||||
homePort,
|
||||
registration,
|
||||
requiredAircraft,
|
||||
heavy,
|
||||
acType,
|
||||
airline,
|
||||
m_class,
|
||||
flighttype,
|
||||
radius, offset));
|
||||
|
||||
acCounter++;
|
||||
requiredAircraft = "";
|
||||
homePort = "";
|
||||
score = 0;
|
||||
}
|
||||
|
||||
void parseTrafficDir(const SGPath& path)
|
||||
{
|
||||
SGTimeStamp st;
|
||||
st.stamp();
|
||||
|
||||
simgear::Dir trafficDir(path);
|
||||
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) {
|
||||
readXML(xml.str(), *this);
|
||||
if (_cancelThread) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // of sub-directories iteration
|
||||
|
||||
SG_LOG(SG_AI, SG_INFO, "parsing traffic schedules took:" << st.elapsedMSec() << "msec");
|
||||
}
|
||||
|
||||
FGTrafficManager* _trafficManager;
|
||||
mutable SGMutex _lock;
|
||||
bool _isFinished;
|
||||
bool _cancelThread;
|
||||
SGPath _trafficDirPath;
|
||||
PathList _trafficDirPaths;
|
||||
|
||||
// parser state
|
||||
|
||||
string_list elementValueStack;
|
||||
// record model paths which are missing, to avoid duplicate
|
||||
// warnings when parsing traffic schedules.
|
||||
std::set<std::string> missingModels;
|
||||
|
||||
std::string mdl, livery, registration, callsign, fltrules,
|
||||
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
|
||||
repeat, acType, airline, m_class, flighttype, requiredAircraft, homePort;
|
||||
int cruiseAlt;
|
||||
int score, acCounter;
|
||||
double radius, offset;
|
||||
bool heavy;
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -151,12 +411,6 @@ FGTrafficManager::FGTrafficManager() :
|
|||
inited(false),
|
||||
doingInit(false),
|
||||
waitingMetarTime(0.0),
|
||||
cruiseAlt(0),
|
||||
score(0),
|
||||
acCounter(0),
|
||||
radius(0),
|
||||
offset(0),
|
||||
heavy(false),
|
||||
enabled("/sim/traffic-manager/enabled"),
|
||||
aiEnabled("/sim/ai/enabled"),
|
||||
realWxEnabled("/environment/realwx/enabled"),
|
||||
|
@ -224,14 +478,6 @@ void FGTrafficManager::shutdown()
|
|||
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()
|
||||
{
|
||||
if (!enabled) {
|
||||
|
@ -240,9 +486,15 @@ void FGTrafficManager::init()
|
|||
|
||||
assert(!doingInit);
|
||||
doingInit = true;
|
||||
if (string(fgGetString("/sim/traffic-manager/datafile")).empty()) {
|
||||
if (string(fgGetString("/sim/traffic-manager/datafile")).empty()) {
|
||||
PathList dirs = globals->get_data_paths("AI/Traffic");
|
||||
if (dirs.empty()) {
|
||||
doingInit = false;
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleParser.reset(new ScheduleParseThread(this));
|
||||
scheduleParser->setTrafficDir(SGPath(globals->get_fg_root(), "AI/Traffic"));
|
||||
scheduleParser->setTrafficDirs(dirs);
|
||||
scheduleParser->start();
|
||||
} else {
|
||||
fgSetBool("/sim/traffic-manager/heuristics", false);
|
||||
|
@ -250,7 +502,10 @@ void FGTrafficManager::init()
|
|||
string ext = path.extension();
|
||||
if (path.extension() == "xml") {
|
||||
if (path.exists()) {
|
||||
readXML(path.str(), *this);
|
||||
// use a SchedulerParser to parse, but run it in this thread,
|
||||
// i.e don't start it
|
||||
ScheduleParseThread parser(this);
|
||||
readXML(path.str(), parser);
|
||||
}
|
||||
} else if (path.extension() == "conf") {
|
||||
if (path.exists()) {
|
||||
|
@ -597,225 +852,3 @@ void FGTrafficManager::Tokenize(const string& str,
|
|||
}
|
||||
|
||||
|
||||
void FGTrafficManager::startXML()
|
||||
{
|
||||
//cout << "Start XML" << endl;
|
||||
requiredAircraft = "";
|
||||
homePort = "";
|
||||
}
|
||||
|
||||
void FGTrafficManager::endXML()
|
||||
{
|
||||
//cout << "End XML" << endl;
|
||||
}
|
||||
|
||||
void FGTrafficManager::startElement(const char *name,
|
||||
const XMLAttributes & atts)
|
||||
{
|
||||
const char *attval;
|
||||
//cout << "Start element " << name << endl;
|
||||
//FGTrafficManager temp;
|
||||
//for (int i = 0; i < atts.size(); i++)
|
||||
// if (string(atts.getName(i)) == string("include"))
|
||||
attval = atts.getValue("include");
|
||||
if (attval != 0) {
|
||||
//cout << "including " << attval << endl;
|
||||
SGPath path = globals->get_fg_root();
|
||||
path.append("/Traffic/");
|
||||
path.append(attval);
|
||||
readXML(path.str(), *this);
|
||||
}
|
||||
elementValueStack.push_back("");
|
||||
// cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
|
||||
}
|
||||
|
||||
void FGTrafficManager::endElement(const char *name)
|
||||
{
|
||||
//cout << "End element " << name << endl;
|
||||
const string & value = elementValueStack.back();
|
||||
|
||||
if (!strcmp(name, "model"))
|
||||
mdl = value;
|
||||
else if (!strcmp(name, "livery"))
|
||||
livery = value;
|
||||
else if (!strcmp(name, "home-port"))
|
||||
homePort = value;
|
||||
else if (!strcmp(name, "registration"))
|
||||
registration = value;
|
||||
else if (!strcmp(name, "airline"))
|
||||
airline = value;
|
||||
else if (!strcmp(name, "actype"))
|
||||
acType = value;
|
||||
else if (!strcmp(name, "required-aircraft"))
|
||||
requiredAircraft = value;
|
||||
else if (!strcmp(name, "flighttype"))
|
||||
flighttype = value;
|
||||
else if (!strcmp(name, "radius"))
|
||||
radius = atoi(value.c_str());
|
||||
else if (!strcmp(name, "offset"))
|
||||
offset = atoi(value.c_str());
|
||||
else if (!strcmp(name, "performance-class"))
|
||||
m_class = value;
|
||||
else if (!strcmp(name, "heavy")) {
|
||||
if (value == string("true"))
|
||||
heavy = true;
|
||||
else
|
||||
heavy = false;
|
||||
} else if (!strcmp(name, "callsign"))
|
||||
callsign = value;
|
||||
else if (!strcmp(name, "fltrules"))
|
||||
fltrules = value;
|
||||
else if (!strcmp(name, "port"))
|
||||
port = value;
|
||||
else if (!strcmp(name, "time"))
|
||||
timeString = value;
|
||||
else if (!strcmp(name, "departure")) {
|
||||
departurePort = port;
|
||||
departureTime = timeString;
|
||||
} else if (!strcmp(name, "cruise-alt"))
|
||||
cruiseAlt = atoi(value.c_str());
|
||||
else if (!strcmp(name, "arrival")) {
|
||||
arrivalPort = port;
|
||||
arrivalTime = timeString;
|
||||
} else if (!strcmp(name, "repeat"))
|
||||
repeat = value;
|
||||
else if (!strcmp(name, "flight")) {
|
||||
// We have loaded and parsed all the information belonging to this flight
|
||||
// so we temporarily store it.
|
||||
//cerr << "Pusing back flight " << callsign << endl;
|
||||
//cerr << callsign << " " << fltrules << " "<< departurePort << " " << arrivalPort << " "
|
||||
// << cruiseAlt << " " << departureTime<< " "<< arrivalTime << " " << repeat << endl;
|
||||
|
||||
//Prioritize aircraft
|
||||
string apt = fgGetString("/sim/presets/airport-id");
|
||||
//cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
|
||||
//if (departurePort == apt) score++;
|
||||
//flights.push_back(new FGScheduledFlight(callsign,
|
||||
// fltrules,
|
||||
// departurePort,
|
||||
// arrivalPort,
|
||||
// cruiseAlt,
|
||||
// departureTime,
|
||||
// arrivalTime,
|
||||
// repeat));
|
||||
if (requiredAircraft == "") {
|
||||
char buffer[16];
|
||||
snprintf(buffer, 16, "%d", acCounter);
|
||||
requiredAircraft = buffer;
|
||||
}
|
||||
SG_LOG(SG_AI, SG_DEBUG, "Adding flight: " << callsign << " "
|
||||
<< fltrules << " "
|
||||
<< departurePort << " "
|
||||
<< arrivalPort << " "
|
||||
<< cruiseAlt << " "
|
||||
<< departureTime << " "
|
||||
<< arrivalTime << " " << repeat << " " << requiredAircraft);
|
||||
// For database maintainance purposes, it may be convenient to
|
||||
//
|
||||
if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
|
||||
SG_LOG(SG_AI, SG_ALERT, "Traffic Dump FLIGHT," << callsign << ","
|
||||
<< fltrules << ","
|
||||
<< departurePort << ","
|
||||
<< arrivalPort << ","
|
||||
<< cruiseAlt << ","
|
||||
<< departureTime << ","
|
||||
<< arrivalTime << "," << repeat << "," << requiredAircraft);
|
||||
}
|
||||
flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
|
||||
fltrules,
|
||||
departurePort,
|
||||
arrivalPort,
|
||||
cruiseAlt,
|
||||
departureTime,
|
||||
arrivalTime,
|
||||
repeat,
|
||||
requiredAircraft));
|
||||
requiredAircraft = "";
|
||||
} else if (!strcmp(name, "aircraft")) {
|
||||
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_AI, 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_AI, 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);
|
||||
//cout << "Character data " << string(s,len) << endl;
|
||||
elementValueStack.back() += token;
|
||||
}
|
||||
|
||||
void FGTrafficManager::pi(const char *target, const char *data)
|
||||
{
|
||||
//cout << "Processing instruction " << target << ' ' << data << endl;
|
||||
}
|
||||
|
||||
void FGTrafficManager::warning(const char *message, int line, int column)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN,
|
||||
"Warning: " << message << " (" << line << ',' << column << ')');
|
||||
}
|
||||
|
||||
void FGTrafficManager::error(const char *message, int line, int column)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_ALERT,
|
||||
"Error: " << message << " (" << line << ',' << column << ')');
|
||||
}
|
||||
|
|
|
@ -51,9 +51,7 @@
|
|||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
#include <simgear/xml/easyxml.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
|
||||
#include "SchedFlight.hxx"
|
||||
#include "Schedule.hxx"
|
||||
|
@ -77,7 +75,7 @@ typedef HeuristicMap::iterator HeuristicMapIterator;
|
|||
|
||||
class ScheduleParseThread;
|
||||
|
||||
class FGTrafficManager : public SGSubsystem, public XMLVisitor
|
||||
class FGTrafficManager : public SGSubsystem
|
||||
{
|
||||
private:
|
||||
bool inited;
|
||||
|
@ -87,24 +85,11 @@ private:
|
|||
|
||||
ScheduleVector scheduledAircraft;
|
||||
ScheduleVectorIterator currAircraft, currAircraftClosest;
|
||||
vector<string> elementValueStack;
|
||||
|
||||
// record model paths which are missing, to avoid duplicate
|
||||
// warnings when parsing traffic schedules.
|
||||
std::set<std::string> missingModels;
|
||||
|
||||
std::string mdl, livery, registration, callsign, fltrules,
|
||||
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
|
||||
repeat, acType, airline, m_class, flighttype, requiredAircraft, homePort;
|
||||
int cruiseAlt;
|
||||
int score, acCounter;
|
||||
double radius, offset;
|
||||
bool heavy;
|
||||
|
||||
FGScheduledFlightMap flights;
|
||||
|
||||
void readTimeTableFromFile(SGPath infilename);
|
||||
void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ");
|
||||
void Tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters = " ");
|
||||
|
||||
simgear::PropertyObject<bool> enabled, aiEnabled, realWxEnabled, metarValid;
|
||||
|
||||
|
@ -129,20 +114,9 @@ public:
|
|||
void init();
|
||||
void update(double time);
|
||||
|
||||
FGScheduledFlightVecIterator getFirstFlight(const string &ref) { return flights[ref].begin(); }
|
||||
FGScheduledFlightVecIterator getLastFlight(const string &ref) { return flights[ref].end(); }
|
||||
FGScheduledFlightVecIterator getFirstFlight(const std::string &ref) { return flights[ref].begin(); }
|
||||
FGScheduledFlightVecIterator getLastFlight(const std::string &ref) { return flights[ref].end(); }
|
||||
|
||||
void endAircraft();
|
||||
|
||||
// Some overloaded virtual XMLVisitor members
|
||||
virtual void startXML ();
|
||||
virtual void endXML ();
|
||||
virtual void startElement (const char * name, const XMLAttributes &atts);
|
||||
virtual void endElement (const char * name);
|
||||
virtual void data (const char * s, int len);
|
||||
virtual void pi (const char * target, const char * data);
|
||||
virtual void warning (const char * message, int line, int column);
|
||||
virtual void error (const char * message, int line, int column);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue