#include "AIMultiplayer.hxx"
+#include <simgear/scene/util/SGNodeMasks.hxx>
+
// #define SG_DEBUG SG_ALERT
FGAIMultiplayer::FGAIMultiplayer() : FGAIBase(otMultiplayer) {
mTimeOffsetSet = false;
mAllowExtrapolation = true;
mLagAdjustSystemSpeed = 10;
-}
+ mLastTimestamp = 0;
+ aip.getSceneGraph()->setNodeMask(~SG_NODEMASK_TERRAIN_BIT);
+ lastUpdateTime = 0;
+}
FGAIMultiplayer::~FGAIMultiplayer() {
}
isTanker = true;
// cout << "isTanker " << isTanker << " " << mCallSign <<endl;
}
- return FGAIBase::init(search_in_AI_path);
+
+ // load model
+ bool result = FGAIBase::init(search_in_AI_path);
+ // propagate installation state (used by MP pilot list)
+ props->setBoolValue("model-installed", _installed);
+ return result;
}
void FGAIMultiplayer::bind() {
FGAIBase::bind();
props->tie("refuel/contact", SGRawValuePointer<bool>(&contact));
- props->setBoolValue("tanker",isTanker);
+ props->tie("tanker", SGRawValuePointer<bool>(&isTanker));
+
+ props->tie("controls/invisible",
+ SGRawValuePointer<bool>(&invisible));
#define AIMPROProp(type, name) \
SGRawValueMethods<FGAIMultiplayer, type>(*this, &FGAIMultiplayer::get##name)
//props->untie("callsign");
props->untie("controls/allow-extrapolation");
props->untie("controls/lag-adjust-system-speed");
+ props->untie("controls/invisible");
props->untie("refuel/contact");
+ props->untie("tanker");
+
}
void FGAIMultiplayer::update(double dt)
{
- using namespace simgear::props;
+ using namespace simgear;
if (dt <= 0)
return;
{
//cout << "Found " << pIt->second->getPath() << ":";
switch ((*firstPropIt)->type) {
- case INT:
- case BOOL:
- case LONG:
+ case props::INT:
+ case props::BOOL:
+ case props::LONG:
pIt->second->setIntValue((*firstPropIt)->int_value);
//cout << "Int: " << (*firstPropIt)->int_value << "\n";
break;
- case FLOAT:
- case DOUBLE:
+ case props::FLOAT:
+ case props::DOUBLE:
pIt->second->setFloatValue((*firstPropIt)->float_value);
//cout << "Flo: " << (*firstPropIt)->float_value << "\n";
break;
- case STRING:
- case UNSPECIFIED:
+ case props::STRING:
+ case props::UNSPECIFIED:
pIt->second->setStringValue((*firstPropIt)->string_value);
//cout << "Str: " << (*firstPropIt)->string_value << "\n";
break;
int ival;
float val;
switch ((*prevPropIt)->type) {
- case INT:
- case BOOL:
- case LONG:
+ case props::INT:
+ case props::BOOL:
+ case props::LONG:
ival = (int) (0.5+(1-tau)*((double) (*prevPropIt)->int_value) +
tau*((double) (*nextPropIt)->int_value));
pIt->second->setIntValue(ival);
//cout << "Int: " << ival << "\n";
break;
- case FLOAT:
- case DOUBLE:
+ case props::FLOAT:
+ case props::DOUBLE:
val = (1-tau)*(*prevPropIt)->float_value +
tau*(*nextPropIt)->float_value;
//cout << "Flo: " << val << "\n";
pIt->second->setFloatValue(val);
break;
- case STRING:
- case UNSPECIFIED:
+ case props::STRING:
+ case props::UNSPECIFIED:
//cout << "Str: " << (*nextPropIt)->string_value << "\n";
pIt->second->setStringValue((*nextPropIt)->string_value);
break;
if (prevIt != mMotionInfo.begin())
{
--prevIt;
-
- MotionInfo::iterator delIt;
- delIt = mMotionInfo.begin();
-
- while (delIt != prevIt)
- {
- std::vector<FGPropertyData*>::const_iterator propIt;
- std::vector<FGPropertyData*>::const_iterator propItEnd;
- propIt = delIt->second.properties.begin();
- propItEnd = delIt->second.properties.end();
-
- //cout << "Deleting data\n";
-
- while (propIt != propItEnd)
- {
- delete *propIt;
- propIt++;
- }
-
- delIt++;
- }
-
mMotionInfo.erase(mMotionInfo.begin(), prevIt);
}
}
} else {
// Ok, we need to predict the future, so, take the best data we can have
// and do some eom computation to guess that for now.
- FGExternalMotionData motionInfo = it->second;
+ FGExternalMotionData& motionInfo = it->second;
// The time to predict, limit to 5 seconds
double t = tInterp - motionInfo.time;
if (pIt != mPropertyMap.end())
{
switch ((*firstPropIt)->type) {
- case INT:
- case BOOL:
- case LONG:
+ case props::INT:
+ case props::BOOL:
+ case props::LONG:
pIt->second->setIntValue((*firstPropIt)->int_value);
//cout << "Int: " << (*firstPropIt)->int_value << "\n";
break;
- case FLOAT:
- case DOUBLE:
+ case props::FLOAT:
+ case props::DOUBLE:
pIt->second->setFloatValue((*firstPropIt)->float_value);
//cout << "Flo: " << (*firstPropIt)->float_value << "\n";
break;
- case STRING:
- case UNSPECIFIED:
+ case props::STRING:
+ case props::UNSPECIFIED:
pIt->second->setStringValue((*firstPropIt)->string_value);
//cout << "Str: " << (*firstPropIt)->string_value << "\n";
break;
// extract the position
pos = SGGeod::fromCart(ecPos);
+ double recent_alt_ft = altitude_ft;
altitude_ft = pos.getElevationFt();
+ // expose a valid vertical speed
+ if (lastUpdateTime != 0)
+ {
+ double dT = curtime - lastUpdateTime;
+ double Weighting=1;
+ if (dt < 1.0)
+ Weighting = dt;
+ // simple smoothing over 1 second
+ vs = (1.0-Weighting)*vs + Weighting * (altitude_ft - recent_alt_ft) / dT * 60;
+ }
+ lastUpdateTime = curtime;
+
// The quaternion rotating from the earth centered frame to the
// horizontal local frame
SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)pos.getLongitudeRad(),
if ( isTanker) {
+ //cout << "IS tanker ";
if ( (range_ft2 < 250.0 * 250.0) &&
(y_shift > 0.0) &&
(elevation > 0.0) ){
// refuel_node->setBoolValue(true);
+ //cout << "in contact" << endl;
contact = true;
} else {
// refuel_node->setBoolValue(false);
+ //cout << "not in contact" << endl;
contact = false;
}
} else {
+ //cout << "NOT tanker " << endl;
contact = false;
}
}
void
-FGAIMultiplayer::addMotionInfo(const FGExternalMotionData& motionInfo,
+FGAIMultiplayer::addMotionInfo(FGExternalMotionData& motionInfo,
long stamp)
{
mLastTimestamp = stamp;
return;
}
mMotionInfo[motionInfo.time] = motionInfo;
+ // We just copied the property (pointer) list - they are ours now. Clear the
+ // properties list in given/returned object, so former owner won't deallocate them.
+ motionInfo.properties.clear();
}
void