]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIMultiplayer.cxx
Interim windows build fix
[flightgear.git] / src / AIModel / AIMultiplayer.cxx
index b2fe6b841636c38c11635aba75f25bdf0d64bcf8..a4176b3a6d7076fb0e0726a2051384a2dc827251 100644 (file)
 #endif
 
 #include <string>
+#include <stdio.h>
+
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
 
 #include "AIMultiplayer.hxx"
 
-#include <simgear/scene/util/SGNodeMasks.hxx>
+using std::string;
 
 // #define SG_DEBUG SG_ALERT
 
-FGAIMultiplayer::FGAIMultiplayer() : FGAIBase(otMultiplayer) {
+FGAIMultiplayer::FGAIMultiplayer() :
+   FGAIBase(otMultiplayer, fgGetBool("/sim/multiplay/hot", false))
+{
    no_roll = false;
 
    mTimeOffsetSet = false;
    mAllowExtrapolation = true;
    mLagAdjustSystemSpeed = 10;
+   mLastTimestamp = 0;
+   lastUpdateTime = 0;
+   playerLag = 0.03;
+   compensateLag = 1;
 
-   aip.getSceneGraph()->setNodeMask(~SG_NODEMASK_TERRAIN_BIT);
-
-}
-
+} 
 
 FGAIMultiplayer::~FGAIMultiplayer() {
 }
@@ -54,8 +61,8 @@ bool FGAIMultiplayer::init(bool search_in_AI_path) {
     isTanker = false; // do this until this property is
                       // passed over the net
 
-    string str1 = _getCallsign();
-    string str2 = "MOBIL";
+    const string& str1 = _getCallsign();
+    const string str2 = "MOBIL";
 
     string::size_type loc1= str1.find( str2, 0 );
     if ( (loc1 != string::npos && str2 != "") ){
@@ -63,18 +70,26 @@ bool FGAIMultiplayer::init(bool search_in_AI_path) {
         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->tie("tanker", SGRawValuePointer<bool>(&isTanker));
+    tie("refuel/contact", SGRawValuePointer<bool>(&contact));
+    tie("tanker", SGRawValuePointer<bool>(&isTanker));
 
-    props->tie("controls/invisible",
+    tie("controls/invisible",
         SGRawValuePointer<bool>(&invisible));
-
+       _uBodyNode = props->getNode("velocities/uBody-fps", true);
+       _vBodyNode = props->getNode("velocities/vBody-fps", true);
+       _wBodyNode = props->getNode("velocities/wBody-fps", true);
+       
 #define AIMPROProp(type, name) \
 SGRawValueMethods<FGAIMultiplayer, type>(*this, &FGAIMultiplayer::get##name)
 
@@ -82,30 +97,21 @@ 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("controls/allow-extrapolation",
-               AIMPRWProp(bool, AllowExtrapolation));
-    props->tie("controls/lag-adjust-system-speed",
-               AIMPRWProp(double, LagAdjustSystemSpeed));
+    //tie("callsign", AIMPROProp(const char *, CallSign));
 
+    tie("controls/allow-extrapolation",
+        AIMPRWProp(bool, AllowExtrapolation));
+    tie("controls/lag-adjust-system-speed",
+        AIMPRWProp(double, LagAdjustSystemSpeed));
+    tie("controls/player-lag",
+        AIMPRWProp(double, playerLag));
+    tie("controls/compensate-lag",
+        AIMPRWProp(int, compensateLag));
 
 #undef AIMPROProp
 #undef AIMPRWProp
 }
 
-void FGAIMultiplayer::unbind() {
-    FGAIBase::unbind();
-
-    //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;
@@ -142,11 +148,22 @@ void FGAIMultiplayer::update(double dt)
     mTimeOffsetSet = true;
     mTimeOffset = curentPkgTime - curtime - lag;
   } else {
-    double offset = curentPkgTime - curtime - lag;
+         double offset = 0.0;
+
+               //spectator mode, more late to be in the interpolation zone
+    if (compensateLag == 3) { offset = curentPkgTime -curtime -lag + playerLag;
+
+                 // old behaviour
+    } else if (compensateLag == 1) { offset = curentPkgTime - curtime - lag;
+
+    // using the prediction mode to display the mpaircraft in the futur/past with given playerlag value
+    //currently compensatelag = 2
+    } else { offset = curentPkgTime - curtime + 0.48*lag + playerLag;
+    }
     if ((!mAllowExtrapolation && offset + lag < mTimeOffset)
         || (offset - 10 > mTimeOffset)) {
       mTimeOffset = offset;
-      SG_LOG(SG_GENERAL, SG_DEBUG, "Resetting time offset adjust system to "
+      SG_LOG(SG_AI, SG_DEBUG, "Resetting time offset adjust system to "
              "avoid extrapolation: time offset = " << mTimeOffset);
     } else {
       // the error of the offset, respectively the negative error to avoid
@@ -156,14 +173,27 @@ void FGAIMultiplayer::update(double dt)
       // arriving packets will pessimize the overall lag much more than
       // early packets will shorten the overall lag
       double sysSpeed;
-      if (err < 0) {
-        // Ok, we have some very late packets and nothing newer increase the
-        // lag by the given speedadjust
-        sysSpeed = mLagAdjustSystemSpeed*err;
-      } else {
-        // We have a too pessimistic display delay shorten that a small bit
-        sysSpeed = SGMiscd::min(0.1*err*err, 0.5);
-      }
+
+  //trying to slow the rudderlag phenomenon thus using more the prediction system
+  //if we are off by less than 1.5s, do a little correction, and bigger step above 1.5s
+         if (fabs(err) < 1.5) {
+               if (err < 0) {
+                 sysSpeed = mLagAdjustSystemSpeed*err*0.01;
+           } else {
+               sysSpeed = SGMiscd::min(0.5*err*err, 0.05);
+               }
+         } else {
+               if (err < 0) {
+
+                       // Ok, we have some very late packets and nothing newer increase the
+                       // lag by the given speedadjust
+                       sysSpeed = mLagAdjustSystemSpeed*err;
+               } else {
+                       // We have a too pessimistic display delay shorten that a small bit
+                       sysSpeed = SGMiscd::min(0.1*err*err, 0.5);
+          }
+         }
+
 
       // simple euler integration for that first order system including some
       // overshooting guard to prevent to aggressive system speeds
@@ -173,7 +203,7 @@ void FGAIMultiplayer::update(double dt)
         systemIncrement = err;
       mTimeOffset += systemIncrement;
       
-      SG_LOG(SG_GENERAL, SG_DEBUG, "Offset adjust system: time offset = "
+      SG_LOG(SG_AI, SG_DEBUG, "Offset adjust system: time offset = "
              << mTimeOffset << ", expected longitudinal position error due to "
              " current adjustment of the offset: "
              << fabs(norm(it->second.linearVel)*systemIncrement));
@@ -187,6 +217,7 @@ void FGAIMultiplayer::update(double dt)
 
   SGVec3d ecPos;
   SGQuatf ecOrient;
+  SGVec3f ecLinearVel;
 
   if (tInterp <= curentPkgTime) {
     // Ok, we need a time prevous to the last available packet,
@@ -195,12 +226,13 @@ void FGAIMultiplayer::update(double dt)
     // Find the first packet before the target time
     MotionInfo::iterator nextIt = mMotionInfo.upper_bound(tInterp);
     if (nextIt == mMotionInfo.begin()) {
-      SG_LOG(SG_GENERAL, SG_DEBUG, "Taking oldest packet!");
+      SG_LOG(SG_AI, SG_DEBUG, "Taking oldest packet!");
       // We have no packet before the target time, just use the first one
       MotionInfo::iterator firstIt = mMotionInfo.begin();
       ecPos = firstIt->second.position;
       ecOrient = firstIt->second.orientation;
-      speed = norm(firstIt->second.linearVel) * SG_METER_TO_NM * 3600.0;
+      ecLinearVel = firstIt->second.linearVel;
+      speed = norm(ecLinearVel) * SG_METER_TO_NM * 3600.0;
 
       std::vector<FGPropertyData*>::const_iterator firstPropIt;
       std::vector<FGPropertyData*>::const_iterator firstPropItEnd;
@@ -238,7 +270,7 @@ void FGAIMultiplayer::update(double dt)
         }
         else
         {
-          SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
+          SG_LOG(SG_AI, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
         }
         ++firstPropIt;
       }
@@ -255,7 +287,7 @@ void FGAIMultiplayer::update(double dt)
       double intervalLen = intervalEnd - intervalStart;
       double tau = (tInterp - intervalStart)/intervalLen;
 
-      SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer vehicle interpolation: ["
+      SG_LOG(SG_AI, SG_DEBUG, "Multiplayer vehicle interpolation: ["
              << intervalStart << ", " << intervalEnd << "], intervalLen = "
              << intervalLen << ", interpolation parameter = " << tau);
 
@@ -263,8 +295,8 @@ void FGAIMultiplayer::update(double dt)
       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;
+      ecLinearVel = ((1-tau)*prevIt->second.linearVel + tau*nextIt->second.linearVel);
+      speed = norm(ecLinearVel) * SG_METER_TO_NM * 3600.0;
 
       if (prevIt->second.properties.size()
           == nextIt->second.properties.size()) {
@@ -318,7 +350,7 @@ void FGAIMultiplayer::update(double dt)
           }
           else
           {
-            SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*prevPropIt)->id << "\n");
+            SG_LOG(SG_AI, SG_DEBUG, "Unable to find property: " << (*prevPropIt)->id << "\n");
           }
           
           ++prevPropIt;
@@ -330,67 +362,48 @@ void FGAIMultiplayer::update(double dt)
       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
+    // The time to predict, limit to 3 seconds
     double t = tInterp - motionInfo.time;
-    t = SGMisc<double>::min(t, 5);
+    t = SGMisc<double>::min(t, 3);
 
-    SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer vehicle extrapolation: "
+    SG_LOG(SG_AI, SG_DEBUG, "Multiplayer vehicle extrapolation: "
            "extrapolation time = " << t);
 
-    // Do a few explicit euler steps with the constant acceleration's
-    // This must be sufficient ...
+    // using velocity and acceleration to guess a parabolic position...
     ecPos = motionInfo.position;
     ecOrient = motionInfo.orientation;
-    SGVec3f linearVel = motionInfo.linearVel;
+    ecLinearVel = motionInfo.linearVel;
+    SGVec3d ecVel = toVec3d(ecOrient.backTransform(ecLinearVel));
     SGVec3f angularVel = motionInfo.angularVel;
-    while (0 < t) {
-      double h = 1e-1;
-      if (t < h)
-        h = t;
+    SGVec3d ecAcc = toVec3d(ecOrient.backTransform(motionInfo.linearAccel));
 
-      SGVec3d ecVel = toVec3d(ecOrient.backTransform(linearVel));
-      ecPos += h*ecVel;
-      ecOrient += h*ecOrient.derivative(angularVel);
+       double normVel = norm(ecVel);
 
-      linearVel += h*(cross(linearVel, angularVel) + motionInfo.linearAccel);
-      angularVel += h*motionInfo.angularAccel;
-      
-      t -= h;
-    }
+       // not doing rotationnal prediction for small speed or rotation rate,
+       // to avoid agitated parked plane
+    if (( norm(angularVel) > 0.05 ) || ( normVel > 1.0 )) {
+               ecOrient += t*ecOrient.derivative(angularVel);
+       }
 
-    std::vector<FGPropertyData*>::const_iterator firstPropIt;
+       // not using acceleration for small speed, to have better parked planes
+       // note that anyway acceleration is not transmit yet by mp
+       if ( normVel > 1.0 ) {
+               ecPos += t*(ecVel + 0.5*t*ecAcc);
+       } else {
+               ecPos += t*(ecVel);
+       }
+
+       std::vector<FGPropertyData*>::const_iterator firstPropIt;
     std::vector<FGPropertyData*>::const_iterator firstPropItEnd;
-    speed = norm(linearVel) * SG_METER_TO_NM * 3600.0;
+    speed = norm(ecLinearVel) * SG_METER_TO_NM * 3600.0;
     firstPropIt = it->second.properties.begin();
     firstPropItEnd = it->second.properties.end();
     while (firstPropIt != firstPropItEnd) {
@@ -425,7 +438,7 @@ void FGAIMultiplayer::update(double dt)
       }
       else
       {
-        SG_LOG(SG_GENERAL, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
+        SG_LOG(SG_AI, SG_DEBUG, "Unable to find property: " << (*firstPropIt)->id << "\n");
       }
       
       ++firstPropIt;
@@ -434,8 +447,21 @@ void FGAIMultiplayer::update(double dt)
   
   // 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(),
@@ -448,7 +474,12 @@ void FGAIMultiplayer::update(double dt)
   roll = rDeg;
   pitch = pDeg;
 
-  SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer position and orientation: "
+  // expose velocities/u,v,wbody-fps in the mp tree
+  _uBodyNode->setValue(ecLinearVel[0] * SG_METER_TO_FEET);
+  _vBodyNode->setValue(ecLinearVel[1] * SG_METER_TO_FEET);
+  _wBodyNode->setValue(ecLinearVel[2] * SG_METER_TO_FEET);
+
+  SG_LOG(SG_AI, SG_DEBUG, "Multiplayer position and orientation: "
          << ecPos << ", " << hlOr);
 
   //###########################//
@@ -483,7 +514,7 @@ void FGAIMultiplayer::update(double dt)
 }
 
 void
-FGAIMultiplayer::addMotionInfo(const FGExternalMotionData& motionInfo,
+FGAIMultiplayer::addMotionInfo(FGExternalMotionData& motionInfo,
                                long stamp)
 {
   mLastTimestamp = stamp;
@@ -500,6 +531,9 @@ FGAIMultiplayer::addMotionInfo(const FGExternalMotionData& motionInfo,
       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