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
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue