]> git.mxchange.org Git - flightgear.git/blob - src/Network/HLA/hla.cxx
Interim windows build fix
[flightgear.git] / src / Network / HLA / hla.cxx
1 //
2 // Copyright (C) 2009 - 2012  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 <algorithm>
28 #include <list>
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 AbstractModel : public SGReferenced {
363 public:
364     virtual ~AbstractModel() {}
365
366     virtual std::string getModelPath() const = 0;
367     virtual void setModelPath(const std::string&) = 0;
368 };
369
370 // Factory class that is used to create an apternative data element for the multiplayer property attribute
371 class MPPropertyVariantRecordDataElementFactory :
372     public sg::HLAVariantArrayDataElement::AlternativeDataElementFactory {
373 public:
374     MPPropertyVariantRecordDataElementFactory(PropertyReferenceSet* propertyReferenceSet) :
375         _propertyReferenceSet(propertyReferenceSet)
376     { }
377
378     virtual sg::HLADataElement* createElement(const sg::HLAVariantRecordDataElement& variantRecordDataElement, unsigned index)
379     {
380         const sg::HLAVariantRecordDataType* dataType = variantRecordDataElement.getDataType();
381         if (!dataType)
382             return 0;
383         const sg::HLAEnumeratedDataType* enumDataType = dataType->getEnumeratedDataType();
384         if (!enumDataType)
385             return 0;
386         const sg::HLADataType* alternativeDataType = dataType->getAlternativeDataType(index);
387         if (!alternativeDataType)
388             return 0;
389
390         // The relative property path should be in the semantics field name
391         std::string relativePath = dataType->getAlternativeSemantics(index);
392         sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement(alternativeDataType, (SGPropertyNode*)0);
393         _propertyReferenceSet->insert(relativePath, dataElement);
394         return dataElement;
395     }
396
397 private:
398     SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
399 };
400
401 class FGHLA::MultiplayerObjectInstance : public sg::HLAObjectInstance {
402 public:
403     MultiplayerObjectInstance(sg::HLAObjectClass* objectClass) :
404         sg::HLAObjectInstance(objectClass),
405         _propertyReferenceSet(new PropertyReferenceSet),
406         _mpProperties(new sg::HLAVariantArrayDataElement)
407     {
408         _mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantRecordDataElementFactory(_propertyReferenceSet.get()));
409     }
410     virtual ~MultiplayerObjectInstance()
411     { }
412
413     SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
414     SGSharedPtr<sg::HLAAbstractLocation> _location;
415     SGSharedPtr<AbstractSimTime> _simTime;
416     SGSharedPtr<AbstractModel> _model;
417     SGSharedPtr<sg::HLAVariantArrayDataElement> _mpProperties;
418 };
419
420 class FGHLA::MPUpdateCallback : public sg::HLAObjectInstance::UpdateCallback {
421 public:
422     virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
423     {
424         updateAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
425         objectInstance.encodeAttributeValues();
426         objectInstance.sendAttributeValues(tag);
427     }
428
429     virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const SGTimeStamp& timeStamp, const sg::RTIData& tag)
430     {
431         updateAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
432         objectInstance.encodeAttributeValues();
433         objectInstance.sendAttributeValues(timeStamp, tag);
434     }
435
436     void updateAttributeValues(MultiplayerObjectInstance& objectInstance)
437     {
438         objectInstance._simTime->setTimeStamp(globals->get_sim_time_sec());
439
440         SGGeod position = _ifce.getPosition();
441         // The quaternion rotating from the earth centered frame to the
442         // horizontal local frame
443         SGQuatd qEc2Hl = SGQuatd::fromLonLat(position);
444         SGQuatd hlOr = SGQuatd::fromYawPitchRoll(_ifce.get_Psi(), _ifce.get_Theta(), _ifce.get_Phi());
445         objectInstance._location->setCartPosition(SGVec3d::fromGeod(position));
446         objectInstance._location->setCartOrientation(qEc2Hl*hlOr);
447         // The angular velocitied in the body frame
448         double p = _ifce.get_P_body();
449         double q = _ifce.get_Q_body();
450         double r = _ifce.get_R_body();
451         objectInstance._location->setAngularBodyVelocity(SGVec3d(p, q, r));
452         // The body uvw velocities in the interface are wrt the wind instead
453         // of wrt the ec frame
454         double n = _ifce.get_V_north()*SG_FEET_TO_METER;
455         double e = _ifce.get_V_east()*SG_FEET_TO_METER;
456         double d = _ifce.get_V_down()*SG_FEET_TO_METER;
457         objectInstance._location->setLinearBodyVelocity(hlOr.transform(SGVec3d(n, e, d)));
458
459         if (objectInstance._mpProperties.valid() && objectInstance._mpProperties->getNumElements() == 0) {
460             if (objectInstance._propertyReferenceSet.valid() && objectInstance._propertyReferenceSet->getRootNode()) {
461                 const sg::HLADataType* elementDataType = objectInstance._mpProperties->getElementDataType();
462                 const sg::HLAVariantRecordDataType* variantRecordDataType = elementDataType->toVariantRecordDataType();
463                 for (unsigned i = 0, count = 0; i < variantRecordDataType->getNumAlternatives(); ++i) {
464                     std::string name = variantRecordDataType->getAlternativeSemantics(i);
465                     SGPropertyNode* node = objectInstance._propertyReferenceSet->getRootNode()->getNode(name);
466                     if (!node)
467                         continue;
468                     objectInstance._mpProperties->getOrCreateElement(count++)->setAlternativeIndex(i);
469                 }
470             }
471         }
472     }
473
474     FlightProperties _ifce;
475 };
476
477 class FGHLA::MPReflectCallback : public sg::HLAObjectInstance::ReflectCallback {
478 public:
479     virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance,
480                                         const sg::HLAIndexList& indexList, const sg::RTIData& tag)
481     {
482         objectInstance.reflectAttributeValues(indexList, tag);
483         reflectAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
484     }
485     virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::HLAIndexList& indexList,
486                                         const SGTimeStamp& timeStamp, const sg::RTIData& tag)
487     {
488         objectInstance.reflectAttributeValues(indexList, timeStamp, tag);
489         reflectAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
490     }
491
492     void reflectAttributeValues(MultiplayerObjectInstance& objectInstance)
493     {
494         // Puh, damn ordering problems with properties startup and so on
495         if (_aiMultiplayer.valid()) {
496             FGExternalMotionData motionInfo;
497             motionInfo.time = objectInstance._simTime->getTimeStamp();
498             motionInfo.lag = 0;
499
500             motionInfo.position = objectInstance._location->getCartPosition();
501             motionInfo.orientation = toQuatf(objectInstance._location->getCartOrientation());
502             motionInfo.linearVel = toVec3f(objectInstance._location->getLinearBodyVelocity());
503             motionInfo.angularVel = toVec3f(objectInstance._location->getAngularBodyVelocity());
504             motionInfo.linearAccel = SGVec3f::zeros();
505             motionInfo.angularAccel = SGVec3f::zeros();
506
507             _aiMultiplayer->addMotionInfo(motionInfo, SGTimeStamp::now().getSeconds());
508
509         } else {
510             std::string modelPath = objectInstance._model->getModelPath();
511             if (modelPath.empty())
512                 return;
513             FGAIManager *aiMgr;
514             aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
515             if (!aiMgr)
516                 return;
517
518             _aiMultiplayer = new FGAIMultiplayer;
519             _aiMultiplayer->setPath(modelPath.c_str());
520             aiMgr->attach(_aiMultiplayer.get());
521
522             objectInstance._propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
523         }
524     }
525
526     void setDie()
527     {
528         if (!_aiMultiplayer.valid())
529             return;
530         _aiMultiplayer->setDie(true);
531         _aiMultiplayer = 0;
532     }
533
534     SGSharedPtr<FGAIMultiplayer> _aiMultiplayer;
535 };
536
537 class SimTimeFactory : public SGReferenced {
538 public:
539     virtual ~SimTimeFactory() {}
540     virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance&) const = 0;
541 };
542
543 // A SimTime implementation that works with the simulation
544 // time in an attribute. Used when we cannot do real time management.
545 class AttributeSimTimeFactory : public SimTimeFactory {
546 public:
547     class SimTime : public AbstractSimTime {
548     public:
549         virtual double getTimeStamp() const
550         { return _simTime; }
551         virtual void setTimeStamp(double simTime)
552         { _simTime = simTime; }
553         
554         sg::HLADataElement* getDataElement()
555         { return _simTime.getDataElement(); }
556         
557     private:
558         sg::HLADoubleData _simTime;
559     };
560
561     virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance& objectInstance) const
562     {
563         SimTime* simTime = new SimTime;
564         objectInstance.setAttributeDataElement(_simTimeIndex, simTime->getDataElement());
565         return simTime;
566     }
567     void setSimTimeIndex(const sg::HLADataElementIndex& simTimeIndex)
568     { _simTimeIndex = simTimeIndex; }
569
570 private:
571     sg::HLADataElementIndex _simTimeIndex;
572 };
573
574 // A SimTime implementation that works with the simulation
575 // time in two attributes like the avation sim net fom works
576 class MSecAttributeSimTimeFactory : public SimTimeFactory {
577 public:
578     class SimTime : public AbstractSimTime {
579     public:
580         virtual double getTimeStamp() const
581         {
582             return _secSimTime + 1e-3*_msecSimTime;
583         }
584         virtual void setTimeStamp(double simTime)
585         {
586             double sec = floor(simTime);
587             _secSimTime = sec;
588             _msecSimTime = 1e3*(simTime - sec);
589         }
590         
591         sg::HLADataElement* getSecDataElement()
592         { return _secSimTime.getDataElement(); }
593         sg::HLADataElement* getMSecDataElement()
594         { return _msecSimTime.getDataElement(); }
595         
596     private:
597         sg::HLADoubleData _secSimTime;
598         sg::HLADoubleData _msecSimTime;
599     };
600     
601     virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance& objectInstance) const
602     {
603         SimTime* simTime = new SimTime;
604         objectInstance.setAttributeDataElement(_secIndex, simTime->getSecDataElement());
605         objectInstance.setAttributeDataElement(_msecIndex, simTime->getMSecDataElement());
606         return simTime;
607     }
608     void setSecIndex(const sg::HLADataElementIndex& secIndex)
609     { _secIndex = secIndex; }
610     void setMSecIndex(const sg::HLADataElementIndex& msecIndex)
611     { _msecIndex = msecIndex; }
612
613 private:
614     sg::HLADataElementIndex _secIndex;
615     sg::HLADataElementIndex _msecIndex;
616 };
617
618 class ModelFactory : public SGReferenced {
619 public:
620     virtual ~ModelFactory() {}
621     virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const = 0;
622 };
623
624 class AttributeModelFactory : public ModelFactory {
625 public:
626     class Model : public AbstractModel {
627     public:
628         virtual std::string getModelPath() const
629         { return _modelPath; }
630         virtual void setModelPath(const std::string& modelPath)
631         { _modelPath = modelPath; }
632         
633         sg::HLADataElement* getDataElement()
634         { return _modelPath.getDataElement(); }
635         
636     private:
637         sg::HLAStringData _modelPath;
638     };
639
640     virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const
641     {
642         Model* model = new Model;
643         objectInstance.setAttributeDataElement(_modelIndex, model->getDataElement());
644         return model;
645     }
646     void setModelIndex(const sg::HLADataElementIndex& modelIndex)
647     { _modelIndex = modelIndex; }
648
649 private:
650     sg::HLADataElementIndex _modelIndex;
651 };
652
653 class AttributeMapModelFactory : public ModelFactory {
654 public:
655     class Model : public AbstractModel {
656     public:
657         Model(const AttributeMapModelFactory* mapModelFactory) :
658             _mapModelFactory(mapModelFactory)
659         { }
660
661         virtual std::string getModelPath() const
662         {
663             if (_modelPath.getValue().empty())
664                 return _modelPath.getValue();
665             return _mapModelFactory->mapToFlightgear(_modelPath);
666         }
667         virtual void setModelPath(const std::string& modelPath)
668         { _modelPath = _mapModelFactory->mapToExternal(modelPath); }
669
670         sg::HLADataElement* getDataElement()
671         { return _modelPath.getDataElement(); }
672
673     private:
674         sg::HLAStringData _modelPath;
675         SGSharedPtr<const AttributeMapModelFactory> _mapModelFactory;
676     };
677
678     virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const
679     {
680         Model* model = new Model(this);
681         objectInstance.setAttributeDataElement(_modelIndex, model->getDataElement());
682         return model;
683     }
684     void setModelIndex(const sg::HLADataElementIndex& modelIndex)
685     { _modelIndex = modelIndex; }
686
687     std::string mapToFlightgear(const std::string& externalModel) const
688     {
689         std::map<std::string,std::string>::const_iterator i;
690         i = _externalToModelPathMap.find(externalModel);
691         if (i != _externalToModelPathMap.end())
692             return i->second;
693         return "default";
694     }
695     std::string mapToExternal(const std::string& modelPath) const
696     {
697         std::map<std::string,std::string>::const_iterator i;
698         i = _modelPathToExternalMap.find(modelPath);
699         if (i != _modelPathToExternalMap.end())
700             return i->second;
701         return _externalDefault;
702     }
703
704     void setExternalDefault(const std::string& externalDefault)
705     { _externalDefault = externalDefault; }
706     void addExternalModelPathPair(const std::string& external, const std::string& modelPath)
707     {
708         _externalToModelPathMap[external] = modelPath;
709         _modelPathToExternalMap[modelPath] = external;
710     }
711
712 private:
713     sg::HLADataElementIndex _modelIndex;
714
715     std::map<std::string,std::string> _externalToModelPathMap;
716     std::map<std::string,std::string> _modelPathToExternalMap;
717     std::string _externalDefault;
718 };
719
720 class FGHLA::MultiplayerObjectClass : public sg::HLAObjectClass {
721 public:
722     MultiplayerObjectClass(const std::string& name, sg::HLAFederate* federate) :
723         HLAObjectClass(name, federate)
724     { }
725     virtual ~MultiplayerObjectClass()
726     { }
727
728     virtual MultiplayerObjectInstance* createObjectInstance(const std::string& name)
729     { return new MultiplayerObjectInstance(this); }
730
731     virtual void discoverInstance(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
732     {
733         HLAObjectClass::discoverInstance(objectInstance, tag);
734         MPReflectCallback* reflectCallback = new MPReflectCallback;
735         objectInstance.setReflectCallback(reflectCallback);
736         attachDataElements(static_cast<MultiplayerObjectInstance&>(objectInstance), false);
737     }
738     virtual void removeInstance(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
739     {
740         HLAObjectClass::removeInstance(objectInstance, tag);
741         MPReflectCallback* reflectCallback;
742         reflectCallback = dynamic_cast<MPReflectCallback*>(objectInstance.getReflectCallback().get());
743         if (!reflectCallback) {
744             SG_LOG(SG_IO, SG_WARN, "HLA: expected to have a different attribute callback in remove instance.");
745             return;
746         }
747         reflectCallback->setDie();
748     }
749     virtual void registerInstance(sg::HLAObjectInstance& objectInstance)
750     {
751         HLAObjectClass::registerInstance(objectInstance);
752         MPUpdateCallback* updateCallback = new MPUpdateCallback;
753         objectInstance.setUpdateCallback(updateCallback);
754         MultiplayerObjectInstance& mpObjectInstance = static_cast<MultiplayerObjectInstance&>(objectInstance);
755         attachDataElements(mpObjectInstance, true);
756         mpObjectInstance._model->setModelPath(fgGetString("/sim/model/path", "default"));
757         mpObjectInstance._propertyReferenceSet->setRootNode(fgGetNode("/", true));
758     }
759     virtual void deleteInstance(sg::HLAObjectInstance& objectInstance)
760     {
761         HLAObjectClass::deleteInstance(objectInstance);
762     }
763
764     virtual void createAttributeDataElements(sg::HLAObjectInstance& objectInstance)
765     {
766         sg::HLAObjectClass::createAttributeDataElements(objectInstance);
767     }
768
769     void setLocationFactory(sg::HLALocationFactory* locationFactory)
770     { _locationFactory = locationFactory; }
771     sg::HLALocationFactory* getLocationFactory()
772     { return _locationFactory.get(); }
773
774     void setSimTimeFactory(SimTimeFactory* simTimeFactory)
775     { _simTimeFactory = simTimeFactory; }
776     SimTimeFactory* getSimTimeFactory()
777     { return _simTimeFactory.get(); }
778
779     void setModelFactory(ModelFactory* modelFactory)
780     { _modelFactory = modelFactory; }
781     ModelFactory* getModelFactory()
782     { return _modelFactory.get(); }
783
784     void setMPPropertiesIndex(const sg::HLADataElementIndex& index)
785     { _mpPropertiesIndex = index; }
786     const sg::HLADataElementIndex& getMPPropertiesIndex() const
787     { return _mpPropertiesIndex; }
788
789     void setInputProperty(const sg::HLADataElementIndex& index, const std::string& property)
790     {
791         _inputProperties[index] = property;
792     }
793     void setOutputProperty(const sg::HLADataElementIndex& index, const std::string& property)
794     {
795         _outputProperties[index] = property;
796     }
797
798 private:
799     void attachDataElements(MultiplayerObjectInstance& objectInstance, bool outgoing)
800     {
801         objectInstance.setAttributeDataElement(_mpPropertiesIndex, objectInstance._mpProperties.get());
802
803         if (_locationFactory.valid())
804             objectInstance._location = _locationFactory->createLocation(objectInstance);
805         if (_modelFactory.valid())
806             objectInstance._model = _modelFactory->createModel(objectInstance);
807         if (_simTimeFactory.valid())
808             objectInstance._simTime = _simTimeFactory->createSimTime(objectInstance);
809
810         if (outgoing)
811             attachPropertyDataElements(*objectInstance._propertyReferenceSet,
812                                        objectInstance, _outputProperties);
813         else
814             attachPropertyDataElements(*objectInstance._propertyReferenceSet,
815                                        objectInstance, _inputProperties);
816     }
817     typedef std::map<sg::HLADataElementIndex, std::string> IndexPropertyMap;
818
819     void attachPropertyDataElements(PropertyReferenceSet& propertyReferenceSet,
820                                     sg::HLAObjectInstance& objectInstance,
821                                     const IndexPropertyMap& attributePathPropertyMap)
822     {
823         for (IndexPropertyMap::const_iterator i = attributePathPropertyMap.begin();
824              i != attributePathPropertyMap.end(); ++i) {
825             sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement;
826             propertyReferenceSet.insert(i->second, dataElement);
827             objectInstance.setAttributeDataElement(i->first, dataElement);
828         }
829     }
830
831     IndexPropertyMap _inputProperties;
832     IndexPropertyMap _outputProperties;
833
834     SGSharedPtr<sg::HLALocationFactory> _locationFactory;
835     SGSharedPtr<SimTimeFactory> _simTimeFactory;
836     SGSharedPtr<ModelFactory> _modelFactory;
837
838     sg::HLADataElementIndex _mpPropertiesIndex;
839 };
840
841 class FGHLA::Federate : public sg::HLAFederate {
842 public:
843     virtual ~Federate()
844     { }
845     virtual bool readObjectModel()
846     { return readRTI1516ObjectModelTemplate(getFederationObjectModel()); }
847
848     virtual sg::HLAObjectClass* createObjectClass(const std::string& name)
849     {
850         if (std::find(_multiplayerObjectClassNames.begin(), _multiplayerObjectClassNames.end(), name)
851             != _multiplayerObjectClassNames.end()) {
852             if (_localAircraftClass.valid()) {
853                 return new MultiplayerObjectClass(name, this);
854             } else {
855                 _localAircraftClass = new MultiplayerObjectClass(name, this);
856                 return _localAircraftClass.get();
857             }
858         } else {
859             return 0;
860         }
861     }
862
863     void updateLocalAircraftInstance()
864     {
865         // First push our own data so that others can recieve ...
866         if (!_localAircraftClass.valid())
867             return;
868         if (!_localAircraftInstance.valid()) {
869             _localAircraftInstance = new MultiplayerObjectInstance(_localAircraftClass.get());
870             _localAircraftInstance->registerInstance();
871         }
872         _localAircraftInstance->updateAttributeValues(sg::RTIData("MPAircraft"));
873     }
874
875     virtual bool shutdown()
876     {
877         if (_localAircraftInstance.valid()) {
878             // Remove the local object from the rti
879             _localAircraftInstance->deleteInstance(simgear::RTIData("gone"));
880             _localAircraftInstance = 0;
881         }
882         return HLAFederate::shutdown();
883     }
884
885     std::list<std::string> _multiplayerObjectClassNames;
886     /// This class is used to register the local instance and to subscribe for others
887     SGSharedPtr<MultiplayerObjectClass> _localAircraftClass;
888     /// The local aircraft instance
889     SGSharedPtr<MultiplayerObjectInstance> _localAircraftInstance;
890 };
891
892 FGHLA::FGHLA(const std::vector<std::string>& tokens) :
893     _hlaFederate(new Federate)
894 {
895     if (1 < tokens.size() && !tokens[1].empty())
896         set_direction(tokens[1]);
897     else
898         set_direction("bi");
899
900     int rate = 60;
901     if (2 < tokens.size() && !tokens[2].empty()) {
902         std::stringstream ss(tokens[2]);
903         ss >> rate;
904     }
905     set_hz(rate);
906
907     if (3 < tokens.size() && !tokens[3].empty())
908         _federate = tokens[3];
909     else
910         _federate = fgGetString("/sim/user/callsign");
911
912     if (4 < tokens.size() && !tokens[4].empty())
913         _federation = tokens[4];
914     else
915         _federation = "FlightGear";
916
917     if (5 < tokens.size() && !tokens[5].empty())
918         _objectModelConfig = tokens[5];
919     else
920         _objectModelConfig = "mp-aircraft.xml";
921 }
922
923 FGHLA::~FGHLA()
924 {
925 }
926
927 bool
928 FGHLA::open()
929 {
930     if (is_enabled()) {
931         SG_LOG(SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
932                 "is already in use, ignoring");
933         return false;
934     }
935
936     if (_federation.empty()) {
937         SG_LOG(SG_IO, SG_ALERT, "No federation to join given to "
938                "the HLA module");
939         return false;
940     }
941
942     if (_federate.empty()) {
943         SG_LOG(SG_IO, SG_ALERT, "No federate name given to the HLA module");
944         return false;
945     }
946
947     if (!SGPath(_objectModelConfig).exists()) {
948         SGPath path(globals->get_fg_root());
949         path.append("HLA");
950         path.append(_objectModelConfig);
951         if (path.exists())
952             _objectModelConfig = path.str();
953         else {
954             SG_LOG(SG_IO, SG_ALERT, "Federate object model configuration \""
955                    << _objectModelConfig << "\" does not exist.");
956             return false;
957         }
958     }
959
960     XMLConfigReader configReader;
961     try {
962         readXML(_objectModelConfig, configReader);
963     } catch (const sg_throwable& e) {
964         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file: "
965                << e.getMessage());
966         return false;
967     } catch (...) {
968         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file");
969         return false;
970     }
971
972     // Flightgears hla configuration
973     std::string objectModel = configReader.getFederateObjectModel();
974     if (objectModel.empty()) {
975         SG_LOG(SG_IO, SG_ALERT, "No federate object model given to "
976                "the HLA module");
977         return false;
978     }
979     if (!SGPath(objectModel).exists()) {
980         SGPath path(SGPath(_objectModelConfig).dir());
981         path.append(objectModel);
982         if (path.exists())
983             objectModel = path.str();
984         else {
985             SG_LOG(SG_IO, SG_ALERT, "Federate object model file \""
986                    << objectModel << "\" does not exist.");
987             return false;
988         }
989     }
990
991     // We need that to communicate to the rti
992     switch (configReader.getRTIVersion()) {
993     case RTI13:
994         _hlaFederate->setVersion(simgear::HLAFederate::RTI13);
995         break;
996     case RTI1516:
997         _hlaFederate->setVersion(simgear::HLAFederate::RTI1516);
998         break;
999     case RTI1516E:
1000         _hlaFederate->setVersion(simgear::HLAFederate::RTI1516E);
1001         break;
1002     }
1003     _hlaFederate->setConnectArguments(configReader.getRTIArguments());
1004     _hlaFederate->setFederationExecutionName(_federation);
1005     _hlaFederate->setFederationObjectModel(objectModel);
1006     _hlaFederate->setFederateType(_federate);
1007
1008     // Store the multiplayer class name in the federate
1009     XMLConfigReader::ObjectClassConfigList::const_iterator i;
1010     for (i = configReader.getObjectClassConfigList().begin();
1011          i != configReader.getObjectClassConfigList().end(); ++i) {
1012
1013         if (i->_type != "Multiplayer") {
1014             SG_LOG(SG_IO, SG_ALERT, "Ignoring unknown object class type \"" << i->_type << "\"!");
1015             continue;
1016         }
1017
1018         // Register the object class that we need for this simple hla implementation
1019         _hlaFederate->_multiplayerObjectClassNames.push_back(i->_name);
1020     }
1021
1022
1023     // Now that it is paramtrized, connect/join
1024     if (!_hlaFederate->init()) {
1025         SG_LOG(SG_IO, SG_ALERT, "Could not init the hla/rti connect.");
1026         return false;
1027     }
1028
1029     // bool publish = get_direction() & SG_IO_OUT;
1030     // bool subscribe = get_direction() & SG_IO_IN;
1031
1032     // Interpret the configuration file
1033     for (i = configReader.getObjectClassConfigList().begin();
1034          i != configReader.getObjectClassConfigList().end(); ++i) {
1035
1036         /// already warned about this above
1037         if (i->_type != "Multiplayer")
1038             continue;
1039
1040         /// The object class for HLA aircraft
1041         SGSharedPtr<MultiplayerObjectClass> objectClass;
1042
1043         // Register the object class that we need for this simple hla implementation
1044         std::string aircraftClassName = i->_name;
1045         objectClass = dynamic_cast<MultiplayerObjectClass*>(_hlaFederate->getObjectClass(aircraftClassName));
1046         if (!objectClass.valid()) {
1047             SG_LOG(SG_IO, SG_ALERT, "Could not find " << aircraftClassName << " object class!");
1048             continue;
1049         }
1050
1051         SGSharedPtr<MultiplayerObjectClass> mpClassCallback = objectClass;
1052
1053         if (i->_positionConfig._type == "cartesian") {
1054             SGSharedPtr<sg::HLACartesianLocationFactory> locationFactory;
1055             locationFactory = new sg::HLACartesianLocationFactory;
1056             XMLConfigReader::DataElementList::const_iterator j;
1057             for (j = i->_positionConfig._dataElementList.begin();
1058                  j != i->_positionConfig._dataElementList.end(); ++j) {
1059
1060                 if (j->_type == "position-x")
1061                     locationFactory->setPositionIndex(0, objectClass->getDataElementIndex(j->_name));
1062                 else if (j->_type == "position-y")
1063                     locationFactory->setPositionIndex(1, objectClass->getDataElementIndex(j->_name));
1064                 else if (j->_type == "position-z")
1065                     locationFactory->setPositionIndex(2, objectClass->getDataElementIndex(j->_name));
1066
1067                 else if (j->_type == "orientation-sin-angle-axis-x")
1068                     locationFactory->setOrientationIndex(0, objectClass->getDataElementIndex(j->_name));
1069                 else if (j->_type == "orientation-sin-angle-axis-y")
1070                     locationFactory->setOrientationIndex(1, objectClass->getDataElementIndex(j->_name));
1071                 else if (j->_type == "orientation-sin-angle-axis-z")
1072                     locationFactory->setOrientationIndex(2, objectClass->getDataElementIndex(j->_name));
1073
1074                 else if (j->_type == "angular-velocity-x")
1075                     locationFactory->setAngularVelocityIndex(0, objectClass->getDataElementIndex(j->_name));
1076                 else if (j->_type == "angular-velocity-y")
1077                     locationFactory->setAngularVelocityIndex(1, objectClass->getDataElementIndex(j->_name));
1078                 else if (j->_type == "angular-velocity-z")
1079                     locationFactory->setAngularVelocityIndex(2, objectClass->getDataElementIndex(j->_name));
1080
1081                 else if (j->_type == "linear-velocity-x")
1082                     locationFactory->setLinearVelocityIndex(0, objectClass->getDataElementIndex(j->_name));
1083                 else if (j->_type == "linear-velocity-y")
1084                     locationFactory->setLinearVelocityIndex(1, objectClass->getDataElementIndex(j->_name));
1085                 else if (j->_type == "linear-velocity-z")
1086                     locationFactory->setLinearVelocityIndex(2, objectClass->getDataElementIndex(j->_name));
1087
1088                 else {
1089                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1090                            << j->_type << "\"for object class \"" << aircraftClassName << "\". Ignoring!");
1091                 }
1092             }
1093
1094             mpClassCallback->setLocationFactory(locationFactory.get());
1095         } else if (i->_positionConfig._type == "geodetic") {
1096             SGSharedPtr<sg::HLAGeodeticLocationFactory> locationFactory;
1097             locationFactory = new sg::HLAGeodeticLocationFactory;
1098
1099             XMLConfigReader::DataElementList::const_iterator j;
1100             for (j = i->_positionConfig._dataElementList.begin();
1101                  j != i->_positionConfig._dataElementList.end(); ++j) {
1102
1103                 if (j->_type == "latitude-deg")
1104                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LatitudeDeg,
1105                                               objectClass->getDataElementIndex(j->_name));
1106                 else if (j->_type == "latitude-rad")
1107                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LatitudeRad,
1108                                               objectClass->getDataElementIndex(j->_name));
1109                 else if (j->_type == "longitude-deg")
1110                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LongitudeDeg,
1111                                               objectClass->getDataElementIndex(j->_name));
1112                 else if (j->_type == "longitude-rad")
1113                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LongitudeRad,
1114                                               objectClass->getDataElementIndex(j->_name));
1115                 else if (j->_type == "elevation-m")
1116                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::ElevationM,
1117                                               objectClass->getDataElementIndex(j->_name));
1118                 else if (j->_type == "elevation-m")
1119                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::ElevationFt,
1120                                               objectClass->getDataElementIndex(j->_name));
1121                 else if (j->_type == "heading-deg")
1122                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::HeadingDeg,
1123                                               objectClass->getDataElementIndex(j->_name));
1124                 else if (j->_type == "heading-rad")
1125                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::HeadingRad,
1126                                               objectClass->getDataElementIndex(j->_name));
1127                 else if (j->_type == "pitch-deg")
1128                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::PitchDeg,
1129                                               objectClass->getDataElementIndex(j->_name));
1130                 else if (j->_type == "pitch-rad")
1131                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::PitchRad,
1132                                               objectClass->getDataElementIndex(j->_name));
1133                 else if (j->_type == "roll-deg")
1134                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::RollDeg,
1135                                               objectClass->getDataElementIndex(j->_name));
1136                 else if (j->_type == "roll-rad")
1137                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::RollRad,
1138                                               objectClass->getDataElementIndex(j->_name));
1139                 else if (j->_type == "ground-track-deg")
1140                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundTrackDeg,
1141                                               objectClass->getDataElementIndex(j->_name));
1142                 else if (j->_type == "ground-track-rad")
1143                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundTrackRad,
1144                                               objectClass->getDataElementIndex(j->_name));
1145                 else if (j->_type == "ground-speed-kt")
1146                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedKnots,
1147                                               objectClass->getDataElementIndex(j->_name));
1148                 else if (j->_type == "ground-speed-ft-per-sec")
1149                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedFtPerSec,
1150                                               objectClass->getDataElementIndex(j->_name));
1151                 else if (j->_type == "ground-speed-m-per-sec")
1152                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedMPerSec,
1153                                               objectClass->getDataElementIndex(j->_name));
1154                 else if (j->_type == "vertical-speed-ft-per-sec")
1155                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerSec,
1156                                               objectClass->getDataElementIndex(j->_name));
1157                 else if (j->_type == "vertical-speed-ft-per-min")
1158                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerMin,
1159                                               objectClass->getDataElementIndex(j->_name));
1160                 else if (j->_type == "vertical-speed-m-per-sec")
1161                     locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedMPerSec,
1162                                               objectClass->getDataElementIndex(j->_name));
1163                 else {
1164                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1165                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1166                 }
1167             }
1168
1169             mpClassCallback->setLocationFactory(locationFactory.get());
1170         }
1171
1172         if (i->_modelConfig._type == "native") {
1173             SGSharedPtr<AttributeModelFactory> attributeModelFactory;
1174             attributeModelFactory = new AttributeModelFactory;
1175
1176             XMLConfigReader::DataElementList::const_iterator j;
1177             for (j = i->_modelConfig._dataElementList.begin();
1178                  j != i->_modelConfig._dataElementList.end(); ++j) {
1179
1180                 if (j->_type == "model-path")
1181                     attributeModelFactory->setModelIndex(objectClass->getDataElementIndex(j->_name));
1182
1183                 else {
1184                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1185                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1186                 }
1187             }
1188
1189             mpClassCallback->setModelFactory(attributeModelFactory.get());
1190         } else if (i->_modelConfig._type == "map") {
1191
1192             SGSharedPtr<AttributeMapModelFactory> attributeModelFactory;
1193             attributeModelFactory = new AttributeMapModelFactory;
1194
1195             XMLConfigReader::DataElementList::const_iterator j;
1196             for (j = i->_modelConfig._dataElementList.begin();
1197                  j != i->_modelConfig._dataElementList.end(); ++j) {
1198
1199                 if (j->_type == "external")
1200                     attributeModelFactory->setModelIndex(objectClass->getDataElementIndex(j->_name));
1201
1202                 else {
1203                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1204                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1205                 }
1206             }
1207
1208             std::list<std::pair<std::string, std::string> >::const_iterator k;
1209             for (k = i->_modelConfig._modelMap.begin();
1210                  k != i->_modelConfig._modelMap.end(); ++k) {
1211
1212                 if (k->second.empty())
1213                     attributeModelFactory->setExternalDefault(k->first);
1214                 else
1215                     attributeModelFactory->addExternalModelPathPair(k->first, k->second);
1216             }
1217
1218             mpClassCallback->setModelFactory(attributeModelFactory.get());
1219
1220         } else {
1221             SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1222                    << i->_modelConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1223         }
1224
1225         if (i->_simTimeConfig._type == "attribute") {
1226             SGSharedPtr<AttributeSimTimeFactory> attributeSimTimeFactory;
1227             attributeSimTimeFactory = new AttributeSimTimeFactory;
1228
1229             XMLConfigReader::DataElementList::const_iterator j;
1230             for (j = i->_simTimeConfig._dataElementList.begin();
1231                  j != i->_simTimeConfig._dataElementList.end(); ++j) {
1232
1233                 if (j->_type == "local-simtime")
1234                     attributeSimTimeFactory->setSimTimeIndex(objectClass->getDataElementIndex(j->_name));
1235                 else {
1236                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1237                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1238                 }
1239             }
1240
1241             mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1242         } else if (i->_simTimeConfig._type == "attribute-sec-msec") {
1243             SGSharedPtr<MSecAttributeSimTimeFactory> attributeSimTimeFactory;
1244             attributeSimTimeFactory = new MSecAttributeSimTimeFactory;
1245
1246             XMLConfigReader::DataElementList::const_iterator j;
1247             for (j = i->_simTimeConfig._dataElementList.begin();
1248                  j != i->_simTimeConfig._dataElementList.end(); ++j) {
1249
1250                 if (j->_type == "local-simtime-sec")
1251                     attributeSimTimeFactory->setSecIndex(objectClass->getDataElementIndex(j->_name));
1252                 else if (j->_type == "local-simtime-msec")
1253                     attributeSimTimeFactory->setMSecIndex(objectClass->getDataElementIndex(j->_name));
1254                 else {
1255                     SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1256                            << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1257                 }
1258             }
1259
1260             mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1261         } else {
1262             SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1263                    << i->_simTimeConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1264         }
1265
1266         if (!i->_mpPropertiesConfig._name.empty()) {
1267             mpClassCallback->setMPPropertiesIndex(objectClass->getDataElementIndex(i->_mpPropertiesConfig._name));
1268         }
1269
1270         // The free configurabel property - dataElement mapping
1271         XMLConfigReader::DataElementList::const_iterator j;
1272         for (j = i->_dataElementList.begin();
1273              j != i->_dataElementList.end(); ++j) {
1274
1275             if (j->_type == "property") {
1276                 if (!j->_inProperty.empty())
1277                     mpClassCallback->setInputProperty(objectClass->getDataElementIndex(j->_name), j->_inProperty);
1278                 if (!j->_outProperty.empty())
1279                     mpClassCallback->setOutputProperty(objectClass->getDataElementIndex(j->_name), j->_outProperty);
1280             } else {
1281                 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown dataElement configuration type \""
1282                        << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1283             }
1284         }
1285     }
1286
1287     set_enabled(true);
1288     return is_enabled();
1289 }
1290
1291 bool
1292 FGHLA::process()
1293 {
1294     if (!is_enabled())
1295         return false;
1296
1297     if (!_hlaFederate.valid())
1298         return false;
1299
1300     // First push our own data so that others can recieve ...
1301     if (get_direction() & SG_IO_OUT)
1302         _hlaFederate->updateLocalAircraftInstance();
1303
1304     // Then get news from others and process possible update requests
1305     _hlaFederate->update();
1306
1307     return true;
1308 }
1309
1310 bool
1311 FGHLA::close()
1312 {
1313     if (!is_enabled())
1314         return false;
1315
1316     if (!_hlaFederate.valid())
1317         return false;
1318
1319     // Leave the federation and try to destroy the federation execution.
1320     _hlaFederate->shutdown();
1321     _hlaFederate = 0;
1322
1323     set_enabled(false);
1324
1325     return true;
1326 }
1327