1
0
Fork 0

a new clock following real time pace, for mp protocol

the current timestamp used in mp protocol and in AImultiplayer is not a good one:
it can pause, or even change speed if we change warp value.
we want it to be used for network protocol lag and jitter estimation, and
a time flowing linearly on both side is needed, here's a first introduction
of this timestamp relates to real elapsed time.
here it's initialised to the system clock, then follow the monotonic clock.
in future improvement, it will allow time synchronisation betwen mp players,
to have a very good close formation flight experience.
This commit is contained in:
jean pellotier 2018-01-24 23:29:41 +01:00
parent 4d28146796
commit b9b280abd1
4 changed files with 40 additions and 8 deletions

View file

@ -30,6 +30,7 @@
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Time/TimeManager.hxx>
#include "AIMultiplayer.hxx"
@ -128,7 +129,8 @@ void FGAIMultiplayer::update(double dt)
// The current simulation time we need to update for,
// note that the simulation time is updated before calling all the
// update methods. Thus it contains the time intervals *end* time
double curtime = globals->get_sim_time_sec();
// 2018: notice this time is specifically used for mp protocol
double curtime = globals->get_subsystem<TimeManager>()->getMPProtocolClockSec();
// Get the last available time
MotionInfo::reverse_iterator it = mMotionInfo.rbegin();

View file

@ -50,6 +50,7 @@
#include "mpmessages.hxx"
#include "MPServerResolver.hxx"
#include <FDM/flightProperties.hxx>
#include <Time/TimeManager.hxx>
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <WS2tcpip.h>
@ -1825,11 +1826,13 @@ FGMultiplayMgr::Send()
mTimeUntilSend = mDt;
}
double sim_time = globals->get_sim_time_sec();
// we are now using a time immune to pause, warp etc as timestamp.
double mp_time = globals->get_subsystem<TimeManager>()->getMPProtocolClockSec();
// static double lastTime = 0.0;
// SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime);
// lastTime = sim_time;
// SG_LOG(SG_GENERAL, SG_INFO, "actual mp dt=" << mp_time - lastTime);
// lastTime = mp_time;
FlightProperties ifce;
@ -1841,7 +1844,7 @@ FGMultiplayMgr::Send()
// note that the simulation time is updated before calling all the
// update methods. Thus it contains the time intervals *end* time.
// The FDM is already run, so the states belong to that time.
motionInfo.time = sim_time;
motionInfo.time = mp_time;
motionInfo.lag = mDt;
// These are for now converted from lat/lon/alt and euler angles.

View file

@ -75,6 +75,7 @@ void TimeManager::init()
_firstUpdate = true;
_inited = true;
_dtRemainder = 0.0;
_mpProtocolClock = 0.0;
_adjustWarpOnUnfreeze = false;
_maxDtPerFrame = fgGetNode("/sim/max-simtime-per-frame", true);
@ -112,6 +113,7 @@ void TimeManager::init()
_modelHz = fgGetNode("sim/model-hz", true);
_timeDelta = fgGetNode("sim/time/delta-realtime-sec", true);
_simTimeDelta = fgGetNode("sim/time/delta-sec", true);
_mpClockNode = fgGetNode("sim/time/mp-clock-sec", true);
_simTimeFactor = fgGetNode("/sim/speed-up", true);
// use pre-set value but ensure we get a sane default
@ -135,6 +137,7 @@ void TimeManager::unbind()
_modelHz.clear();
_timeDelta.clear();
_simTimeDelta.clear();
_mpClockNode.clear();
_simTimeFactor.clear();
}
@ -182,6 +185,11 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
// Update the elapsed time.
if (_firstUpdate) {
_lastStamp.stamp();
// we initialise the mp protocol clock with the system clock.
_systemStamp.systemClockHoursAndMinutes();
_mpProtocolClock = _systemStamp.toSecs();
_firstUpdate = false;
_lastClockFreeze = _clockFreeze->getBoolValue();
}
@ -196,10 +204,16 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
_lastFrameTime=0;
_frameCount = 0;
}
SGTimeStamp currentStamp;
currentStamp.stamp();
// this dt will be clamped by the max sim time by frame.
double dt = (currentStamp - _lastStamp).toSecs();
// here we have a true real dt for a clock "real time".
double mpProtocolDt = dt;
if (dt > _frameLatencyMax)
_frameLatencyMax = dt;
@ -221,14 +235,19 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
double modelHz = _modelHz->getDoubleValue();
fdmGroup->set_fixed_update_time(1.0 / modelHz);
// round the real time down to a multiple of 1/model-hz.
// this way all systems are updated the _same_ amount of dt.
dt += _dtRemainder;
// we keep the mp clock sync with the sim time, as it's used as timestamp
// in fdm state,
mpProtocolDt += _dtRemainder;
int multiLoop = long(floor(dt * modelHz));
multiLoop = SGMisc<long>::max(0, multiLoop);
_dtRemainder = dt - double(multiLoop)/modelHz;
dt = double(multiLoop)/modelHz;
mpProtocolDt -= _dtRemainder;
realDt = dt;
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
@ -237,9 +256,12 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
// sim time can be scaled
simDt = dt * _simTimeFactor->getDoubleValue();
}
_lastStamp = currentStamp;
globals->inc_sim_time_sec(simDt);
_mpProtocolClock += mpProtocolDt;
_mpClockNode->setDoubleValue(_mpProtocolClock);
// These are useful, especially for Nasal scripts.
_timeDelta->setDoubleValue(realDt);

View file

@ -46,6 +46,8 @@ public:
void valueChanged(SGPropertyNode *) override;
void setTimeOffset(const std::string& offset_type, long int offset);
inline double getMPProtocolClockSec() const { return _mpProtocolClock; }
static const char* subsystemName() { return "time"; }
private:
@ -69,6 +71,7 @@ private:
bool _inited;
SGTime* _impl;
SGTimeStamp _lastStamp;
SGTimeStamp _systemStamp;
bool _firstUpdate;
double _dtRemainder;
SGPropertyNode_ptr _maxDtPerFrame;
@ -77,6 +80,7 @@ private:
SGPropertyNode_ptr _warp;
SGPropertyNode_ptr _warpDelta;
SGPropertyNode_ptr _simTimeFactor;
SGPropertyNode_ptr _mpClockNode;
bool _lastClockFreeze;
bool _adjustWarpOnUnfreeze;
@ -87,6 +91,7 @@ private:
SGPropertyNode_ptr _frameLatency;
time_t _lastFrameTime;
double _frameLatencyMax;
double _mpProtocolClock;
int _frameCount;
SGPropertyNode_ptr _sceneryLoaded;