]> git.mxchange.org Git - flightgear.git/blob - src/Network/HLA/hla.cxx
Fix Linux compile / math dependency
[flightgear.git] / src / Network / HLA / hla.cxx
1 //
2 // Copyright (C) 2009 - 2010  Mathias Fröhlich <Mathias.Froehlich@web.de>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License as
6 // published by the Free Software Foundation; either version 2 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "hla.hxx"
24
25 #include <simgear/compiler.h>
26
27 #include <string>
28
29 #include <map>
30 #include <string>
31 #include <stack>
32
33 #include <simgear/debug/logstream.hxx>
34 #include <simgear/math/SGMath.hxx>
35 #include <simgear/misc/sg_path.hxx>
36 #include <simgear/props/props.hxx>
37 #include <simgear/structure/exception.hxx>
38 #include <simgear/xml/easyxml.hxx>
39
40 #include <simgear/hla/HLAFederate.hxx>
41 #include <simgear/hla/HLAArrayDataElement.hxx>
42 #include <simgear/hla/HLADataElement.hxx>
43 #include <simgear/hla/HLADataType.hxx>
44 #include <simgear/hla/HLALocation.hxx>
45 #include <simgear/hla/HLAObjectClass.hxx>
46 #include <simgear/hla/HLAObjectInstance.hxx>
47 #include <simgear/hla/HLAPropertyDataElement.hxx>
48 #include <simgear/hla/HLAVariantRecordDataElement.hxx>
49
50 #include <AIModel/AIMultiplayer.hxx>
51 #include <AIModel/AIManager.hxx>
52
53 #include <FDM/flightProperties.hxx>
54
55 #include <Main/fg_props.hxx>
56 #include <Main/globals.hxx>
57
58 // FIXME rename HLAMP
59 // FIXME make classes here private ...
60
61 namespace sg = simgear;
62
63 enum HLAVersion {
64     RTI13,
65     RTI1516,
66     RTI1516E
67 };
68
69 class FGHLA::XMLConfigReader : public XMLVisitor {
70 public:
71     XMLConfigReader() :
72         _rtiVersion(RTI13)
73     { }
74
75     const std::string& getFederateObjectModel() const
76     { return _federateObjectModel; }
77
78     HLAVersion getRTIVersion() const
79     { return _rtiVersion; }
80     const std::list<std::string>& getRTIArguments() const
81     { return _rtiArguments; }
82
83     struct DataElement {
84         std::string _type;
85         std::string _name;
86         std::string _inProperty;
87         std::string _outProperty;
88     };
89     typedef std::list<DataElement> DataElementList;
90     struct ModelConfig {
91         std::string _type;
92         DataElementList _dataElementList;
93         std::list<std::pair<std::string, std::string> > _modelMap;
94     };
95     struct SimTimeConfig {
96         std::string _type;
97         DataElementList _dataElementList;
98     };
99     struct PositionConfig {
100         std::string _type;
101         DataElementList _dataElementList;
102     };
103     struct MPPropertiesConfig {
104         std::string _name;
105     };
106     struct ObjectClassConfig {
107         std::string _name;
108         std::string _type;
109         ModelConfig _modelConfig;
110         SimTimeConfig _simTimeConfig;
111         PositionConfig _positionConfig;
112         MPPropertiesConfig _mpPropertiesConfig;
113         DataElementList _dataElementList;
114     };
115     typedef std::list<ObjectClassConfig> ObjectClassConfigList;
116
117     const ObjectClassConfigList& getObjectClassConfigList() const
118     { return _objectClassConfigList; }
119
120 protected:
121     virtual void startXML()
122     {
123         _modeStack.push(TopLevelMode);
124     }
125     virtual void endXML()
126     {
127         _modeStack.pop();
128     }
129     virtual void startElement(const char* name, const XMLAttributes& atts)
130     {
131         if (strcmp(name, "hlaConfiguration") == 0) {
132             if (!isModeStackTop(TopLevelMode))
133                 throw sg_exception("hlaConfiguration tag not at top level");
134
135             _modeStack.push(HLAConfigurationMode);
136         }
137
138         else if (strcmp(name, "rti") == 0) {
139             if (!isModeStackTop(HLAConfigurationMode))
140                 throw sg_exception("rti tag not at top level");
141
142             std::string rtiVersion = getAttribute("version", atts);
143             if (rtiVersion == "RTI13")
144                 _rtiVersion = RTI13;
145             else if (rtiVersion == "RTI1516")
146                 _rtiVersion = RTI1516;
147             else if (rtiVersion == "RTI1516E")
148                 _rtiVersion = RTI1516E;
149             else
150                 throw sg_exception("invalid version attribute in rti tag");
151
152             _modeStack.push(RTIMode);
153         }
154         else if (strcmp(name, "argument") == 0) {
155             if (!isModeStackTop(RTIMode))
156                 throw sg_exception("argument tag not inside an rti tag");
157
158             _modeStack.push(RTIArgumentMode);
159             _rtiArguments.push_back(std::string());
160         }
161
162         else if (strcmp(name, "objects") == 0) {
163             if (!isModeStackTop(HLAConfigurationMode))
164                 throw sg_exception("objects tag not at top level");
165
166             _modeStack.push(ObjectsMode);
167         }
168         else if (strcmp(name, "objectClass") == 0) {
169             // Currently this is flat and only allows one class to be configured
170             if (!isModeStackTop(ObjectsMode))
171                 throw sg_exception("objects tag not inside an objects tag");
172             if (!_objectClassConfigList.empty())
173                 throw sg_exception("currently only one objectClass is allowed");
174             // if (!isModeStackTop(ObjectsMode) && !isModeStackTop(ObjectClassMode))
175             //     throw sg_exception("objects tag not inside an objects or objectClass tag");
176
177             ObjectClassConfig objectClassConfig;
178             objectClassConfig._type = getAttribute("type", atts);
179             objectClassConfig._name = getAttribute("name", atts);
180             _objectClassConfigList.push_back(objectClassConfig);
181
182             _modeStack.push(ObjectClassMode);
183         }
184         else if (strcmp(name, "model") == 0) {
185             if (!isModeStackTop(ObjectClassMode))
186                 throw sg_exception("position tag not inside an objectClass tag");
187
188             _objectClassConfigList.back()._modelConfig._type = getAttribute("type", atts);
189
190             _modeStack.push(ModelMode);
191         }
192         else if (strcmp(name, "key") == 0) {
193             if (!isModeStackTop(ModelMode))
194                 throw sg_exception("key tag not inside an model tag");
195
196             std::pair<std::string,std::string> p;
197             p.first = getAttribute("external", atts);
198             p.second = getAttribute("modelPath", atts);
199             _objectClassConfigList.back()._modelConfig._modelMap.push_back(p);
200
201             _modeStack.push(KeyMode);
202         }
203         else if (strcmp(name, "simTime") == 0) {
204             if (!isModeStackTop(ObjectClassMode))
205                 throw sg_exception("simTime tag not inside an objectClass tag");
206
207             _objectClassConfigList.back()._simTimeConfig._type = getAttribute("type", atts);
208
209             _modeStack.push(SimTimeMode);
210         }
211         else if (strcmp(name, "position") == 0) {
212             if (!isModeStackTop(ObjectClassMode))
213                 throw sg_exception("position tag not inside an objectClass tag");
214
215             _objectClassConfigList.back()._positionConfig._type = getAttribute("type", atts);
216
217             _modeStack.push(PositionMode);
218         }
219         else if (strcmp(name, "mpProperties") == 0) {
220             if (!isModeStackTop(ObjectClassMode))
221                 throw sg_exception("mpProperties tag not inside an objectClass tag");
222
223             _objectClassConfigList.back()._mpPropertiesConfig._name = getAttribute("name", atts);
224
225             _modeStack.push(MPPropertiesMode);
226         }
227         else if (strcmp(name, "dataElement") == 0) {
228
229             DataElement dataElement;
230             dataElement._type = getAttribute("type", atts);
231             dataElement._name = getAttribute("name", atts);
232             if (isModeStackTop(ModelMode)) {
233                 _objectClassConfigList.back()._modelConfig._dataElementList.push_back(dataElement);
234             } else if (isModeStackTop(SimTimeMode)) {
235                 _objectClassConfigList.back()._simTimeConfig._dataElementList.push_back(dataElement);
236             } else if (isModeStackTop(PositionMode)) {
237                 _objectClassConfigList.back()._positionConfig._dataElementList.push_back(dataElement);
238             } else if (isModeStackTop(ObjectClassMode)) {
239                 std::string io = getAttribute("io", atts);
240                 dataElement._inProperty = getAttribute("in", atts);
241                 if (dataElement._inProperty.empty())
242                     dataElement._inProperty = io;
243                 dataElement._outProperty = getAttribute("out", atts);
244                 if (dataElement._outProperty.empty())
245                     dataElement._outProperty = io;
246                 _objectClassConfigList.back()._dataElementList.push_back(dataElement);
247             } else {
248                 throw sg_exception("dataElement tag not inside a position, model or objectClass tag");
249             }
250
251             _modeStack.push(DataElementMode);
252         }
253
254         else if (strcmp(name, "federateObjectModel") == 0) {
255             if (!isModeStackTop(HLAConfigurationMode))
256                 throw sg_exception("federateObjectModel tag not at top level");
257
258             _federateObjectModel = getAttribute("name", atts);
259             _modeStack.push(FederateObjectModelMode);
260         }
261
262         else {
263             throw sg_exception(std::string("Unknown tag ") + name);
264         }
265     }
266
267     virtual void data(const char * s, int length)
268     {
269         if (isModeStackTop(RTIArgumentMode)) {
270             _rtiArguments.back().append(s, length);
271         }
272     }
273
274     virtual void endElement(const char* name)
275     {
276         _modeStack.pop();
277     }
278
279     std::string getAttribute(const char* name, const XMLAttributes& atts)
280     {
281         int index = atts.findAttribute(name);
282         if (index < 0 || atts.size() <= index)
283             return std::string();
284         return std::string(atts.getValue(index));
285     }
286     std::string getAttribute(const std::string& name, const XMLAttributes& atts)
287     {
288         int index = atts.findAttribute(name.c_str());
289         if (index < 0 || atts.size() <= index)
290             return std::string();
291         return std::string(atts.getValue(index));
292     }
293
294 private:
295     // poor peoples xml validation ...
296     enum Mode {
297         TopLevelMode,
298         HLAConfigurationMode,
299         RTIMode,
300         RTIArgumentMode,
301         ObjectsMode,
302         ObjectClassMode,
303         ModelMode,
304         KeyMode,
305         SimTimeMode,
306         PositionMode,
307         MPPropertiesMode,
308         DataElementMode,
309         FederateObjectModelMode
310     };
311     bool isModeStackTop(Mode mode)
312     {
313         if (_modeStack.empty())
314             return false;
315         return _modeStack.top() == mode;
316     }
317     std::stack<Mode> _modeStack;
318
319     std::string _federateObjectModel;
320     HLAVersion _rtiVersion;
321     std::list<std::string> _rtiArguments;
322
323     ObjectClassConfigList _objectClassConfigList;
324 };
325
326 class PropertyReferenceSet : public SGReferenced {
327 public:
328     void insert(const std::string& relativePath, const SGSharedPtr<sg::HLAPropertyDataElement>& dataElement)
329     {
330         if (_rootNode.valid())
331             dataElement->setPropertyNode(_rootNode->getNode(relativePath, true));
332         _pathDataElementPairList.push_back(PathDataElementPair(relativePath, dataElement));
333     }
334
335     void setRootNode(SGPropertyNode* rootNode)
336     {
337         _rootNode = rootNode;
338         for (PathDataElementPairList::iterator i = _pathDataElementPairList.begin();
339              i != _pathDataElementPairList.end(); ++i) {
340             i->second->setPropertyNode(_rootNode->getNode(i->first, true));
341         }
342     }
343     SGPropertyNode* getRootNode()
344     { return _rootNode.get(); }
345
346 private:
347     SGSharedPtr<SGPropertyNode> _rootNode;
348
349     typedef std::pair<std::string, SGSharedPtr<sg::HLAPropertyDataElement> > PathDataElementPair;
350     typedef std::list<PathDataElementPair> PathDataElementPairList;
351     PathDataElementPairList _pathDataElementPairList;
352 };
353
354 class AbstractSimTime : public SGReferenced {
355 public:
356     virtual ~AbstractSimTime() {}
357
358     virtual double getTimeStamp() const = 0;
359     virtual void setTimeStamp(double) = 0;
360 };
361
362 class SimTimeFactory : public SGReferenced {
363 public:
364     virtual ~SimTimeFactory() {}
365     virtual AbstractSimTime* createSimTime(sg::HLAAttributePathElementMap&) const = 0;
366 };
367
368 // A SimTime implementation that works with the simulation
369 // time in an attribute. Used when we cannot do real time management.
370 class AttributeSimTime : public AbstractSimTime {
371 public:
372
373     virtual double getTimeStamp() const
374     { return _simTime; }
375     virtual void setTimeStamp(double simTime)
376     { _simTime = simTime; }
377
378     sg::HLADataElement* getDataElement()
379     { return _simTime.getDataElement(); }
380
381 private:
382     simgear::HLADoubleData _simTime;
383 };
384
385 class AttributeSimTimeFactory : public SimTimeFactory {
386 public:
387     virtual AttributeSimTime* createSimTime(sg::HLAAttributePathElementMap& attributePathElementMap) const
388     {
389         AttributeSimTime* attributeSimTime = new AttributeSimTime;
390         attributePathElementMap[_simTimeIndexPathPair.first][_simTimeIndexPathPair.second] = attributeSimTime->getDataElement();
391         return attributeSimTime;
392     }
393
394     void setSimTimeIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
395     { _simTimeIndexPathPair = indexPathPair; }
396
397 private:
398     sg::HLADataElement::IndexPathPair _simTimeIndexPathPair;
399 };
400
401 // A SimTime implementation that works with the simulation
402 // time in two attributes like the avation sim net fom works
403 class MSecAttributeSimTime : public AbstractSimTime {
404 public:
405     virtual double getTimeStamp() const
406     {
407         return _secSimTime + 1e-3*_msecSimTime;
408     }
409     virtual void setTimeStamp(double simTime)
410     {
411         double sec = floor(simTime);
412         _secSimTime = sec;
413         _msecSimTime = 1e3*(simTime - sec);
414     }
415
416     sg::HLADataElement* getSecDataElement()
417     { return _secSimTime.getDataElement(); }
418     sg::HLADataElement* getMSecDataElement()
419     { return _msecSimTime.getDataElement(); }
420
421 private:
422     simgear::HLADoubleData _secSimTime;
423     simgear::HLADoubleData _msecSimTime;
424 };
425
426 class MSecAttributeSimTimeFactory : public SimTimeFactory {
427 public:
428     virtual MSecAttributeSimTime* createSimTime(sg::HLAAttributePathElementMap& attributePathElementMap) const
429     {
430         MSecAttributeSimTime* attributeSimTime = new MSecAttributeSimTime;
431         attributePathElementMap[_secIndexPathPair.first][_secIndexPathPair.second] = attributeSimTime->getSecDataElement();
432         attributePathElementMap[_msecIndexPathPair.first][_msecIndexPathPair.second] = attributeSimTime->getMSecDataElement();
433         return attributeSimTime;
434     }
435
436     void setSecIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
437     { _secIndexPathPair = indexPathPair; }
438     void setMSecIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
439     { _msecIndexPathPair = indexPathPair; }
440
441 private:
442     sg::HLADataElement::IndexPathPair _secIndexPathPair;
443     sg::HLADataElement::IndexPathPair _msecIndexPathPair;
444 };
445
446 class AbstractModel : public SGReferenced {
447 public:
448     virtual ~AbstractModel() {}
449
450     virtual std::string getModelPath() const = 0;
451     virtual void setModelPath(const std::string&) = 0;
452 };
453
454 class ModelFactory : public SGReferenced {
455 public:
456     virtual ~ModelFactory() {}
457     virtual AbstractModel* createModel(sg::HLAAttributePathElementMap&, bool) const = 0;
458 };
459
460 class AttributeModel : public AbstractModel {
461 public:
462     virtual std::string getModelPath() const
463     { return _modelPath; }
464     virtual void setModelPath(const std::string& modelPath)
465     { _modelPath = modelPath; }
466
467     sg::HLADataElement* getDataElement()
468     { return _modelPath.getDataElement(); }
469
470 private:
471     simgear::HLAStringData _modelPath;
472 };
473
474 class AttributeModelFactory : public ModelFactory {
475 public:
476     virtual AttributeModel* createModel(sg::HLAAttributePathElementMap& attributePathElementMap, bool outgoing) const
477     {
478         AttributeModel* attributeModel = new AttributeModel;
479         attributePathElementMap[_modelIndexPathPair.first][_modelIndexPathPair.second] = attributeModel->getDataElement();
480         if (outgoing)
481             attributeModel->setModelPath(fgGetString("/sim/model/path", "default"));
482         return attributeModel;
483     }
484
485     void setModelIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
486     { _modelIndexPathPair = indexPathPair; }
487
488 private:
489     sg::HLADataElement::IndexPathPair _modelIndexPathPair;
490 };
491
492 class AttributeMapModelFactory : public ModelFactory {
493 public:
494     class Model : public AbstractModel {
495     public:
496         Model(const AttributeMapModelFactory* mapModelFactory) :
497             _mapModelFactory(mapModelFactory)
498         { }
499
500         virtual std::string getModelPath() const
501         {
502             if (_modelPath.getValue().empty())
503                 return _modelPath.getValue();
504             return _mapModelFactory->mapToFlightgear(_modelPath);
505         }
506         virtual void setModelPath(const std::string& modelPath)
507         { _modelPath = _mapModelFactory->mapToExternal(modelPath); }
508
509         sg::HLADataElement* getDataElement()
510         { return _modelPath.getDataElement(); }
511
512     private:
513         simgear::HLAStringData _modelPath;
514         SGSharedPtr<const AttributeMapModelFactory> _mapModelFactory;
515     };
516
517     virtual AbstractModel* createModel(sg::HLAAttributePathElementMap& attributePathElementMap, bool outgoing) const
518     {
519         Model* attributeModel = new Model(this);
520         attributePathElementMap[_modelIndexPathPair.first][_modelIndexPathPair.second] = attributeModel->getDataElement();
521         if (outgoing)
522             attributeModel->setModelPath(fgGetString("/sim/model/path", "default"));
523         return attributeModel;
524     }
525
526     void setModelIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
527     { _modelIndexPathPair = indexPathPair; }
528
529     std::string mapToFlightgear(const std::string& externalModel) const
530     {
531         std::map<std::string,std::string>::const_iterator i;
532         i = _externalToModelPathMap.find(externalModel);
533         if (i != _externalToModelPathMap.end())
534             return i->second;
535         return "default";
536     }
537     std::string mapToExternal(const std::string& modelPath) const
538     {
539         std::map<std::string,std::string>::const_iterator i;
540         i = _modelPathToExternalMap.find(modelPath);
541         if (i != _modelPathToExternalMap.end())
542             return i->second;
543         return _externalDefault;
544     }
545
546     void setExternalDefault(const std::string& externalDefault)
547     { _externalDefault = externalDefault; }
548     void addExternalModelPathPair(const std::string& external, const std::string& modelPath)
549     {
550         _externalToModelPathMap[external] = modelPath;
551         _modelPathToExternalMap[modelPath] = external;
552     }
553
554 private:
555     sg::HLADataElement::IndexPathPair _modelIndexPathPair;
556     std::map<std::string,std::string> _externalToModelPathMap;
557     std::map<std::string,std::string> _modelPathToExternalMap;
558     std::string _externalDefault;
559 };
560
561 // Factory class that is used to create an apternative data element for the multiplayer property attribute
562 class MPPropertyVariantRecordDataElementFactory : public sg::HLAVariantArrayDataElement::AlternativeDataElementFactory {
563 public:
564     MPPropertyVariantRecordDataElementFactory(PropertyReferenceSet* propertyReferenceSet) :
565         _propertyReferenceSet(propertyReferenceSet)
566     { }
567
568     virtual sg::HLADataElement* createElement(const sg::HLAVariantRecordDataElement& variantRecordDataElement, unsigned index)
569     {
570         const sg::HLAVariantRecordDataType* dataType = variantRecordDataElement.getDataType();
571         if (!dataType)
572             return 0;
573         const sg::HLAEnumeratedDataType* enumDataType = dataType->getEnumeratedDataType();
574         if (!enumDataType)
575             return 0;
576         const sg::HLADataType* alternativeDataType = dataType->getAlternativeDataType(index);
577         if (!alternativeDataType)
578             return 0;
579
580         // The relative property path should be in the semantics field name
581         std::string relativePath = dataType->getAlternativeSemantics(index);
582         sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement(alternativeDataType, (SGPropertyNode*)0);
583         _propertyReferenceSet->insert(relativePath, dataElement);
584         return dataElement;
585     }
586
587 private:
588     SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
589 };
590
591 class MPAttributeCallback : public sg::HLAObjectInstance::AttributeCallback {
592 public:
593     MPAttributeCallback() :
594         _propertyReferenceSet(new PropertyReferenceSet),
595         _mpProperties(new sg::HLAVariantArrayDataElement)
596     {
597         _mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantRecordDataElementFactory(_propertyReferenceSet.get()));
598     }
599     virtual ~MPAttributeCallback()
600     { }
601
602     void setLocation(sg::HLAAbstractLocation* location)
603     { _location = location; }
604     sg::HLAAbstractLocation* getLocation()
605     { return _location.get(); }
606     const sg::HLAAbstractLocation* getLocation() const
607     { return _location.get(); }
608
609     void setModel(AbstractModel* model)
610     { _model = model; }
611     AbstractModel* getModel()
612     { return _model.get(); }
613     const AbstractModel* getModel() const
614     { return _model.get(); }
615
616     void setSimTime(AbstractSimTime* simTime)
617     { _simTime = simTime; }
618     AbstractSimTime* getSimTime()
619     { return _simTime.get(); }
620     const AbstractSimTime* getSimTime() const
621     { return _simTime.get(); }
622
623     sg::HLAVariantArrayDataElement* getMPProperties() const
624     { return _mpProperties.get(); }
625
626     SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
627
628 protected:
629     SGSharedPtr<sg::HLAAbstractLocation> _location;
630     SGSharedPtr<AbstractSimTime> _simTime;
631     SGSharedPtr<AbstractModel> _model;
632     SGSharedPtr<sg::HLAVariantArrayDataElement> _mpProperties;
633 };
634
635 class MPOutAttributeCallback : public MPAttributeCallback {
636 public:
637     virtual void updateAttributeValues(sg::HLAObjectInstance&, const sg::RTIData&)
638     {
639         _simTime->setTimeStamp(globals->get_sim_time_sec());
640
641         SGGeod position = ifce.getPosition();
642         // The quaternion rotating from the earth centered frame to the
643         // horizontal local frame
644         SGQuatd qEc2Hl = SGQuatd::fromLonLat(position);
645         SGQuatd hlOr = SGQuatd::fromYawPitchRoll(ifce.get_Psi(), ifce.get_Theta(), ifce.get_Phi());
646         _location->setCartPosition(SGVec3d::fromGeod(position));
647         _location->setCartOrientation(qEc2Hl*hlOr);
648         // The angular velocitied in the body frame
649         double p = ifce.get_P_body();
650         double q = ifce.get_Q_body();
651         double r = ifce.get_R_body();
652         _location->setAngularBodyVelocity(SGVec3d(p, q, r));
653         // The body uvw velocities in the interface are wrt the wind instead
654         // of wrt the ec frame
655         double n = ifce.get_V_north();
656         double e = ifce.get_V_east();
657         double d = ifce.get_V_down();
658         _location->setLinearBodyVelocity(hlOr.transform(SGVec3d(n, e, d)));
659
660         if (_mpProperties.valid() && _mpProperties->getNumElements() == 0) {
661             if (_propertyReferenceSet.valid() && _propertyReferenceSet->getRootNode()) {
662                 const sg::HLADataType* elementDataType = _mpProperties->getElementDataType();
663                 const sg::HLAVariantRecordDataType* variantRecordDataType = elementDataType->toVariantRecordDataType();
664                 for (unsigned i = 0, count = 0; i < variantRecordDataType->getNumAlternatives(); ++i) {
665                     std::string name = variantRecordDataType->getAlternativeSemantics(i);
666                     SGPropertyNode* node = _propertyReferenceSet->getRootNode()->getNode(name);
667                     if (!node)
668                         continue;
669                     _mpProperties->getOrCreateElement(count++)->setAlternativeIndex(i);
670                 }
671             }
672         }
673     }
674
675 private:
676     FlightProperties ifce;
677 };
678
679 class MPInAttributeCallback : public MPAttributeCallback {
680 public:
681     virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance,
682                                         const sg::RTIIndexDataPairList&, const sg::RTIData&)
683     {
684         // Puh, damn ordering problems with properties startup and so on
685         if (_aiMultiplayer.valid()) {
686             FGExternalMotionData motionInfo;
687             motionInfo.time = _simTime->getTimeStamp();
688             motionInfo.lag = 0;
689
690             motionInfo.position = _location->getCartPosition();
691             motionInfo.orientation = toQuatf(_location->getCartOrientation());
692             motionInfo.linearVel = toVec3f(_location->getLinearBodyVelocity());
693             motionInfo.angularVel = toVec3f(_location->getAngularBodyVelocity());
694             motionInfo.linearAccel = SGVec3f::zeros();
695             motionInfo.angularAccel = SGVec3f::zeros();
696
697             _aiMultiplayer->addMotionInfo(motionInfo, SGTimeStamp::now().getSeconds());
698
699         } else {
700             std::string modelPath = _model->getModelPath();
701             if (modelPath.empty())
702                 return;
703             FGAIManager *aiMgr;
704             aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
705             if (!aiMgr)
706                 return;
707
708             _aiMultiplayer = new FGAIMultiplayer;
709             _aiMultiplayer->setPath(modelPath.c_str());
710             aiMgr->attach(_aiMultiplayer.get());
711
712             _propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
713         }
714     }
715
716     void setDie()
717     {
718         if (!_aiMultiplayer.valid())
719             return;
720         _aiMultiplayer->setDie(true);
721         _aiMultiplayer = 0;
722     }
723
724 private:
725     SGSharedPtr<FGAIMultiplayer> _aiMultiplayer;
726 };
727
728
729 class MpClassCallback : public sg::HLAObjectClass::InstanceCallback {
730 public:
731     MpClassCallback()
732     { }
733     virtual ~MpClassCallback()
734     { }
735
736     virtual void discoverInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
737     {
738         MPInAttributeCallback* attributeCallback = new MPInAttributeCallback;
739         objectInstance.setAttributeCallback(attributeCallback);
740         attachDataElements(objectInstance, *attributeCallback, false);
741     }
742
743     virtual void removeInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
744     {
745         MPInAttributeCallback* attributeCallback;
746         attributeCallback = dynamic_cast<MPInAttributeCallback*>(objectInstance.getAttributeCallback().get());
747         if (!attributeCallback) {
748             SG_LOG(SG_IO, SG_WARN, "HLA: expected to have a different attribute callback in remove instance.");
749             return;
750         }
751         attributeCallback->setDie();
752     }
753
754     virtual void registerInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance)
755     {
756         MPOutAttributeCallback* attributeCallback = new MPOutAttributeCallback;
757         objectInstance.setAttributeCallback(attributeCallback);
758         attachDataElements(objectInstance, *attributeCallback, true);
759         attributeCallback->_propertyReferenceSet->setRootNode(fgGetNode("/", true));
760     }
761
762     virtual void deleteInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance)
763     {
764     }
765
766     void setLocationFactory(sg::HLALocationFactory* locationFactory)
767     { _locationFactory = locationFactory; }
768     sg::HLALocationFactory* getLocationFactory()
769     { return _locationFactory.get(); }
770
771     void setSimTimeFactory(SimTimeFactory* simTimeFactory)
772     { _simTimeFactory = simTimeFactory; }
773     SimTimeFactory* getSimTimeFactory()
774     { return _simTimeFactory.get(); }
775
776     void setModelFactory(ModelFactory* modelFactory)
777     { _modelFactory = modelFactory; }
778     ModelFactory* getModelFactory()
779     { return _modelFactory.get(); }
780
781     void setMPPropertiesIndexPathPair(const sg::HLADataElement::IndexPathPair& indexPathPair)
782     { _mpPropertiesIndexPathPair = indexPathPair; }
783     const sg::HLADataElement::IndexPathPair& getMPPropertiesIndexPathPair() const
784     { return _mpPropertiesIndexPathPair; }
785
786     typedef std::map<sg::HLADataElement::Path, std::string> PathPropertyMap;
787     typedef std::map<unsigned, PathPropertyMap> AttributePathPropertyMap;
788
789     void setInputProperty(const sg::HLADataElement::IndexPathPair& indexPathPair, const std::string& property)
790     {
791         _inputProperties[indexPathPair.first][indexPathPair.second] = property;
792     }
793     void setOutputProperty(const sg::HLADataElement::IndexPathPair& indexPathPair, const std::string& property)
794     {
795         _outputProperties[indexPathPair.first][indexPathPair.second] = property;
796     }
797
798 private:
799     void attachDataElements(sg::HLAObjectInstance& objectInstance, MPAttributeCallback& attributeCallback, bool outgoing)
800     {
801         sg::HLAAttributePathElementMap attributePathElementMap;
802
803         if (_locationFactory.valid())
804             attributeCallback.setLocation(_locationFactory->createLocation(attributePathElementMap));
805         if (_modelFactory.valid())
806             attributeCallback.setModel(_modelFactory->createModel(attributePathElementMap, outgoing));
807         if (_simTimeFactory.valid())
808             attributeCallback.setSimTime(_simTimeFactory->createSimTime(attributePathElementMap));
809
810         attributePathElementMap[_mpPropertiesIndexPathPair.first][_mpPropertiesIndexPathPair.second] = attributeCallback.getMPProperties();
811
812         if (outgoing)
813             attachPropertyDataElements(*attributeCallback._propertyReferenceSet,
814                                        attributePathElementMap, _outputProperties);
815         else
816             attachPropertyDataElements(*attributeCallback._propertyReferenceSet,
817                                        attributePathElementMap, _inputProperties);
818
819         objectInstance.setAttributes(attributePathElementMap);
820     }
821     void attachPropertyDataElements(PropertyReferenceSet& propertyReferenceSet,
822                                     sg::HLAAttributePathElementMap& attributePathElementMap,
823                                     const AttributePathPropertyMap& attributePathPropertyMap)
824     {
825         for (AttributePathPropertyMap::const_iterator i = attributePathPropertyMap.begin();
826              i != attributePathPropertyMap.end(); ++i) {
827             for (PathPropertyMap::const_iterator j = i->second.begin();
828                  j != i->second.end(); ++j) {
829                 sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement;
830                 propertyReferenceSet.insert(j->second, dataElement);
831                 attributePathElementMap[i->first][j->first] = dataElement;
832             }
833         }
834     }
835
836     AttributePathPropertyMap _inputProperties;
837     AttributePathPropertyMap _outputProperties;
838
839     SGSharedPtr<sg::HLALocationFactory> _locationFactory;
840     SGSharedPtr<SimTimeFactory> _simTimeFactory;
841     SGSharedPtr<ModelFactory> _modelFactory;
842
843     sg::HLADataElement::IndexPathPair _mpPropertiesIndexPathPair;
844 };
845
846 class FGHLA::Federate : public sg::HLAFederate {
847 public:
848     virtual ~Federate()
849     { }
850     virtual bool readObjectModel()
851     { return readRTI1516ObjectModelTemplate(getFederationObjectModel()); }
852 };
853
854 FGHLA::FGHLA(const std::vector<std::string>& tokens) :
855     _hlaFederate(new Federate)
856 {
857     if (1 < tokens.size() && !tokens[1].empty())
858         set_direction(tokens[1]);
859     else
860         set_direction("bi");
861
862     int rate = 60;
863     if (2 < tokens.size() && !tokens[2].empty()) {
864         std::stringstream ss(tokens[2]);
865         ss >> rate;
866     }
867     set_hz(rate);
868
869     if (3 < tokens.size() && !tokens[3].empty())
870         _federate = tokens[3];
871     else
872         _federate = fgGetString("/sim/user/callsign");
873
874     if (4 < tokens.size() && !tokens[4].empty())
875         _federation = tokens[4];
876     else
877         _federation = "FlightGear";
878
879     if (5 < tokens.size() && !tokens[5].empty())
880         _objectModelConfig = tokens[5];
881     else
882         _objectModelConfig = "mp-aircraft.xml";
883 }
884
885 FGHLA::~FGHLA()
886 {
887 }
888
889 bool
890 FGHLA::open()
891 {
892     if (is_enabled()) {
893         SG_LOG(SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
894                 "is already in use, ignoring");
895         return false;
896     }
897
898     if (_federation.empty()) {
899         SG_LOG(SG_IO, SG_ALERT, "No federation to join given to "
900                "the HLA module");
901         return false;
902     }
903
904     if (_federate.empty()) {
905         SG_LOG(SG_IO, SG_ALERT, "No federate name given to the HLA module");
906         return false;
907     }
908
909     if (!SGPath(_objectModelConfig).exists()) {
910         SGPath path(globals->get_fg_root());
911         path.append("HLA");
912         path.append(_objectModelConfig);
913         if (path.exists())
914             _objectModelConfig = path.str();
915         else {
916             SG_LOG(SG_IO, SG_ALERT, "Federate object model configuration \""
917                    << _objectModelConfig << "\" does not exist.");
918             return false;
919         }
920     }
921
922     XMLConfigReader configReader;
923     try {
924         readXML(_objectModelConfig, configReader);
925     } catch (const sg_throwable& e) {
926         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file: "
927                << e.getMessage());
928         return false;
929     } catch (...) {
930         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file");
931         return false;
932     }
933
934     // Flightgears hla configuration
935     std::string objectModel = configReader.getFederateObjectModel();
936     if (objectModel.empty()) {
937         SG_LOG(SG_IO, SG_ALERT, "No federate object model given to "
938                "the HLA module");
939         return false;
940     }
941     if (!SGPath(objectModel).exists()) {
942         SGPath path(SGPath(_objectModelConfig).dir());
943         path.append(objectModel);
944         if (path.exists())
945             objectModel = path.str();
946         else {
947             SG_LOG(SG_IO, SG_ALERT, "Federate object model file \""
948                    << objectModel << "\" does not exist.");
949             return false;
950         }
951     }
952
953     // We need that to communicate to the rti
954     switch (configReader.getRTIVersion()) {
955     case RTI13:
956         _hlaFederate->setVersion(simgear::HLAFederate::RTI13);
957         break;
958     case RTI1516:
959         _hlaFederate->setVersion(simgear::HLAFederate::RTI1516);
960         break;
961     case RTI1516E:
962         _hlaFederate->setVersion(simgear::HLAFederate::RTI1516E);
963         break;
964     }
965     _hlaFederate->setConnectArguments(configReader.getRTIArguments());
966     _hlaFederate->setFederationExecutionName(_federation);
967     _hlaFederate->setFederationObjectModel(objectModel);
968     _hlaFederate->setFederateType(_federate);
969
970     // Now that it is paramtrized, connect/join
971     if (!_hlaFederate->init()) {
972         SG_LOG(SG_IO, SG_ALERT, "Could not init the hla/rti connect.");
973         return false;
974     }
975
976     // bool publish = get_direction() & SG_IO_OUT;
977     // bool subscribe = get_direction() & SG_IO_IN;
978
979     // This should be configured form a file
980     XMLConfigReader::ObjectClassConfigList::const_iterator i;
981     for (i = configReader.getObjectClassConfigList().begin();
982          i != configReader.getObjectClassConfigList().end(); ++i) {
983
984         if (i->_type != "Multiplayer") {
985             SG_LOG(SG_IO, SG_ALERT, "Ignoring unknown object class type \"" << i->_type << "\"!");
986             continue;
987         }
988
989         /// The object class for HLA aircraft
990         SGSharedPtr<simgear::HLAObjectClass> objectClass;
991
992         // Register the object class that we need for this simple hla implementation
993         std::string aircraftClassName = i->_name;
994         objectClass = _hlaFederate->getObjectClass(aircraftClassName);
995         if (!objectClass.valid()) {
996             SG_LOG(SG_IO, SG_ALERT, "Could not find " << aircraftClassName << " object class!");
997             continue;
998         }
999
1000         SGSharedPtr<MpClassCallback> mpClassCallback = new MpClassCallback;
1001
1002         if (i->_positionConfig._type == "cartesian") {
1003             SGSharedPtr<sg::HLACartesianLocationFactory> locationFactory;
1004             locationFactory = new sg::HLACartesianLocationFactory;
1005             XMLConfigReader::DataElementList::const_iterator j;
1006             for (j = i->_positionConfig._dataElementList.begin();
1007                  j != i->_positionConfig._dataElementList.end(); ++j) {
1008
1009                 if (j->_type == "position-x")
1010                     locationFactory->setPositionIndexPathPair(0, objectClass->getIndexPathPair(j->_name));
1011                 else if (j->_type == "position-y")
1012                     locationFactory->setPositionIndexPathPair(1, objectClass->getIndexPathPair(j->_name));
1013                 else if (j->_type == "position-z")
1014                     locationFactory->setPositionIndexPathPair(2, objectClass->getIndexPathPair(j->_name));
1015
1016                 else if (j->_type == "orientation-sin-angle-axis-x")
1017                     locationFactory->setOrientationIndexPathPair(0, objectClass->getIndexPathPair(j->_name));
1018                 else if (j->_type == "orientation-sin-angle-axis-y")
1019                     locationFactory->setOrientationIndexPathPair(1, objectClass->getIndexPathPair(j->_name));
1020                 else if (j->_type == "orientation-sin-angle-axis-z")
1021                     locationFactory->setOrientationIndexPathPair(2, objectClass->getIndexPathPair(j->_name));
1022
1023                 else if (j->_type == "angular-velocity-x")
1024                     locationFactory->setAngularVelocityIndexPathPair(0, objectClass->getIndexPathPair(j->_name));
1025                 else if (j->_type == "angular-velocity-y")
1026                     locationFactory->setAngularVelocityIndexPathPair(1, objectClass->getIndexPathPair(j->_name));
1027                 else if (j->_type == "angular-velocity-z")
1028                     locationFactory->setAngularVelocityIndexPathPair(2, objectClass->getIndexPathPair(j->_name));
1029
1030                 else if (j->_type == "linear-velocity-x")
1031                     locationFactory->setLinearVelocityIndexPathPair(0, objectClass->getIndexPathPair(j->_name));
1032                 else if (j->_type == "linear-velocity-y")
1033                     locationFactory->setLinearVelocityIndexPathPair(1, objectClass->getIndexPathPair(j->_name));
1034                 else if (j->_type == "linear-velocity-z")
1035                     locationFactory->setLinearVelocityIndexPathPair(2, objectClass->getIndexPathPair(j->_name));
1036
1037                 else {
1038                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1039                            << j->_type << "\"for object class \"" << aircraftClassName << "\". Ignoring!");
1040                 }
1041             }
1042
1043             mpClassCallback->setLocationFactory(locationFactory.get());
1044         } else if (i->_positionConfig._type == "geodetic") {
1045             SGSharedPtr<sg::HLAGeodeticLocationFactory> locationFactory;
1046             locationFactory = new sg::HLAGeodeticLocationFactory;
1047
1048             XMLConfigReader::DataElementList::const_iterator j;
1049             for (j = i->_positionConfig._dataElementList.begin();
1050                  j != i->_positionConfig._dataElementList.end(); ++j) {
1051
1052                 if (j->_type == "latitude-deg")
1053                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::LatitudeDeg,
1054                                                       objectClass->getIndexPathPair(j->_name));
1055                 else if (j->_type == "latitude-rad")
1056                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::LatitudeRad,
1057                                                       objectClass->getIndexPathPair(j->_name));
1058                 else if (j->_type == "longitude-deg")
1059                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::LongitudeDeg,
1060                                                       objectClass->getIndexPathPair(j->_name));
1061                 else if (j->_type == "longitude-rad")
1062                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::LongitudeRad,
1063                                                       objectClass->getIndexPathPair(j->_name));
1064                 else if (j->_type == "elevation-m")
1065                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::ElevationM,
1066                                                       objectClass->getIndexPathPair(j->_name));
1067                 else if (j->_type == "elevation-m")
1068                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::ElevationFt,
1069                                                       objectClass->getIndexPathPair(j->_name));
1070                 else if (j->_type == "heading-deg")
1071                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::HeadingDeg,
1072                                                       objectClass->getIndexPathPair(j->_name));
1073                 else if (j->_type == "heading-rad")
1074                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::HeadingRad,
1075                                                       objectClass->getIndexPathPair(j->_name));
1076                 else if (j->_type == "pitch-deg")
1077                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::PitchDeg,
1078                                                       objectClass->getIndexPathPair(j->_name));
1079                 else if (j->_type == "pitch-rad")
1080                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::PitchRad,
1081                                                       objectClass->getIndexPathPair(j->_name));
1082                 else if (j->_type == "roll-deg")
1083                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::RollDeg,
1084                                                       objectClass->getIndexPathPair(j->_name));
1085                 else if (j->_type == "roll-rad")
1086                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::RollRad,
1087                                                       objectClass->getIndexPathPair(j->_name));
1088                 else if (j->_type == "ground-track-deg")
1089                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::GroundTrackDeg,
1090                                                       objectClass->getIndexPathPair(j->_name));
1091                 else if (j->_type == "ground-track-rad")
1092                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::GroundTrackRad,
1093                                                       objectClass->getIndexPathPair(j->_name));
1094                 else if (j->_type == "ground-speed-kt")
1095                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::GroundSpeedKnots,
1096                                                       objectClass->getIndexPathPair(j->_name));
1097                 else if (j->_type == "ground-speed-ft-per-sec")
1098                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::GroundSpeedFtPerSec,
1099                                                       objectClass->getIndexPathPair(j->_name));
1100                 else if (j->_type == "ground-speed-m-per-sec")
1101                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::GroundSpeedMPerSec,
1102                                                       objectClass->getIndexPathPair(j->_name));
1103                 else if (j->_type == "vertical-speed-ft-per-sec")
1104                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerSec,
1105                                                       objectClass->getIndexPathPair(j->_name));
1106                 else if (j->_type == "vertical-speed-ft-per-min")
1107                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerMin,
1108                                                       objectClass->getIndexPathPair(j->_name));
1109                 else if (j->_type == "vertical-speed-m-per-sec")
1110                     locationFactory->setIndexPathPair(sg::HLAGeodeticLocationFactory::VerticalSpeedMPerSec,
1111                                                       objectClass->getIndexPathPair(j->_name));
1112                 else {
1113                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1114                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1115                 }
1116             }
1117
1118             mpClassCallback->setLocationFactory(locationFactory.get());
1119         }
1120
1121         if (i->_modelConfig._type == "native") {
1122             SGSharedPtr<AttributeModelFactory> attributeModelFactory;
1123             attributeModelFactory = new AttributeModelFactory;
1124
1125             XMLConfigReader::DataElementList::const_iterator j;
1126             for (j = i->_modelConfig._dataElementList.begin();
1127                  j != i->_modelConfig._dataElementList.end(); ++j) {
1128
1129                 if (j->_type == "model-path")
1130                     attributeModelFactory->setModelIndexPathPair(objectClass->getIndexPathPair(j->_name));
1131
1132                 else {
1133                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1134                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1135                 }
1136             }
1137
1138             mpClassCallback->setModelFactory(attributeModelFactory.get());
1139         } else if (i->_modelConfig._type == "map") {
1140
1141             SGSharedPtr<AttributeMapModelFactory> attributeModelFactory;
1142             attributeModelFactory = new AttributeMapModelFactory;
1143
1144             XMLConfigReader::DataElementList::const_iterator j;
1145             for (j = i->_modelConfig._dataElementList.begin();
1146                  j != i->_modelConfig._dataElementList.end(); ++j) {
1147
1148                 if (j->_type == "external")
1149                     attributeModelFactory->setModelIndexPathPair(objectClass->getIndexPathPair(j->_name));
1150
1151                 else {
1152                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1153                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1154                 }
1155             }
1156
1157             std::list<std::pair<std::string, std::string> >::const_iterator k;
1158             for (k = i->_modelConfig._modelMap.begin();
1159                  k != i->_modelConfig._modelMap.end(); ++k) {
1160
1161                 if (k->second.empty())
1162                     attributeModelFactory->setExternalDefault(k->first);
1163                 else
1164                     attributeModelFactory->addExternalModelPathPair(k->first, k->second);
1165             }
1166
1167             mpClassCallback->setModelFactory(attributeModelFactory.get());
1168
1169         } else {
1170             SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1171                    << i->_modelConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1172         }
1173
1174         if (i->_simTimeConfig._type == "attribute") {
1175             SGSharedPtr<AttributeSimTimeFactory> attributeSimTimeFactory;
1176             attributeSimTimeFactory = new AttributeSimTimeFactory;
1177
1178             XMLConfigReader::DataElementList::const_iterator j;
1179             for (j = i->_simTimeConfig._dataElementList.begin();
1180                  j != i->_simTimeConfig._dataElementList.end(); ++j) {
1181
1182                 if (j->_type == "local-simtime")
1183                     attributeSimTimeFactory->setSimTimeIndexPathPair(objectClass->getIndexPathPair(j->_name));
1184                 else {
1185                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1186                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1187                 }
1188             }
1189
1190             mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1191         } else if (i->_simTimeConfig._type == "attribute-sec-msec") {
1192             SGSharedPtr<MSecAttributeSimTimeFactory> attributeSimTimeFactory;
1193             attributeSimTimeFactory = new MSecAttributeSimTimeFactory;
1194
1195             XMLConfigReader::DataElementList::const_iterator j;
1196             for (j = i->_simTimeConfig._dataElementList.begin();
1197                  j != i->_simTimeConfig._dataElementList.end(); ++j) {
1198
1199                 if (j->_type == "local-simtime-sec")
1200                     attributeSimTimeFactory->setSecIndexPathPair(objectClass->getIndexPathPair(j->_name));
1201                 else if (j->_type == "local-simtime-msec")
1202                     attributeSimTimeFactory->setMSecIndexPathPair(objectClass->getIndexPathPair(j->_name));
1203                 else {
1204                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1205                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1206                 }
1207             }
1208
1209             mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1210         } else {
1211             SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1212                    << i->_simTimeConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1213         }
1214
1215         if (!i->_mpPropertiesConfig._name.empty()) {
1216             mpClassCallback->setMPPropertiesIndexPathPair(objectClass->getIndexPathPair(i->_mpPropertiesConfig._name));
1217         }
1218
1219         // The free configurabel property - dataElement mapping
1220         XMLConfigReader::DataElementList::const_iterator j;
1221         for (j = i->_dataElementList.begin();
1222              j != i->_dataElementList.end(); ++j) {
1223
1224             if (j->_type == "property") {
1225                 if (!j->_inProperty.empty())
1226                     mpClassCallback->setInputProperty(objectClass->getIndexPathPair(j->_name), j->_inProperty);
1227                 if (!j->_outProperty.empty())
1228                     mpClassCallback->setOutputProperty(objectClass->getIndexPathPair(j->_name), j->_outProperty);
1229             } else {
1230                 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown dataElement configuration type \""
1231                        << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1232             }
1233         }
1234
1235         objectClass->setInstanceCallback(mpClassCallback);
1236
1237         if (i->_type == "Multiplayer")
1238             _localAircraftClass = objectClass;
1239     }
1240
1241     set_enabled(true);
1242     return is_enabled();
1243 }
1244
1245 bool
1246 FGHLA::process()
1247 {
1248     if (!is_enabled())
1249         return false;
1250
1251     // First push our own data so that others can recieve ...
1252     if (get_direction() & SG_IO_OUT) {
1253         if (fgGetBool("/sim/fdm-initialized", false) && _localAircraftClass.valid()) {
1254             if (!_localAircraftInstance.valid()) {
1255                 _localAircraftInstance = new sg::HLAObjectInstance(_localAircraftClass.get());
1256                 _localAircraftInstance->registerInstance();
1257             }
1258             _localAircraftInstance->updateAttributeValues(sg::RTIData("tag"));
1259         }
1260     }
1261
1262     // Then get news from others and process possible update requests
1263     if (get_direction() & (SG_IO_IN|SG_IO_OUT)) {
1264         _hlaFederate->processMessages();
1265     }
1266
1267     return true;
1268 }
1269
1270 bool
1271 FGHLA::close()
1272 {
1273     if (!is_enabled())
1274         return false;
1275
1276     if (get_direction() & SG_IO_OUT) {
1277         // Remove the local object from the rti
1278         _localAircraftInstance->deleteInstance(simgear::RTIData("gone"));
1279         _localAircraftInstance = 0;
1280     }
1281
1282     // Leave the federation and try to destroy the federation execution.
1283     _hlaFederate->shutdown();
1284
1285     set_enabled(false);
1286
1287     return true;
1288 }
1289