Merge pull request #1257 from immibis/1164-fix

When game speed is 2 or higher, run multiple ticks.
fix-quicksave-sim-speed-crash
Mateusz Przybył 2020-07-14 22:41:05 +02:00 committed by GitHub
commit 174669ec92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 76 additions and 20 deletions

View File

@ -1060,6 +1060,12 @@ int CApplication::Run()
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)
{
if (m_active)
@ -1158,21 +1164,30 @@ int CApplication::Run()
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL);
// Prepare and process step simulation event
Event event = CreateUpdateEvent();
if (event.type != EVENT_NULL && m_controller != nullptr)
// Prepare and process step simulation event(s)
// If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy.
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);
m_controller->ProcessEvent(event);
CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME);
CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME);
m_controller->ProcessEvent(event);
CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME);
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE);
m_engine->FrameUpdate();
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE);
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE);
m_engine->FrameUpdate();
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE);
}
}
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL);
@ -1188,6 +1203,10 @@ int CApplication::Run()
}
end:
m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp);
m_systemUtils->DestroyTimeStamp(currentTimeStamp);
m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp);
return m_exitCode;
}
@ -1529,20 +1548,20 @@ void CApplication::SetSimulationSpeed(float speed)
{
m_simulationSpeed = speed;
m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp);
m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp);
m_realAbsTimeBase = m_realAbsTime;
m_absTimeBase = m_exactAbsTime;
GetLogger()->Info("Simulation speed = %.2f\n", speed);
}
Event CApplication::CreateUpdateEvent()
Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp)
{
if (m_simulationSuspended)
return Event(EVENT_NULL);
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 newRealAbsTime = m_realAbsTimeBase + absDiff;

View File

@ -289,7 +289,7 @@ protected:
//! If applicable, creates a virtual event to match the changed state as of new event
Event CreateVirtualEvent(const Event& sourceEvent);
//! Prepares a simulation update event
TEST_VIRTUAL Event CreateUpdateEvent();
TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp);
//! Logs debug data for event
void LogEvent(const Event& event);

View File

@ -116,6 +116,9 @@ public:
//! Copies the time stamp from \a src to \a dst
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
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;

View File

@ -83,6 +83,19 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
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)
{
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);

View File

@ -40,6 +40,7 @@ public:
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;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;

View File

@ -34,6 +34,11 @@ void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp)
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)
{
return (after->sdlTicks - before->sdlTicks) * 1000000ll;

View File

@ -46,6 +46,7 @@ public:
void Init() 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;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;

View File

@ -83,6 +83,11 @@ void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp)
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)
{
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));

View File

@ -38,6 +38,7 @@ public:
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;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;

View File

@ -55,9 +55,9 @@ public:
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,
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_FLOAT_EQ(relTime, event.rTime);
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)
{
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);
}
@ -224,7 +230,9 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation)
NextInstant(-1111);
Event event = m_app->CreateUpdateEvent();
SystemTimeStamp *now = CreateTimeStamp();
GetCurrentTimeStamp(now);
Event event = m_app->CreateUpdateEvent(now);
EXPECT_EQ(EVENT_NULL, event.type);
}