]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIManager.cxx
Csaba "Jester" HALASZ: radar fix & extension
[flightgear.git] / src / AIModel / AIManager.cxx
1 // AIManager.cxx  Based on David Luff's AIMgr:
2 // - a global management type for AI objects
3 //
4 // Written by David Culp, started October 2003.
5 // - davidculp2@comcast.net
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21 #include <Main/globals.hxx>
22
23 #include <Airports/simple.hxx>
24 #include <Traffic/TrafficMgr.hxx>
25
26 #include "AIManager.hxx"
27 #include "AIAircraft.hxx"
28 #include "AIShip.hxx"
29 #include "AIBallistic.hxx"
30 #include "AIStorm.hxx"
31 #include "AIThermal.hxx"
32 #include "AICarrier.hxx"
33 #include "AIStatic.hxx"
34 #include "AIMultiplayer.hxx"
35
36 FGAIManager::FGAIManager() {
37   _dt = 0.0;
38   mNumAiModels = 0;
39   for (unsigned i = 0; i < FGAIBase::MAX_OBJECTS; ++i)
40     mNumAiTypeModels[i] = 0;
41 }
42
43 FGAIManager::~FGAIManager() {
44   ai_list_iterator ai_list_itr = ai_list.begin();
45   while(ai_list_itr != ai_list.end()) {
46       (*ai_list_itr)->unbind();
47       ++ai_list_itr;
48   }
49 }
50
51
52 void FGAIManager::init() {
53   root = fgGetNode("sim/ai", true);
54
55   enabled = root->getNode("enabled", true)->getBoolValue();
56   if (!enabled)
57       return;
58
59   wind_from_down_node = fgGetNode("/environment/wind-from-down-fps", true);
60   wind_from_east_node  = fgGetNode("/environment/wind-from-east-fps",true);
61   wind_from_north_node = fgGetNode("/environment/wind-from-north-fps",true);
62
63   user_latitude_node  = fgGetNode("/position/latitude-deg", true);
64   user_longitude_node = fgGetNode("/position/longitude-deg", true);
65   user_altitude_node  = fgGetNode("/position/altitude-ft", true);
66   user_heading_node   = fgGetNode("/orientation/heading-deg", true);
67   user_pitch_node     = fgGetNode("/orientation/pitch-deg", true);
68   user_yaw_node       = fgGetNode("/orientation/side-slip-deg", true);
69   user_speed_node     = fgGetNode("/velocities/uBody-fps", true);
70 }
71
72
73 void FGAIManager::postinit() {
74   // postinit, so that it can access the Nasal subsystem
75   for(int i = 0 ; i < root->nChildren() ; i++) {
76     SGPropertyNode *aiEntry = root->getChild( i );
77     if( !strcmp( aiEntry->getName(), "scenario" ) ) {
78       scenario_filename = aiEntry->getStringValue();
79       if (!scenario_filename.empty())
80         processScenario( scenario_filename );
81     }
82   }
83 }
84
85
86 void FGAIManager::reinit() {
87    update(0.0);
88    ai_list_iterator ai_list_itr = ai_list.begin();
89
90    while(ai_list_itr != ai_list.end()) {
91       (*ai_list_itr)->reinit();
92       ++ai_list_itr;
93    }
94 }
95
96
97 void FGAIManager::bind() {
98    root = globals->get_props()->getNode("ai/models", true);
99    root->tie("count", SGRawValueMethods<FGAIManager, int>(*this,
100              &FGAIManager::getNumAiObjects));
101 }
102
103
104 void FGAIManager::unbind() {
105     root->untie("count");
106 }
107
108
109 void FGAIManager::update(double dt) {
110   // initialize these for finding nearest thermals
111   range_nearest = 10000.0;
112   strength = 0.0;
113   if (!enabled)
114     return;
115
116   FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
117   _dt = dt;
118
119   ai_list_iterator ai_list_itr = ai_list.begin();
120   while(ai_list_itr != ai_list.end()) {
121     if ((*ai_list_itr)->getDie()) {      
122       tmgr->release((*ai_list_itr)->getID());
123       --mNumAiModels;
124       --(mNumAiTypeModels[(*ai_list_itr)->getType()]);
125       FGAIBase *base = *ai_list_itr;
126       SGPropertyNode *props = base->_getProps();
127
128       props->setBoolValue("valid", false);
129       base->unbind();
130
131       // for backward compatibility reset properties, so that aircraft,
132       // which don't know the <valid> property, keep working
133       // TODO: remove after a while
134       props->setIntValue("id", -1);
135       props->setBoolValue("radar/in-range", false);
136       props->setIntValue("refuel/tanker", false);
137
138       ai_list_itr = ai_list.erase(ai_list_itr);
139     } else {
140       fetchUserState();
141       if ((*ai_list_itr)->isa(FGAIBase::otThermal)) {
142         FGAIBase *base = *ai_list_itr;
143         processThermal((FGAIThermal*)base); 
144       } else { 
145         (*ai_list_itr)->update(_dt);
146       }
147       ++ai_list_itr;
148     }
149   }
150   wind_from_down_node->setDoubleValue( strength ); // for thermals
151 }
152
153 void
154 FGAIManager::attach(SGSharedPtr<FGAIBase> model)
155 {
156   unsigned idx = mNumAiTypeModels[model->getType()];
157   const char* typeString = model->getTypeString();
158   SGPropertyNode* root = globals->get_props()->getNode("ai/models", true);
159   SGPropertyNode* p;
160   int i;
161   for (i=0;i<10000;i++) //find free index in the property tree, if we have
162       //more than 10000 mp-aircrafts in the property tree we should optimize the mp-server
163   {
164     p = root->getNode(typeString, i, false);
165     if (!p || !p->getBoolValue("valid", false))
166       break;
167     if (p->getIntValue("id",-1)==model->getID()) {
168         p->setStringValue("callsign","***invalid node***"); //debug only, should never set!
169     }
170   }
171   p = root->getNode(typeString, i, true);
172   model->setManager(this, p);
173   ai_list.push_back(model);
174   ++mNumAiModels;
175   ++(mNumAiTypeModels[model->getType()]);
176   model->init(model->getType()==FGAIBase::otAircraft
177       || model->getType()==FGAIBase::otMultiplayer
178       || model->getType()==FGAIBase::otStatic);
179   model->bind();
180   p->setBoolValue("valid", true);
181 }
182
183
184 void FGAIManager::destroyObject( int ID ) {
185   ai_list_iterator ai_list_itr = ai_list.begin();
186   while(ai_list_itr != ai_list.end()) {
187     if ((*ai_list_itr)->getID() == ID) {
188       --mNumAiModels;
189       --(mNumAiTypeModels[(*ai_list_itr)->getType()]);
190       (*ai_list_itr)->unbind();
191       ai_list_itr = ai_list.erase(ai_list_itr);
192     } else
193       ++ai_list_itr;
194   }
195 }
196
197 int
198 FGAIManager::getNumAiObjects(void) const
199 {
200   return mNumAiModels;
201 }
202
203 void FGAIManager::fetchUserState( void ) {
204      user_latitude  = user_latitude_node->getDoubleValue();
205      user_longitude = user_longitude_node->getDoubleValue();
206      user_altitude  = user_altitude_node->getDoubleValue();
207      user_heading   = user_heading_node->getDoubleValue();
208      user_pitch     = user_pitch_node->getDoubleValue();
209      user_yaw       = user_yaw_node->getDoubleValue();
210      user_speed     = user_speed_node->getDoubleValue() * 0.592484;
211      wind_from_east = wind_from_east_node->getDoubleValue();
212      wind_from_north = wind_from_north_node->getDoubleValue();
213 }
214
215
216 // only keep the results from the nearest thermal
217 void FGAIManager::processThermal( FGAIThermal* thermal ) {
218   thermal->update(_dt);
219   if ( thermal->_getRange() < range_nearest ) {
220      range_nearest = thermal->_getRange();
221      strength = thermal->getStrength();
222   }
223 }
224
225
226 void FGAIManager::processScenario( const string &filename ) {
227
228   SGPropertyNode_ptr scenarioTop = loadScenarioFile(filename);
229   if (!scenarioTop)
230     return;
231   SGPropertyNode* scenarios = scenarioTop->getChild("scenario");
232   if (!scenarios)
233     return;
234
235   for (int i = 0; i < scenarios->nChildren(); i++) { 
236     SGPropertyNode* scEntry = scenarios->getChild(i);
237     if (strcmp(scEntry->getName(), "entry"))
238       continue;
239     std::string type = scEntry->getStringValue("type", "aircraft");
240
241     if (type == "aircraft") {
242       FGAIAircraft* aircraft = new FGAIAircraft;
243       aircraft->readFromScenario(scEntry);
244       attach(aircraft);
245
246     } else if (type == "ship") {
247       FGAIShip* ship = new FGAIShip;
248       ship->readFromScenario(scEntry);
249       attach(ship);
250       
251     } else if (type == "carrier") {
252       FGAICarrier* carrier = new FGAICarrier;
253       carrier->readFromScenario(scEntry);
254       attach(carrier);
255       
256     } else if (type == "thunderstorm") {
257       FGAIStorm* storm = new FGAIStorm;
258       storm->readFromScenario(scEntry);
259       attach(storm);
260       
261     } else if (type == "thermal") {
262       FGAIThermal* thermal = new FGAIThermal;
263       thermal->readFromScenario(scEntry);
264       attach(thermal);
265       
266     } else if (type == "ballistic") {
267       FGAIBallistic* ballistic = new FGAIBallistic;
268       ballistic->readFromScenario(scEntry);
269       attach(ballistic);
270       
271     } else if (type == "static") {
272       FGAIStatic* aistatic = new FGAIStatic;
273       aistatic->readFromScenario(scEntry);
274       attach(aistatic);
275       
276     }
277   }
278 }
279
280 SGPropertyNode_ptr
281 FGAIManager::loadScenarioFile(const std::string& filename)
282 {
283   SGPath path(globals->get_fg_root());
284   path.append("AI/" + filename + ".xml");
285   try {
286     SGPropertyNode_ptr root = new SGPropertyNode;
287     readProperties(path.str(), root);
288     return root;
289   } catch (const sg_exception &e) {
290     SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path specified for AI "
291            "scenario: \"" << path.str() << "\"");
292     return 0;
293   }
294 }
295
296 bool FGAIManager::getStartPosition(const string& id, const string& pid,
297                                    SGGeod& geodPos, double& hdng, SGVec3d& uvw)
298 {
299   bool found = false;
300   SGPropertyNode* root = fgGetNode("sim/ai", true);
301   if (!root->getNode("enabled", true)->getBoolValue())
302       return found;
303
304   for(int i = 0 ; (!found) && i < root->nChildren() ; i++) {
305     SGPropertyNode *aiEntry = root->getChild( i );
306     if( !strcmp( aiEntry->getName(), "scenario" ) ) {
307       string filename = aiEntry->getStringValue();
308       SGPropertyNode_ptr scenarioTop = loadScenarioFile(filename);
309       if (scenarioTop) {
310         SGPropertyNode* scenarios = scenarioTop->getChild("scenario");
311         if (scenarios) {
312           for (int i = 0; i < scenarios->nChildren(); i++) { 
313             SGPropertyNode* scEntry = scenarios->getChild(i);
314             std::string type = scEntry->getStringValue("type");
315             std::string pnumber = scEntry->getStringValue("pennant-number");
316             std::string name = scEntry->getStringValue("name");
317             if (type == "carrier" && (pnumber == id || name == id)) {
318               SGSharedPtr<FGAICarrier> carrier = new FGAICarrier;
319               carrier->readFromScenario(scEntry);
320               
321               if (carrier->getParkPosition(pid, geodPos, hdng, uvw)) {
322                 found = true;
323                 break;
324               }
325             }
326           }
327         }
328       }
329     }
330   }
331   return found;
332 }
333
334 //end AIManager.cxx