#include "AIMultiplayer.hxx"
+
// #define SG_DEBUG SG_ALERT
-FGAIMultiplayer::FGAIMultiplayer() : FGAIBase(otMultiplayer) {
+FGAIMultiplayer::FGAIMultiplayer() :
+ FGAIBase(otMultiplayer, false)
+{
no_roll = false;
mTimeOffsetSet = false;
mAllowExtrapolation = true;
mLagAdjustSystemSpeed = 10;
-}
+ mLastTimestamp = 0;
+ lastUpdateTime = 0;
+}
FGAIMultiplayer::~FGAIMultiplayer() {
}
-bool FGAIMultiplayer::init() {
+bool FGAIMultiplayer::init(bool search_in_AI_path) {
+ props->setStringValue("sim/model/path", model_path.c_str());
//refuel_node = fgGetNode("systems/refuel/contact", true);
isTanker = false; // do this until this property is
// passed over the net
- string str1 = mCallSign;
+ string str1 = _getCallsign();
string str2 = "MOBIL";
- unsigned int loc1= str1.find( str2, 0 );
+ string::size_type loc1= str1.find( str2, 0 );
if ( (loc1 != string::npos && str2 != "") ){
// cout << " string found " << str2 << " in " << str1 << endl;
isTanker = true;
// cout << "isTanker " << isTanker << " " << mCallSign <<endl;
}
- return FGAIBase::init();
+
+ // 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)
SGRawValueMethods<FGAIMultiplayer, type>(*this, \
&FGAIMultiplayer::get##name, &FGAIMultiplayer::set##name)
- props->tie("callsign", AIMPROProp(const char *, CallSign));
+ //props->tie("callsign", AIMPROProp(const char *, CallSign));
props->tie("controls/allow-extrapolation",
AIMPRWProp(bool, AllowExtrapolation));
void FGAIMultiplayer::unbind() {
FGAIBase::unbind();
- props->untie("callsign");
+ //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;
+
if (dt <= 0)
return;
mTimeOffset = curentPkgTime - curtime - lag;
} else {
double offset = curentPkgTime - curtime - lag;
- if (!mAllowExtrapolation && offset + lag < mTimeOffset) {
+ if ((!mAllowExtrapolation && offset + lag < mTimeOffset)
+ || (offset - 10 > mTimeOffset)) {
mTimeOffset = offset;
SG_LOG(SG_GENERAL, SG_DEBUG, "Resetting time offset adjust system to "
"avoid extrapolation: time offset = " << mTimeOffset);
SGVec3d ecPos;
SGQuatf ecOrient;
+
if (tInterp <= curentPkgTime) {
// Ok, we need a time prevous to the last available packet,
// that is good ...
MotionInfo::iterator firstIt = mMotionInfo.begin();
ecPos = firstIt->second.position;
ecOrient = firstIt->second.orientation;
+ speed = norm(firstIt->second.linearVel) * SG_METER_TO_NM * 3600.0;
- std::vector<FGFloatPropertyData>::const_iterator firstPropIt;
- std::vector<FGFloatPropertyData>::const_iterator firstPropItEnd;
+ std::vector<FGPropertyData*>::const_iterator firstPropIt;
+ std::vector<FGPropertyData*>::const_iterator firstPropItEnd;
firstPropIt = firstIt->second.properties.begin();
firstPropItEnd = firstIt->second.properties.end();
while (firstPropIt != firstPropItEnd) {
- float val = firstPropIt->value;
- PropertyMap::iterator pIt = mPropertyMap.find(firstPropIt->id);
+ //cout << " Setting property..." << (*firstPropIt)->id;
+ PropertyMap::iterator pIt = mPropertyMap.find((*firstPropIt)->id);
if (pIt != mPropertyMap.end())
- pIt->second->setFloatValue(val);
+ {
+ //cout << "Found " << pIt->second->getPath() << ":";
+ switch ((*firstPropIt)->type) {
+ case props::INT:
+ case props::BOOL:
+ case props::LONG:
+ pIt->second->setIntValue((*firstPropIt)->int_value);
+ //cout << "Int: " << (*firstPropIt)->int_value << "\n";
+ break;
+ case props::FLOAT:
+ case props::DOUBLE:
+ pIt->second->setFloatValue((*firstPropIt)->float_value);
+ //cout << "Flo: " << (*firstPropIt)->float_value << "\n";
+ break;
+ case props::STRING:
+ case props::UNSPECIFIED:
+ pIt->second->setStringValue((*firstPropIt)->string_value);
+ //cout << "Str: " << (*firstPropIt)->string_value << "\n";
+ break;
+ default:
+ // FIXME - currently defaults to float values
+ pIt->second->setFloatValue((*firstPropIt)->float_value);
+ //cout << "Unknown: " << (*firstPropIt)->float_value << "\n";
+ break;
+ }
+ }
+ else
+ {
+ SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
+ }
++firstPropIt;
}
ecPos = ((1-tau)*prevIt->second.position + tau*nextIt->second.position);
ecOrient = interpolate((float)tau, prevIt->second.orientation,
nextIt->second.orientation);
+ speed = norm((1-tau)*prevIt->second.linearVel
+ + tau*nextIt->second.linearVel) * SG_METER_TO_NM * 3600.0;
if (prevIt->second.properties.size()
== nextIt->second.properties.size()) {
- std::vector<FGFloatPropertyData>::const_iterator prevPropIt;
- std::vector<FGFloatPropertyData>::const_iterator prevPropItEnd;
- std::vector<FGFloatPropertyData>::const_iterator nextPropIt;
- std::vector<FGFloatPropertyData>::const_iterator nextPropItEnd;
+ std::vector<FGPropertyData*>::const_iterator prevPropIt;
+ std::vector<FGPropertyData*>::const_iterator prevPropItEnd;
+ std::vector<FGPropertyData*>::const_iterator nextPropIt;
+ std::vector<FGPropertyData*>::const_iterator nextPropItEnd;
prevPropIt = prevIt->second.properties.begin();
prevPropItEnd = prevIt->second.properties.end();
nextPropIt = nextIt->second.properties.begin();
nextPropItEnd = nextIt->second.properties.end();
while (prevPropIt != prevPropItEnd) {
- float val = (1-tau)*prevPropIt->value + tau*nextPropIt->value;
- PropertyMap::iterator pIt = mPropertyMap.find(prevPropIt->id);
+ PropertyMap::iterator pIt = mPropertyMap.find((*prevPropIt)->id);
+ //cout << " Setting property..." << (*prevPropIt)->id;
+
if (pIt != mPropertyMap.end())
- pIt->second->setFloatValue(val);
+ {
+ //cout << "Found " << pIt->second->getPath() << ":";
+
+ int ival;
+ float val;
+ switch ((*prevPropIt)->type) {
+ 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 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 props::STRING:
+ case props::UNSPECIFIED:
+ //cout << "Str: " << (*nextPropIt)->string_value << "\n";
+ pIt->second->setStringValue((*nextPropIt)->string_value);
+ break;
+ default:
+ // FIXME - currently defaults to float values
+ val = (1-tau)*(*prevPropIt)->float_value +
+ tau*(*nextPropIt)->float_value;
+ //cout << "Unk: " << val << "\n";
+ pIt->second->setFloatValue(val);
+ break;
+ }
+ }
+ else
+ {
+ SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*prevPropIt)->id << "\n");
+ }
+
++prevPropIt;
++nextPropIt;
}
}
// Now throw away too old data
- if (prevIt != mMotionInfo.begin()) {
+ if (prevIt != mMotionInfo.begin())
+ {
--prevIt;
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;
t -= h;
}
- std::vector<FGFloatPropertyData>::const_iterator firstPropIt;
- std::vector<FGFloatPropertyData>::const_iterator firstPropItEnd;
+ std::vector<FGPropertyData*>::const_iterator firstPropIt;
+ std::vector<FGPropertyData*>::const_iterator firstPropItEnd;
+ speed = norm(linearVel) * SG_METER_TO_NM * 3600.0;
firstPropIt = it->second.properties.begin();
firstPropItEnd = it->second.properties.end();
while (firstPropIt != firstPropItEnd) {
- float val = firstPropIt->value;
- PropertyMap::iterator pIt = mPropertyMap.find(firstPropIt->id);
+ PropertyMap::iterator pIt = mPropertyMap.find((*firstPropIt)->id);
+ //cout << " Setting property..." << (*firstPropIt)->id;
+
if (pIt != mPropertyMap.end())
- pIt->second->setFloatValue(val);
+ {
+ switch ((*firstPropIt)->type) {
+ case props::INT:
+ case props::BOOL:
+ case props::LONG:
+ pIt->second->setIntValue((*firstPropIt)->int_value);
+ //cout << "Int: " << (*firstPropIt)->int_value << "\n";
+ break;
+ case props::FLOAT:
+ case props::DOUBLE:
+ pIt->second->setFloatValue((*firstPropIt)->float_value);
+ //cout << "Flo: " << (*firstPropIt)->float_value << "\n";
+ break;
+ case props::STRING:
+ case props::UNSPECIFIED:
+ pIt->second->setStringValue((*firstPropIt)->string_value);
+ //cout << "Str: " << (*firstPropIt)->string_value << "\n";
+ break;
+ default:
+ // FIXME - currently defaults to float values
+ pIt->second->setFloatValue((*firstPropIt)->float_value);
+ //cout << "Unk: " << (*firstPropIt)->float_value << "\n";
+ break;
+ }
+ }
+ else
+ {
+ SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
+ }
+
++firstPropIt;
}
}
// 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;
- // Drop packets arriving out of order
- if (!mMotionInfo.empty() && motionInfo.time < mMotionInfo.rbegin()->first)
- return;
+
+ if (!mMotionInfo.empty()) {
+ double diff = motionInfo.time - mMotionInfo.rbegin()->first;
+
+ // packet is very old -- MP has probably reset (incl. his timebase)
+ if (diff < -10.0)
+ mMotionInfo.clear();
+
+ // drop packets arriving out of order
+ else if (diff < 0.0)
+ 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
SGPropertyNode* pNode = props->getChild(prop.c_str(), true);
pNode->setDoubleValue(val);
}
-