If multiplayer record is enabled, carry on recording while replaying.
This background recording keeps the user aircraft stationary while recording all movements of multiplayer aircraft. Allows one to look at replay without, for example, disturbing continuous record to file.
This commit is contained in:
parent
15915b5a79
commit
001c1d231d
4 changed files with 143 additions and 81 deletions
|
@ -325,85 +325,112 @@ FGFlightRecorder::capture(double SimTime, FGReplayData* ReplayData)
|
|||
if (!ReplayData)
|
||||
return NULL;
|
||||
}
|
||||
int Offset = 0;
|
||||
|
||||
// When replaying, we are able to carry recording live multiplayer
|
||||
// information. To make this work we need to record a stationay
|
||||
// user aircraft, with information from the last live user aircraft
|
||||
// FGReplayData. So we store the last live user aircraft information in
|
||||
// this static vector.
|
||||
//
|
||||
static std::vector<char> s_recent_raw_data;
|
||||
|
||||
int in_replay = fgGetInt("/sim/replay/replay-state");
|
||||
|
||||
ReplayData->sim_time = SimTime;
|
||||
ReplayData->raw_data.resize( m_TotalRecordSize);
|
||||
char* pBuffer = &ReplayData->raw_data.front();
|
||||
|
||||
// 64bit aligned data first!
|
||||
{
|
||||
// capture doubles
|
||||
double* pDoubles = (double*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureDouble.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pDoubles[i] = m_CaptureDouble[i].Signal->getDoubleValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(double);
|
||||
}
|
||||
|
||||
// 32bit aligned data comes second...
|
||||
{
|
||||
// capture floats
|
||||
float* pFloats = (float*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureFloat.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pFloats[i] = m_CaptureFloat[i].Signal->getFloatValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(float);
|
||||
}
|
||||
|
||||
{
|
||||
// capture integers (32bit aligned)
|
||||
int* pInt = (int*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInteger.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pInt[i] = m_CaptureInteger[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(int);
|
||||
}
|
||||
|
||||
// 16bit aligned data is next...
|
||||
{
|
||||
// capture 16bit short integers
|
||||
short int* pShortInt = (short int*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInt16.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pShortInt[i] = (short int) m_CaptureInt16[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(short int);
|
||||
}
|
||||
|
||||
// finally: byte aligned data is last...
|
||||
{
|
||||
// capture 8bit chars
|
||||
signed char* pChar = (signed char*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInt8.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pChar[i] = (signed char) m_CaptureInt8[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(signed char);
|
||||
}
|
||||
|
||||
{
|
||||
// capture 1bit booleans (8bit aligned)
|
||||
unsigned char* pFlags = (unsigned char*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureBool.size();
|
||||
int Size = (SignalCount+7)/8;
|
||||
Offset += Size;
|
||||
memset(pFlags,0,Size);
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
if (m_CaptureBool[i].Signal->getBoolValue())
|
||||
pFlags[i>>3] |= 1 << (i&7);
|
||||
}
|
||||
if (in_replay) {
|
||||
// Record the fixed position of live user aircraft at the point at
|
||||
// which we started replay.
|
||||
//
|
||||
ReplayData->raw_data = s_recent_raw_data;
|
||||
}
|
||||
else {
|
||||
// Find live information about the user aircraft.
|
||||
//
|
||||
int Offset = 0;
|
||||
ReplayData->raw_data.resize( m_TotalRecordSize);
|
||||
char* pBuffer = &ReplayData->raw_data.front();
|
||||
|
||||
assert(Offset + sizeof(double) == m_TotalRecordSize);
|
||||
// 64bit aligned data first!
|
||||
{
|
||||
// capture doubles
|
||||
double* pDoubles = (double*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureDouble.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pDoubles[i] = m_CaptureDouble[i].Signal->getDoubleValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(double);
|
||||
}
|
||||
|
||||
// 32bit aligned data comes second...
|
||||
{
|
||||
// capture floats
|
||||
float* pFloats = (float*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureFloat.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pFloats[i] = m_CaptureFloat[i].Signal->getFloatValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(float);
|
||||
}
|
||||
|
||||
{
|
||||
// capture integers (32bit aligned)
|
||||
int* pInt = (int*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInteger.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pInt[i] = m_CaptureInteger[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(int);
|
||||
}
|
||||
|
||||
// 16bit aligned data is next...
|
||||
{
|
||||
// capture 16bit short integers
|
||||
short int* pShortInt = (short int*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInt16.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pShortInt[i] = (short int) m_CaptureInt16[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(short int);
|
||||
}
|
||||
|
||||
// finally: byte aligned data is last...
|
||||
{
|
||||
// capture 8bit chars
|
||||
signed char* pChar = (signed char*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureInt8.size();
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
pChar[i] = (signed char) m_CaptureInt8[i].Signal->getIntValue();
|
||||
}
|
||||
Offset += SignalCount * sizeof(signed char);
|
||||
}
|
||||
|
||||
{
|
||||
// capture 1bit booleans (8bit aligned)
|
||||
unsigned char* pFlags = (unsigned char*) &pBuffer[Offset];
|
||||
unsigned int SignalCount = m_CaptureBool.size();
|
||||
int Size = (SignalCount+7)/8;
|
||||
Offset += Size;
|
||||
memset(pFlags,0,Size);
|
||||
for (unsigned int i=0; i<SignalCount; i++)
|
||||
{
|
||||
if (m_CaptureBool[i].Signal->getBoolValue())
|
||||
pFlags[i>>3] |= 1 << (i&7);
|
||||
}
|
||||
}
|
||||
|
||||
assert(Offset + sizeof(double) == m_TotalRecordSize);
|
||||
|
||||
// Update s_recent_raw_data so that we will be able to carry recording
|
||||
// while replaying.
|
||||
//
|
||||
s_recent_raw_data = ReplayData->raw_data;
|
||||
}
|
||||
|
||||
// If m_ReplayMultiplayer is true, move all recent
|
||||
// multiplayer messages from m_MultiplayMgr into
|
||||
|
@ -423,6 +450,15 @@ FGFlightRecorder::capture(double SimTime, FGReplayData* ReplayData)
|
|||
}
|
||||
ReplayData->UpdateStats();
|
||||
|
||||
// Note that if we are replaying, <ReplayData> will contain the last live
|
||||
// position of the live user aircraft, plus any multiplayer packets that
|
||||
// have arrived recently. If there were no recent multiplayer packets,
|
||||
// then there's no actually no need to record anything (unless we're at the
|
||||
// start of recording).
|
||||
//
|
||||
// But for now at least, we don't try to optimise the recording like that.
|
||||
//
|
||||
|
||||
return ReplayData;
|
||||
}
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ FGReplay::init()
|
|||
replay_looped = fgGetNode("/sim/replay/looped", true);
|
||||
replay_duration_act = fgGetNode("/sim/replay/duration-act", true);
|
||||
speed_up = fgGetNode("/sim/speed-up", true);
|
||||
replay_multiplayer = fgGetNode("/sim/replay/multiplayer", true);
|
||||
|
||||
// alias to keep backward compatibility
|
||||
fgGetNode("/sim/freeze/replay-state", true)->alias(replay_master);
|
||||
|
@ -724,10 +725,24 @@ FGReplay::update( double dt )
|
|||
if (ResetTime)
|
||||
replay_master->setIntValue(replay_state);
|
||||
|
||||
return; // don't record the replay session
|
||||
if (replay_multiplayer->getIntValue()) {
|
||||
// Carry on recording while replaying.
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// Don't record while replaying.
|
||||
return;
|
||||
}
|
||||
}
|
||||
case 2: // normal replay operation
|
||||
return; // don't record the replay session
|
||||
if (replay_multiplayer->getIntValue()) {
|
||||
// Carry on recording while replaying.
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// Don't record while replaying.
|
||||
return;
|
||||
}
|
||||
default:
|
||||
throw sg_range_exception("unknown FGReplay state");
|
||||
}
|
||||
|
@ -749,6 +764,9 @@ FGReplay::update( double dt )
|
|||
sim_time = new_sim_time;
|
||||
}
|
||||
|
||||
// We still record even if we are replaying, if /sim/replay/multiplayer is
|
||||
// true.
|
||||
//
|
||||
FGReplayData* r = record(sim_time);
|
||||
if (!r)
|
||||
{
|
||||
|
|
|
@ -151,6 +151,7 @@ private:
|
|||
SGPropertyNode_ptr replay_looped;
|
||||
SGPropertyNode_ptr replay_duration_act;
|
||||
SGPropertyNode_ptr speed_up;
|
||||
SGPropertyNode_ptr replay_multiplayer;
|
||||
double replay_time_prev; // Used to detect jumps while replaying.
|
||||
|
||||
double m_high_res_time; // default: 60 secs of high res data
|
||||
|
|
|
@ -1765,21 +1765,28 @@ int FGMultiplayMgr::GetMsg(MsgBuf& msgBuf, simgear::IPAddress& SenderAddress)
|
|||
for(;;) {
|
||||
|
||||
if (mReplayMessageQueue.empty()) {
|
||||
// No recorded messages available, so look for chat messages
|
||||
// only from <mSocket>.
|
||||
// No recorded messages available, so look for live messages
|
||||
// from <mSocket>.
|
||||
//
|
||||
int RecvStatus = GetMsgNetwork(msgBuf, SenderAddress);
|
||||
if (RecvStatus == 0) {
|
||||
// No recorded messages, and no live messages, so return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Always record all messages.
|
||||
//
|
||||
std::shared_ptr<std::vector<char>> data( new std::vector<char>(RecvStatus));
|
||||
memcpy( &data->front(), msgBuf.Msg, RecvStatus);
|
||||
mRecordMessageQueue.push_back(data);
|
||||
|
||||
if (msgBuf.Header.MsgId == CHAT_MSG_ID) {
|
||||
return RecvStatus;
|
||||
}
|
||||
|
||||
// If we get here, there is a live message but it is a
|
||||
// multiplayer aircraft position so we ignore it while
|
||||
// replaying.
|
||||
//
|
||||
}
|
||||
else {
|
||||
// Replay recorded message, unless it is a chat message.
|
||||
|
@ -1789,7 +1796,7 @@ int FGMultiplayMgr::GetMsg(MsgBuf& msgBuf, simgear::IPAddress& SenderAddress)
|
|||
assert(replayMessage->size() <= sizeof(msgBuf));
|
||||
int length = replayMessage->size();
|
||||
memcpy(&msgBuf.Msg, &replayMessage->front(), length);
|
||||
// Don't return chat messages.
|
||||
// Don't return recorded chat messages.
|
||||
if (msgBuf.Header.MsgId != CHAT_MSG_ID) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO,
|
||||
"replaying message length=" << replayMessage->size()
|
||||
|
|
Loading…
Add table
Reference in a new issue