X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAIManager.cxx;h=9813b9dc25f768542f0378e344e5e2850d34c564;hb=b5c46a8d59120f18b0bc268af72ecb6d3a75b3e3;hp=b3d3060da74ce6772e3d96dc4ec53fbc8c656ea3;hpb=85a1e5cc983169594563763c903436c8f1cfa934;p=flightgear.git diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index b3d3060da..9813b9dc2 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -1,5 +1,5 @@ // AIManager.cxx Based on David Luff's AIMgr: -// - a global management class for AI objects +// - a global management type for AI objects // // Written by David Culp, started October 2003. // - davidculp2@comcast.net @@ -16,248 +16,446 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include +#include +#include -#include -#include
#include
-#include +#include +#include #include "AIManager.hxx" #include "AIAircraft.hxx" #include "AIShip.hxx" #include "AIBallistic.hxx" - -SG_USING_STD(list); - +#include "AIStorm.hxx" +#include "AIThermal.hxx" +#include "AICarrier.hxx" +#include "AIStatic.hxx" +#include "AIMultiplayer.hxx" +#include "AITanker.hxx" +#include "AIWingman.hxx" +#include "AIGroundVehicle.hxx" FGAIManager::FGAIManager() { - initDone = false; - numObjects = 0; - dt_count = 9; + _dt = 0.0; + mNumAiModels = 0; + + for (unsigned i = 0; i < FGAIBase::MAX_OBJECTS; ++i) + mNumAiTypeModels[i] = 0; } FGAIManager::~FGAIManager() { - ai_list_itr = ai_list.begin(); - while(ai_list_itr != ai_list.end()) { - delete (*ai_list_itr); - ++ai_list_itr; + ai_list_iterator ai_list_itr = ai_list.begin(); + + while(ai_list_itr != ai_list.end()) { + (*ai_list_itr)->unbind(); + ++ai_list_itr; } - ai_list.clear(); - ids.clear(); } +void +FGAIManager::init() { + root = fgGetNode("sim/ai", true); -void FGAIManager::init() { - int rval; - root = fgGetNode("sim/ai", true); + enabled = root->getNode("enabled", true)->getBoolValue(); - for (int i = 0; i < root->nChildren(); i++) { - const SGPropertyNode * entry = root->getChild(i); + if (!enabled) + return; - if (!strcmp(entry->getName(), "entry")) { - if (!strcmp(entry->getStringValue("type", ""), "aircraft")) { + thermal_lift_node = fgGetNode("/environment/thermal-lift-fps", true); + wind_from_east_node = fgGetNode("/environment/wind-from-east-fps",true); + wind_from_north_node = fgGetNode("/environment/wind-from-north-fps",true); + + user_latitude_node = fgGetNode("/position/latitude-deg", true); + user_longitude_node = fgGetNode("/position/longitude-deg", true); + user_altitude_node = fgGetNode("/position/altitude-ft", true); + user_heading_node = fgGetNode("/orientation/heading-deg", true); + user_pitch_node = fgGetNode("/orientation/pitch-deg", true); + user_yaw_node = fgGetNode("/orientation/side-slip-deg", true); + user_roll_node = fgGetNode("/orientation/roll-deg", true); + user_speed_node = fgGetNode("/velocities/uBody-fps", true); +} - rval = createAircraft( entry->getStringValue("class", ""), - entry->getStringValue("path"), - entry->getDoubleValue("latitude"), - entry->getDoubleValue("longitude"), - entry->getDoubleValue("altitude-ft"), - entry->getDoubleValue("heading"), - entry->getDoubleValue("speed-KTAS"), - 0.0, - entry->getDoubleValue("bank") ); +void +FGAIManager::postinit() { + // postinit, so that it can access the Nasal subsystem + map scenarios; + for (int i = 0 ; i < root->nChildren() ; i++) { + SGPropertyNode *n = root->getChild(i); + if (strcmp(n->getName(), "scenario")) + continue; + + string name = n->getStringValue(); + if (name.empty()) + continue; + + if (scenarios.find(name) != scenarios.end()) { + SG_LOG(SG_GENERAL, SG_WARN, "won't load scenario '" << name << "' twice"); + continue; + } - } else if (!strcmp(entry->getStringValue("type", ""), "ship")) { + SG_LOG(SG_GENERAL, SG_ALERT, "loading scenario '" << name << '\''); + processScenario(name); + scenarios[name] = true; + } +} - rval = createShip( entry->getStringValue("path"), - entry->getDoubleValue("latitude"), - entry->getDoubleValue("longitude"), - entry->getDoubleValue("altitude-ft"), - entry->getDoubleValue("heading"), - entry->getDoubleValue("speed-KTAS"), - entry->getDoubleValue("rudder") ); +void +FGAIManager::reinit() { + update(0.0); + ai_list_iterator ai_list_itr = ai_list.begin(); - } else if (!strcmp(entry->getStringValue("type", ""), "ballistic")) { + while(ai_list_itr != ai_list.end()) { + (*ai_list_itr)->reinit(); + ++ai_list_itr; + } +} - rval = createBallistic( entry->getStringValue("path"), - entry->getDoubleValue("latitude"), - entry->getDoubleValue("longitude"), - entry->getDoubleValue("altitude-ft"), - entry->getDoubleValue("azimuth"), - entry->getDoubleValue("elevation"), - entry->getDoubleValue("speed") ); +void +FGAIManager::bind() { + root = globals->get_props()->getNode("ai/models", true); + root->tie("count", SGRawValueMethods(*this, + &FGAIManager::getNumAiObjects)); +} - } +void +FGAIManager::unbind() { + root->untie("count"); +} + +void +FGAIManager::update(double dt) { + // initialize these for finding nearest thermals + range_nearest = 10000.0; + strength = 0.0; + + if (!enabled) + return; + + FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager"); + _dt = dt; + + ai_list_iterator ai_list_itr = ai_list.begin(); + + while(ai_list_itr != ai_list.end()) { + + if ((*ai_list_itr)->getDie()) { + tmgr->release((*ai_list_itr)->getID()); + --mNumAiModels; + --(mNumAiTypeModels[(*ai_list_itr)->getType()]); + FGAIBase *base = (*ai_list_itr).get(); + SGPropertyNode *props = base->_getProps(); + + props->setBoolValue("valid", false); + base->unbind(); + + // for backward compatibility reset properties, so that aircraft, + // which don't know the property, keep working + // TODO: remove after a while + props->setIntValue("id", -1); + props->setBoolValue("radar/in-range", false); + props->setIntValue("refuel/tanker", false); + + ai_list_itr = ai_list.erase(ai_list_itr); + } else { + fetchUserState(); + if ((*ai_list_itr)->isa(FGAIBase::otThermal)) { + FGAIBase *base = (*ai_list_itr).get(); + processThermal((FGAIThermal*)base); + } else { + (*ai_list_itr)->update(_dt); + } + ++ai_list_itr; + } } - } - initDone = true; + thermal_lift_node->setDoubleValue( strength ); // for thermals } +void +FGAIManager::attach(FGAIBase *model) +{ + //unsigned idx = mNumAiTypeModels[model->getType()]; + const char* typeString = model->getTypeString(); + SGPropertyNode* root = globals->get_props()->getNode("ai/models", true); + SGPropertyNode* p; + int i; + + // find free index in the property tree, if we have + // more than 10000 mp-aircrafts in the property tree we should optimize the mp-server + for (i = 0; i < 10000; i++) { + p = root->getNode(typeString, i, false); + + if (!p || !p->getBoolValue("valid", false)) + break; + + if (p->getIntValue("id",-1)==model->getID()) { + p->setStringValue("callsign","***invalid node***"); //debug only, should never set! + } + } -void FGAIManager::bind() { - root = globals->get_props()->getNode("ai/models", true); - root->tie("count", SGRawValuePointer(&numObjects)); + p = root->getNode(typeString, i, true); + model->setManager(this, p); + ai_list.push_back(model); + ++mNumAiModels; + ++(mNumAiTypeModels[model->getType()]); + model->init(model->getType()==FGAIBase::otAircraft + || model->getType()==FGAIBase::otMultiplayer + || model->getType()==FGAIBase::otStatic); + model->bind(); + p->setBoolValue("valid", true); } +void +FGAIManager::destroyObject( int ID ) { + ai_list_iterator ai_list_itr = ai_list.begin(); + + while(ai_list_itr != ai_list.end()) { + + if ((*ai_list_itr)->getID() == ID) { + --mNumAiModels; + --(mNumAiTypeModels[(*ai_list_itr)->getType()]); + (*ai_list_itr)->unbind(); + ai_list_itr = ai_list.erase(ai_list_itr); + } else + ++ai_list_itr; + } -void FGAIManager::unbind() { - root->untie("count"); } +int +FGAIManager::getNumAiObjects(void) const +{ + return mNumAiModels; +} -void FGAIManager::update(double dt) { - - ai_list_itr = ai_list.begin(); - while(ai_list_itr != ai_list.end()) { - if ((*ai_list_itr)->getDie()) { - freeID((*ai_list_itr)->getID()); - delete (*ai_list_itr); - ai_list.erase(ai_list_itr); - --ai_list_itr; - --numObjects; - } else { - fetchUserState(); - (*ai_list_itr)->update(dt); - } - ++ai_list_itr; - } +void +FGAIManager::fetchUserState( void ) { + user_latitude = user_latitude_node->getDoubleValue(); + user_longitude = user_longitude_node->getDoubleValue(); + user_altitude = user_altitude_node->getDoubleValue(); + user_heading = user_heading_node->getDoubleValue(); + user_pitch = user_pitch_node->getDoubleValue(); + user_yaw = user_yaw_node->getDoubleValue(); + user_speed = user_speed_node->getDoubleValue() * 0.592484; + user_roll = user_roll_node->getDoubleValue(); + wind_from_east = wind_from_east_node->getDoubleValue(); + wind_from_north = wind_from_north_node->getDoubleValue(); } +// only keep the results from the nearest thermal +void +FGAIManager::processThermal( FGAIThermal* thermal ) { + thermal->update(_dt); + + if ( thermal->_getRange() < range_nearest ) { + range_nearest = thermal->_getRange(); + strength = thermal->getStrength(); + } -// This function returns the next available ID -int FGAIManager::assignID() { - int maxint = 30000; - int x; - bool used; - for (x=0; xsetID( assignID() ); - ++numObjects; - if (model_class == "light") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]); - } else if (model_class == "ww2_fighter") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]); - } else if (model_class == "jet_transport") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); - } else if (model_class == "jet_fighter") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]); + SGPropertyNode* scenarios = scenarioTop->getChild("scenario"); + + if (!scenarios) + return; + + for (int i = 0; i < scenarios->nChildren(); i++) { + SGPropertyNode* scEntry = scenarios->getChild(i); + + if (strcmp(scEntry->getName(), "entry")) + continue; + std::string type = scEntry->getStringValue("type", "aircraft"); + + if (type == "tanker") { // refueling scenarios + FGAITanker* tanker = new FGAITanker; + tanker->readFromScenario(scEntry); + attach(tanker); + + } else if (type == "wingman") { + FGAIWingman* wingman = new FGAIWingman; + wingman->readFromScenario(scEntry); + attach(wingman); + + } else if (type == "aircraft") { + FGAIAircraft* aircraft = new FGAIAircraft; + aircraft->readFromScenario(scEntry); + attach(aircraft); + + } else if (type == "ship") { + FGAIShip* ship = new FGAIShip; + ship->readFromScenario(scEntry); + attach(ship); + + } else if (type == "carrier") { + FGAICarrier* carrier = new FGAICarrier; + carrier->readFromScenario(scEntry); + attach(carrier); + + } else if (type == "groundvehicle") { + FGAIGroundVehicle* groundvehicle = new FGAIGroundVehicle; + groundvehicle->readFromScenario(scEntry); + attach(groundvehicle); + + } else if (type == "thunderstorm") { + FGAIStorm* storm = new FGAIStorm; + storm->readFromScenario(scEntry); + attach(storm); + + } else if (type == "thermal") { + FGAIThermal* thermal = new FGAIThermal; + thermal->readFromScenario(scEntry); + attach(thermal); + + } else if (type == "ballistic") { + FGAIBallistic* ballistic = new FGAIBallistic; + ballistic->readFromScenario(scEntry); + attach(ballistic); + + } else if (type == "static") { + FGAIStatic* aistatic = new FGAIStatic; + aistatic->readFromScenario(scEntry); + attach(aistatic); } - ai_plane->setHeading(heading); - ai_plane->setSpeed(speed); - ai_plane->setPath(path.c_str()); - ai_plane->setAltitude(altitude); - ai_plane->setLongitude(longitude); - ai_plane->setLatitude(latitude); - ai_plane->setBank(roll); - ai_plane->init(); - ai_plane->bind(); - return ai_plane->getID(); -} + } -int FGAIManager::createShip( string path, double latitude, double longitude, - double altitude, double heading, double speed, - double rudder ) { - - FGAIShip* ai_ship = new FGAIShip(this); - ai_list.push_back(ai_ship); - ai_ship->setID( assignID() ); - ++numObjects; - ai_ship->setHeading(heading); - ai_ship->setSpeed(speed); - ai_ship->setPath(path.c_str()); - ai_ship->setAltitude(altitude); - ai_ship->setLongitude(longitude); - ai_ship->setLatitude(latitude); - ai_ship->setBank(rudder); - ai_ship->init(); - ai_ship->bind(); - return ai_ship->getID(); } - -int FGAIManager::createBallistic( string path, double latitude, double longitude, - double altitude, double azimuth, double elevation, - double speed ) { - - FGAIBallistic* ai_ballistic = new FGAIBallistic(this); - ai_list.push_back(ai_ballistic); - ai_ballistic->setID( assignID() ); - ++numObjects; - ai_ballistic->setAzimuth(azimuth); - ai_ballistic->setElevation(elevation); - ai_ballistic->setSpeed(speed); - ai_ballistic->setPath(path.c_str()); - ai_ballistic->setAltitude(altitude); - ai_ballistic->setLongitude(longitude); - ai_ballistic->setLatitude(latitude); - ai_ballistic->init(); - ai_ballistic->bind(); - return ai_ballistic->getID(); +SGPropertyNode_ptr +FGAIManager::loadScenarioFile(const std::string& filename) +{ + SGPath path(globals->get_fg_root()); + path.append("AI/" + filename + ".xml"); + try { + SGPropertyNode_ptr root = new SGPropertyNode; + readProperties(path.str(), root); + return root; + } catch (const sg_exception &) { + SG_LOG(SG_GENERAL, SG_DEBUG, "Incorrect path specified for AI " + "scenario: \"" << path.str() << "\""); + return 0; + } } -void FGAIManager::destroyObject( int ID ) { - ai_list_itr = ai_list.begin(); - while(ai_list_itr != ai_list.end()) { - if ((*ai_list_itr)->getID() == ID) { - freeID( ID ); - delete (*ai_list_itr); - ai_list.erase(ai_list_itr); - --ai_list_itr; - --numObjects; - return; +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" ) ) { + 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); + std::string type = scEntry->getStringValue("type"); + std::string pnumber = scEntry->getStringValue("pennant-number"); + std::string name = scEntry->getStringValue("name"); + if (type == "carrier" && (pnumber == id || name == id)) { + osg::ref_ptr carrier = new FGAICarrier; + carrier->readFromScenario(scEntry); + + if (carrier->getParkPosition(pid, geodPos, hdng, uvw)) { + found = true; + break; + } + } + } + } } - ++ai_list_itr; } + } + return found; +} + +const FGAIBase * +FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range) +{ + // we specify tgt extent (ft) according to the AIObject type + double tgt_ht[] = {0, 50 ,100, 250, 0, 100, 0, 0, 50, 50, 50}; + double tgt_length[] = {0, 100, 200, 750, 0, 50, 0, 0, 200, 100, 100}; + ai_list_iterator ai_list_itr = ai_list.begin(); + ai_list_iterator end = ai_list.end(); + + while (ai_list_itr != end) { + double tgt_alt = (*ai_list_itr)->_getAltitude(); + int type = (*ai_list_itr)->getType(); + tgt_ht[type] += fuse_range; + + if (fabs(tgt_alt - alt) > tgt_ht[type] || type == FGAIBase::otBallistic + || type == FGAIBase::otStorm || type == FGAIBase::otThermal ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: skipping " + << fabs(tgt_alt - alt) + << " " + << type + ); + ++ai_list_itr; + continue; + } + + double tgt_lat = (*ai_list_itr)->_getLatitude(); + double tgt_lon = (*ai_list_itr)->_getLongitude(); + int id = (*ai_list_itr)->getID(); + + double range = calcRange(lat, lon, tgt_lat, tgt_lon); + + SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: AI list size " + << ai_list.size() + << " type " << type + << " ID " << id + << " range " << range + //<< " bearing " << bearing + << " alt " << tgt_alt + ); + + tgt_length[type] += fuse_range; + + if (range < tgt_length[type]){ + SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: HIT! " + << " type " << type + << " ID " << id + << " range " << range + << " alt " << tgt_alt + ); + return (*ai_list_itr).get(); + } + ++ai_list_itr; + } + return 0; } -// fetch the user's state every 10 sim cycles -void FGAIManager::fetchUserState( void ) { - ++dt_count; - if (dt_count == 10) { - user_latitude = fgGetDouble("/position/latitude-deg"); - user_longitude = fgGetDouble("/position/longitude-deg"); - user_altitude = fgGetDouble("/position/altitude-ft"); - user_heading = fgGetDouble("/orientation/heading-deg"); - user_pitch = fgGetDouble("/orientation/pitch-deg"); - user_yaw = fgGetDouble("/orientation/side-slip-deg"); - user_speed = fgGetDouble("/velocities/uBody-fps") * 0.592484; - dt_count = 0; - } +double +FGAIManager::calcRange(double lat, double lon, double lat2, double lon2) const +{ + double course, az2, distance; + + //calculate the bearing and range of the second pos from the first + geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &az2, &distance); + distance *= SG_METER_TO_FEET; + return distance; } + +//end AIManager.cxx