Merge pull request #1257 from immibis/1164-fix
When game speed is 2 or higher, run multiple ticks.fix-quicksave-sim-speed-crash
commit
174669ec92
|
@ -1060,6 +1060,12 @@ int CApplication::Run()
|
||||||
|
|
||||||
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
|
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
|
||||||
|
|
||||||
|
SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp();
|
||||||
|
SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp();
|
||||||
|
SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp();
|
||||||
|
m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp);
|
||||||
|
m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (m_active)
|
if (m_active)
|
||||||
|
@ -1158,21 +1164,30 @@ int CApplication::Run()
|
||||||
|
|
||||||
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL);
|
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL);
|
||||||
|
|
||||||
// Prepare and process step simulation event
|
// Prepare and process step simulation event(s)
|
||||||
Event event = CreateUpdateEvent();
|
// If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy.
|
||||||
if (event.type != EVENT_NULL && m_controller != nullptr)
|
int numTickSlices = static_cast<int>(GetSimulationSpeed());
|
||||||
|
if(numTickSlices < 1) numTickSlices = 1;
|
||||||
|
m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp);
|
||||||
|
m_systemUtils->GetCurrentTimeStamp(currentTimeStamp);
|
||||||
|
for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
|
||||||
{
|
{
|
||||||
LogEvent(event);
|
m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
|
||||||
|
Event event = CreateUpdateEvent(interpolatedTimeStamp);
|
||||||
|
if (event.type != EVENT_NULL && m_controller != nullptr)
|
||||||
|
{
|
||||||
|
LogEvent(event);
|
||||||
|
|
||||||
m_sound->FrameMove(m_relTime);
|
m_sound->FrameMove(m_relTime);
|
||||||
|
|
||||||
CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME);
|
CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME);
|
||||||
m_controller->ProcessEvent(event);
|
m_controller->ProcessEvent(event);
|
||||||
CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME);
|
CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME);
|
||||||
|
|
||||||
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE);
|
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE);
|
||||||
m_engine->FrameUpdate();
|
m_engine->FrameUpdate();
|
||||||
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE);
|
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL);
|
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL);
|
||||||
|
@ -1188,6 +1203,10 @@ int CApplication::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp);
|
||||||
|
m_systemUtils->DestroyTimeStamp(currentTimeStamp);
|
||||||
|
m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp);
|
||||||
|
|
||||||
return m_exitCode;
|
return m_exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1529,20 +1548,20 @@ void CApplication::SetSimulationSpeed(float speed)
|
||||||
{
|
{
|
||||||
m_simulationSpeed = speed;
|
m_simulationSpeed = speed;
|
||||||
|
|
||||||
m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp);
|
m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp);
|
||||||
m_realAbsTimeBase = m_realAbsTime;
|
m_realAbsTimeBase = m_realAbsTime;
|
||||||
m_absTimeBase = m_exactAbsTime;
|
m_absTimeBase = m_exactAbsTime;
|
||||||
|
|
||||||
GetLogger()->Info("Simulation speed = %.2f\n", speed);
|
GetLogger()->Info("Simulation speed = %.2f\n", speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event CApplication::CreateUpdateEvent()
|
Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp)
|
||||||
{
|
{
|
||||||
if (m_simulationSuspended)
|
if (m_simulationSuspended)
|
||||||
return Event(EVENT_NULL);
|
return Event(EVENT_NULL);
|
||||||
|
|
||||||
m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
|
m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
|
||||||
m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp);
|
m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp);
|
||||||
|
|
||||||
long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
|
long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
|
||||||
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
|
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
|
||||||
|
|
|
@ -289,7 +289,7 @@ protected:
|
||||||
//! If applicable, creates a virtual event to match the changed state as of new event
|
//! If applicable, creates a virtual event to match the changed state as of new event
|
||||||
Event CreateVirtualEvent(const Event& sourceEvent);
|
Event CreateVirtualEvent(const Event& sourceEvent);
|
||||||
//! Prepares a simulation update event
|
//! Prepares a simulation update event
|
||||||
TEST_VIRTUAL Event CreateUpdateEvent();
|
TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp);
|
||||||
//! Logs debug data for event
|
//! Logs debug data for event
|
||||||
void LogEvent(const Event& event);
|
void LogEvent(const Event& event);
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,9 @@ public:
|
||||||
//! Copies the time stamp from \a src to \a dst
|
//! Copies the time stamp from \a src to \a dst
|
||||||
TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
|
TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
|
||||||
|
|
||||||
|
//! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between.
|
||||||
|
virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0;
|
||||||
|
|
||||||
//! Returns a time stamp associated with current time
|
//! Returns a time stamp associated with current time
|
||||||
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;
|
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,19 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
|
||||||
|
{
|
||||||
|
long long delta = TimeStampExactDiff(a, b);
|
||||||
|
delta *= i; // truncates
|
||||||
|
dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000;
|
||||||
|
dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000;
|
||||||
|
if(dst->clockTime.tv_nsec >= 1000000000)
|
||||||
|
{
|
||||||
|
dst->clockTime.tv_nsec -= 1000000000;
|
||||||
|
dst->clockTime.tv_sec++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
|
void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
|
||||||
{
|
{
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
|
|
||||||
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
||||||
|
|
||||||
|
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
|
||||||
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
||||||
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,11 @@ void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp)
|
||||||
stamp->sdlTicks = SDL_GetTicks();
|
stamp->sdlTicks = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
|
||||||
|
{
|
||||||
|
dst->sdlTicks = a->sdlTicks + static_cast<Uint32>((b->sdlTicks - a->sdlTicks) * i);
|
||||||
|
}
|
||||||
|
|
||||||
long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
|
long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
|
||||||
{
|
{
|
||||||
return (after->sdlTicks - before->sdlTicks) * 1000000ll;
|
return (after->sdlTicks - before->sdlTicks) * 1000000ll;
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
void Init() override;
|
void Init() override;
|
||||||
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
||||||
|
|
||||||
|
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
|
||||||
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
||||||
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,11 @@ void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp)
|
||||||
stamp->counterValue = value.QuadPart;
|
stamp->counterValue = value.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
|
||||||
|
{
|
||||||
|
dst->counterValue = a->counterValue + static_cast<long long>((b->counterValue - a->counterValue) * static_cast<double>(i));
|
||||||
|
}
|
||||||
|
|
||||||
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
|
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
|
||||||
{
|
{
|
||||||
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
|
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
|
|
||||||
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
|
||||||
|
|
||||||
|
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
|
||||||
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
|
||||||
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ public:
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Event CreateUpdateEvent() override
|
Event CreateUpdateEvent(SystemTimeStamp *timestamp) override
|
||||||
{
|
{
|
||||||
return CApplication::CreateUpdateEvent();
|
return CApplication::CreateUpdateEvent(timestamp);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,7 +157,9 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs
|
||||||
float relTime, float absTime,
|
float relTime, float absTime,
|
||||||
long long relTimeReal, long long absTimeReal)
|
long long relTimeReal, long long absTimeReal)
|
||||||
{
|
{
|
||||||
Event event = m_app->CreateUpdateEvent();
|
SystemTimeStamp *now = CreateTimeStamp();
|
||||||
|
GetCurrentTimeStamp(now);
|
||||||
|
Event event = m_app->CreateUpdateEvent(now);
|
||||||
EXPECT_EQ(EVENT_FRAME, event.type);
|
EXPECT_EQ(EVENT_FRAME, event.type);
|
||||||
EXPECT_FLOAT_EQ(relTime, event.rTime);
|
EXPECT_FLOAT_EQ(relTime, event.rTime);
|
||||||
EXPECT_FLOAT_EQ(relTime, m_app->GetRelTime());
|
EXPECT_FLOAT_EQ(relTime, m_app->GetRelTime());
|
||||||
|
@ -172,7 +174,11 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs
|
||||||
TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended)
|
TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended)
|
||||||
{
|
{
|
||||||
m_app->SuspendSimulation();
|
m_app->SuspendSimulation();
|
||||||
Event event = m_app->CreateUpdateEvent();
|
|
||||||
|
SystemTimeStamp *now = CreateTimeStamp();
|
||||||
|
GetCurrentTimeStamp(now);
|
||||||
|
Event event = m_app->CreateUpdateEvent(now);
|
||||||
|
|
||||||
EXPECT_EQ(EVENT_NULL, event.type);
|
EXPECT_EQ(EVENT_NULL, event.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +230,9 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation)
|
||||||
|
|
||||||
NextInstant(-1111);
|
NextInstant(-1111);
|
||||||
|
|
||||||
Event event = m_app->CreateUpdateEvent();
|
SystemTimeStamp *now = CreateTimeStamp();
|
||||||
|
GetCurrentTimeStamp(now);
|
||||||
|
Event event = m_app->CreateUpdateEvent(now);
|
||||||
EXPECT_EQ(EVENT_NULL, event.type);
|
EXPECT_EQ(EVENT_NULL, event.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue