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:
parent
4d28146796
commit
b9b280abd1
4 changed files with 40 additions and 8 deletions
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <Time/TimeManager.hxx>
|
||||||
|
|
||||||
#include "AIMultiplayer.hxx"
|
#include "AIMultiplayer.hxx"
|
||||||
|
|
||||||
|
@ -128,7 +129,8 @@ void FGAIMultiplayer::update(double dt)
|
||||||
// The current simulation time we need to update for,
|
// The current simulation time we need to update for,
|
||||||
// note that the simulation time is updated before calling all the
|
// note that the simulation time is updated before calling all the
|
||||||
// update methods. Thus it contains the time intervals *end* time
|
// 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
|
// Get the last available time
|
||||||
MotionInfo::reverse_iterator it = mMotionInfo.rbegin();
|
MotionInfo::reverse_iterator it = mMotionInfo.rbegin();
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "mpmessages.hxx"
|
#include "mpmessages.hxx"
|
||||||
#include "MPServerResolver.hxx"
|
#include "MPServerResolver.hxx"
|
||||||
#include <FDM/flightProperties.hxx>
|
#include <FDM/flightProperties.hxx>
|
||||||
|
#include <Time/TimeManager.hxx>
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
#include <WS2tcpip.h>
|
#include <WS2tcpip.h>
|
||||||
|
@ -1825,11 +1826,13 @@ FGMultiplayMgr::Send()
|
||||||
mTimeUntilSend = mDt;
|
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;
|
// static double lastTime = 0.0;
|
||||||
|
|
||||||
// SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime);
|
// SG_LOG(SG_GENERAL, SG_INFO, "actual mp dt=" << mp_time - lastTime);
|
||||||
// lastTime = sim_time;
|
// lastTime = mp_time;
|
||||||
|
|
||||||
FlightProperties ifce;
|
FlightProperties ifce;
|
||||||
|
|
||||||
|
@ -1841,7 +1844,7 @@ FGMultiplayMgr::Send()
|
||||||
// note that the simulation time is updated before calling all the
|
// note that the simulation time is updated before calling all the
|
||||||
// update methods. Thus it contains the time intervals *end* time.
|
// update methods. Thus it contains the time intervals *end* time.
|
||||||
// The FDM is already run, so the states belong to that time.
|
// The FDM is already run, so the states belong to that time.
|
||||||
motionInfo.time = sim_time;
|
motionInfo.time = mp_time;
|
||||||
motionInfo.lag = mDt;
|
motionInfo.lag = mDt;
|
||||||
|
|
||||||
// These are for now converted from lat/lon/alt and euler angles.
|
// These are for now converted from lat/lon/alt and euler angles.
|
||||||
|
|
|
@ -75,6 +75,7 @@ void TimeManager::init()
|
||||||
_firstUpdate = true;
|
_firstUpdate = true;
|
||||||
_inited = true;
|
_inited = true;
|
||||||
_dtRemainder = 0.0;
|
_dtRemainder = 0.0;
|
||||||
|
_mpProtocolClock = 0.0;
|
||||||
_adjustWarpOnUnfreeze = false;
|
_adjustWarpOnUnfreeze = false;
|
||||||
|
|
||||||
_maxDtPerFrame = fgGetNode("/sim/max-simtime-per-frame", true);
|
_maxDtPerFrame = fgGetNode("/sim/max-simtime-per-frame", true);
|
||||||
|
@ -112,6 +113,7 @@ void TimeManager::init()
|
||||||
_modelHz = fgGetNode("sim/model-hz", true);
|
_modelHz = fgGetNode("sim/model-hz", true);
|
||||||
_timeDelta = fgGetNode("sim/time/delta-realtime-sec", true);
|
_timeDelta = fgGetNode("sim/time/delta-realtime-sec", true);
|
||||||
_simTimeDelta = fgGetNode("sim/time/delta-sec", true);
|
_simTimeDelta = fgGetNode("sim/time/delta-sec", true);
|
||||||
|
_mpClockNode = fgGetNode("sim/time/mp-clock-sec", true);
|
||||||
|
|
||||||
_simTimeFactor = fgGetNode("/sim/speed-up", true);
|
_simTimeFactor = fgGetNode("/sim/speed-up", true);
|
||||||
// use pre-set value but ensure we get a sane default
|
// use pre-set value but ensure we get a sane default
|
||||||
|
@ -135,6 +137,7 @@ void TimeManager::unbind()
|
||||||
_modelHz.clear();
|
_modelHz.clear();
|
||||||
_timeDelta.clear();
|
_timeDelta.clear();
|
||||||
_simTimeDelta.clear();
|
_simTimeDelta.clear();
|
||||||
|
_mpClockNode.clear();
|
||||||
_simTimeFactor.clear();
|
_simTimeFactor.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +185,11 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
// Update the elapsed time.
|
// Update the elapsed time.
|
||||||
if (_firstUpdate) {
|
if (_firstUpdate) {
|
||||||
_lastStamp.stamp();
|
_lastStamp.stamp();
|
||||||
|
|
||||||
|
// we initialise the mp protocol clock with the system clock.
|
||||||
|
_systemStamp.systemClockHoursAndMinutes();
|
||||||
|
_mpProtocolClock = _systemStamp.toSecs();
|
||||||
|
|
||||||
_firstUpdate = false;
|
_firstUpdate = false;
|
||||||
_lastClockFreeze = _clockFreeze->getBoolValue();
|
_lastClockFreeze = _clockFreeze->getBoolValue();
|
||||||
}
|
}
|
||||||
|
@ -196,10 +204,16 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
_lastFrameTime=0;
|
_lastFrameTime=0;
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGTimeStamp currentStamp;
|
SGTimeStamp currentStamp;
|
||||||
currentStamp.stamp();
|
currentStamp.stamp();
|
||||||
|
|
||||||
|
// this dt will be clamped by the max sim time by frame.
|
||||||
double dt = (currentStamp - _lastStamp).toSecs();
|
double dt = (currentStamp - _lastStamp).toSecs();
|
||||||
|
|
||||||
|
// here we have a true real dt for a clock "real time".
|
||||||
|
double mpProtocolDt = dt;
|
||||||
|
|
||||||
if (dt > _frameLatencyMax)
|
if (dt > _frameLatencyMax)
|
||||||
_frameLatencyMax = dt;
|
_frameLatencyMax = dt;
|
||||||
|
|
||||||
|
@ -221,14 +235,19 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
|
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
|
||||||
double modelHz = _modelHz->getDoubleValue();
|
double modelHz = _modelHz->getDoubleValue();
|
||||||
fdmGroup->set_fixed_update_time(1.0 / modelHz);
|
fdmGroup->set_fixed_update_time(1.0 / modelHz);
|
||||||
|
|
||||||
// round the real time down to a multiple of 1/model-hz.
|
// round the real time down to a multiple of 1/model-hz.
|
||||||
// this way all systems are updated the _same_ amount of dt.
|
// this way all systems are updated the _same_ amount of dt.
|
||||||
dt += _dtRemainder;
|
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));
|
int multiLoop = long(floor(dt * modelHz));
|
||||||
multiLoop = SGMisc<long>::max(0, multiLoop);
|
multiLoop = SGMisc<long>::max(0, multiLoop);
|
||||||
_dtRemainder = dt - double(multiLoop)/modelHz;
|
_dtRemainder = dt - double(multiLoop)/modelHz;
|
||||||
dt = double(multiLoop)/modelHz;
|
dt = double(multiLoop)/modelHz;
|
||||||
|
mpProtocolDt -= _dtRemainder;
|
||||||
|
|
||||||
realDt = dt;
|
realDt = dt;
|
||||||
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
|
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
|
||||||
|
@ -237,9 +256,12 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
// sim time can be scaled
|
// sim time can be scaled
|
||||||
simDt = dt * _simTimeFactor->getDoubleValue();
|
simDt = dt * _simTimeFactor->getDoubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastStamp = currentStamp;
|
_lastStamp = currentStamp;
|
||||||
globals->inc_sim_time_sec(simDt);
|
globals->inc_sim_time_sec(simDt);
|
||||||
|
_mpProtocolClock += mpProtocolDt;
|
||||||
|
|
||||||
|
_mpClockNode->setDoubleValue(_mpProtocolClock);
|
||||||
|
|
||||||
// These are useful, especially for Nasal scripts.
|
// These are useful, especially for Nasal scripts.
|
||||||
_timeDelta->setDoubleValue(realDt);
|
_timeDelta->setDoubleValue(realDt);
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
void valueChanged(SGPropertyNode *) override;
|
void valueChanged(SGPropertyNode *) override;
|
||||||
|
|
||||||
void setTimeOffset(const std::string& offset_type, long int offset);
|
void setTimeOffset(const std::string& offset_type, long int offset);
|
||||||
|
|
||||||
|
inline double getMPProtocolClockSec() const { return _mpProtocolClock; }
|
||||||
|
|
||||||
static const char* subsystemName() { return "time"; }
|
static const char* subsystemName() { return "time"; }
|
||||||
private:
|
private:
|
||||||
|
@ -69,6 +71,7 @@ private:
|
||||||
bool _inited;
|
bool _inited;
|
||||||
SGTime* _impl;
|
SGTime* _impl;
|
||||||
SGTimeStamp _lastStamp;
|
SGTimeStamp _lastStamp;
|
||||||
|
SGTimeStamp _systemStamp;
|
||||||
bool _firstUpdate;
|
bool _firstUpdate;
|
||||||
double _dtRemainder;
|
double _dtRemainder;
|
||||||
SGPropertyNode_ptr _maxDtPerFrame;
|
SGPropertyNode_ptr _maxDtPerFrame;
|
||||||
|
@ -77,6 +80,7 @@ private:
|
||||||
SGPropertyNode_ptr _warp;
|
SGPropertyNode_ptr _warp;
|
||||||
SGPropertyNode_ptr _warpDelta;
|
SGPropertyNode_ptr _warpDelta;
|
||||||
SGPropertyNode_ptr _simTimeFactor;
|
SGPropertyNode_ptr _simTimeFactor;
|
||||||
|
SGPropertyNode_ptr _mpClockNode;
|
||||||
|
|
||||||
bool _lastClockFreeze;
|
bool _lastClockFreeze;
|
||||||
bool _adjustWarpOnUnfreeze;
|
bool _adjustWarpOnUnfreeze;
|
||||||
|
@ -87,6 +91,7 @@ private:
|
||||||
SGPropertyNode_ptr _frameLatency;
|
SGPropertyNode_ptr _frameLatency;
|
||||||
time_t _lastFrameTime;
|
time_t _lastFrameTime;
|
||||||
double _frameLatencyMax;
|
double _frameLatencyMax;
|
||||||
|
double _mpProtocolClock;
|
||||||
int _frameCount;
|
int _frameCount;
|
||||||
|
|
||||||
SGPropertyNode_ptr _sceneryLoaded;
|
SGPropertyNode_ptr _sceneryLoaded;
|
||||||
|
|
Loading…
Add table
Reference in a new issue