Move ticks adjustment to main_loop

This commit is contained in:
Benau 2018-07-01 14:31:42 +08:00
parent 75c8864e8f
commit d3f7cb7999
6 changed files with 54 additions and 105 deletions

View File

@ -51,12 +51,11 @@ MainLoop* main_loop = 0;
// ----------------------------------------------------------------------------
MainLoop::MainLoop(unsigned parent_pid)
: m_abort(false), m_parent_pid(parent_pid)
: m_abort(false), m_ticks_adjustment(0), m_parent_pid(parent_pid)
{
m_curr_time = 0;
m_prev_time = 0;
m_throttle_fps = true;
m_is_last_substep = false;
m_frame_before_loading_world = false;
#ifdef WIN32
if (parent_pid != 0)
@ -183,16 +182,6 @@ float MainLoop::getLimitedDt()
} // while(1)
dt *= 0.001f;
// If this is a client, the server might request an adjustment of
// this client's world clock (to reduce number of rewinds).
if (World::getWorld() &&
NetworkConfig::get()->isClient() &&
!RewindManager::get()->isRewinding() )
{
dt = World::getWorld()->adjustDT(dt);
}
return dt;
} // getLimitedDt
@ -325,11 +314,11 @@ void MainLoop::run()
if (m_parent_pid != 0 && getppid() != (int)m_parent_pid)
m_abort = true;
#endif
m_is_last_substep = false;
PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7);
left_over_time += getLimitedDt();
int num_steps = stk_config->time2Ticks(left_over_time);
float dt = stk_config->ticks2Time(1);
left_over_time -= num_steps * dt ;
@ -391,11 +380,33 @@ void MainLoop::run()
PROFILER_POP_CPU_MARKER();
}
m_ticks_adjustment.lock();
if (m_ticks_adjustment.getData() != 0)
{
if (m_ticks_adjustment.getData() > 0)
{
num_steps += m_ticks_adjustment.getData();
m_ticks_adjustment.getData() = 0;
}
else if (m_ticks_adjustment.getData() < 0)
{
int new_steps = num_steps + m_ticks_adjustment.getData();
if (new_steps < 0)
{
num_steps = 0;
m_ticks_adjustment.getData() = new_steps;
}
else
{
num_steps = new_steps;
m_ticks_adjustment.getData() = 0;
}
}
}
m_ticks_adjustment.unlock();
for(int i=0; i<num_steps; i++)
{
// Enable last substep in last iteration
m_is_last_substep = (i == num_steps - 1);
PROFILER_PUSH_CPU_MARKER("Update race", 0, 255, 255);
if (World::getWorld()) updateRace(1);
PROFILER_POP_CPU_MARKER();
@ -444,7 +455,6 @@ void MainLoop::run()
if (auto gp = GameProtocol::lock())
gp->sendAllActions();
}
m_is_last_substep = false;
PROFILER_POP_CPU_MARKER(); // MainLoop pop
PROFILER_SYNC_FRAME();
} // while !m_abort

View File

@ -20,7 +20,8 @@
#ifndef HEADER_MAIN_LOOP_HPP
#define HEADER_MAIN_LOOP_HPP
typedef unsigned long Uint32;
#include "utils/synchronised.hpp"
#include "utils/types.hpp"
#include <atomic>
/** Management class for the whole gameflow, this is where the
@ -35,12 +36,11 @@ private:
bool m_throttle_fps;
bool m_frame_before_loading_world;
/** True during the last substep of the inner main loop (where world
* is updated). Used to reduce amount of updates (e.g. sfx positions
* etc). */
bool m_is_last_substep;
Uint32 m_curr_time;
Uint32 m_prev_time;
Synchronised<int> m_ticks_adjustment;
uint32_t m_curr_time;
uint32_t m_prev_time;
unsigned m_parent_pid;
float getLimitedDt();
void updateRace(int ticks);
@ -55,6 +55,14 @@ public:
bool isAborted() const { return m_abort; }
// ------------------------------------------------------------------------
void setFrameBeforeLoadingWorld() { m_frame_before_loading_world = true; }
// ------------------------------------------------------------------------
void setTicksAdjustment(int ticks)
{
m_ticks_adjustment.lock();
m_ticks_adjustment.getData() += ticks;
m_ticks_adjustment.unlock();
}
}; // MainLoop
extern MainLoop* main_loop;

View File

@ -63,7 +63,6 @@ WorldStatus::WorldStatus()
void WorldStatus::reset()
{
m_time = 0.0f;
m_adjust_time_by.store(0);
m_time_ticks = 0;
m_auxiliary_ticks = 0;
m_count_up_ticks = 0;
@ -473,66 +472,6 @@ void WorldStatus::updateTime(int ticks)
} // switch m_phase
} // update
//-----------------------------------------------------------------------------
/** If the server requests that a client's time should be adjusted,
* smoothly change the clock speed of this client to go a bit faster
* or slower till the overall adjustment was reached.
* \param dt Original time step size.
*/
float WorldStatus::adjustDT(float dt)
{
int adjust_time = m_adjust_time_by.load();
if (adjust_time == 0)
return dt;
// If request, adjust world time to go ahead (adjust>0) or
// slow down (<0). This is done in 5% of dt steps so that the
// user will not notice this.
const float FRACTION = 0.10f; // fraction of dt to be adjusted
float adjust_time_by = adjust_time / 1000.0f;
float time_adjust;
if (adjust_time_by > 0.0f) // make it run faster
{
time_adjust = dt * FRACTION;
if (time_adjust > adjust_time_by)
{
m_adjust_time_by.fetch_sub(int(adjust_time_by * 1000.f));
time_adjust = adjust_time_by;
}
else
m_adjust_time_by.fetch_sub(int(time_adjust * 1000.f));
Log::verbose("WorldStatus",
"At %f %f adjusting time (speed up) by %f dt %f to dt %f for %f",
World::getWorld()->getTime(), StkTime::getRealTime(),
time_adjust, dt, dt + time_adjust, adjust_time_by);
}
else // adjust_time_by negative, i.e. will go slower
{
time_adjust = -dt * FRACTION;
if (time_adjust < adjust_time_by)
{
m_adjust_time_by.fetch_sub(int(adjust_time_by * 1000.f));
time_adjust = adjust_time_by;
}
else
m_adjust_time_by.fetch_sub(int(time_adjust * 1000.f));
Log::verbose("WorldStatus",
"At %f %f adjusting time (slow down) by %f dt %f to dt %f for %f",
World::getWorld()->getTime(), StkTime::getRealTime(),
time_adjust, dt, dt + time_adjust, adjust_time_by);
}
dt += time_adjust;
// No negative or tends to zero dt
const float min_dt = stk_config->ticks2Time(1);
if (dt < min_dt)
dt = min_dt;
return dt;
} // adjustDT
//-----------------------------------------------------------------------------
/** Called on the client when it receives a notification from the server that
* all clients (and server) are ready to start the race. The server will

View File

@ -107,15 +107,6 @@ private:
/** The third sound to be played in ready, set, go. */
SFXBase *m_start_sound;
/** In networked game the world clock might be adjusted (without the
* player noticing), e.g. if a client causes rewinds in the server,
* that client needs to speed up to be further ahead of the server
* or slow down if time in client goes too far from server time
* to reduce the number of rollbacks. This is the amount of time
* by which the client's clock needs to be adjusted (positive or
* negative). */
std::atomic<int> m_adjust_time_by;
/** The clock mode: normal counting forwards, or countdown */
ClockType m_clock_mode;
protected:
@ -163,7 +154,6 @@ public:
virtual void terminateRace();
void setTime(const float time);
void setTicks(int ticks);
float adjustDT(float dt);
// ------------------------------------------------------------------------
// Note: GO_PHASE is both: start phase and race phase
@ -219,10 +209,6 @@ public:
int getTicksSinceStart() const { return m_count_up_ticks; }
// ------------------------------------------------------------------------
void setReadyToRace() { m_server_is_ready.store(true); }
// ------------------------------------------------------------------------
/** Sets a time by which the clock should be adjusted. Used by networking
* if too many rewinds are detected. */
void setAdjustTime(int t) { m_adjust_time_by.fetch_add(t); }
}; // WorldStatus

View File

@ -33,6 +33,7 @@
#include "network/stk_peer.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
#include "main_loop.hpp"
// ============================================================================
std::weak_ptr<GameProtocol> GameProtocol::m_game_protocol;
@ -214,8 +215,7 @@ void GameProtocol::handleControllerAction(Event *event)
const int ticks_difference = m_initial_ticks.at(event->getPeer());
if (will_trigger_rewind)
{
if (rewind_delta > max_adjustment)
rewind_delta = max_adjustment;
rewind_delta += max_adjustment;
Log::info("GameProtocol", "At %d %f %d requesting time adjust"
" (speed up) of %d for host %d",
World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
@ -229,8 +229,7 @@ void GameProtocol::handleControllerAction(Event *event)
if (cur_diff > 0 &&
cur_diff - ticks_difference > max_adjustment)
{
// 80% slow down
const int adjustment = -max_adjustment * 8 / 10;
const int adjustment = ticks_difference - cur_diff;
Log::info("GameProtocol", "At %d %f %d requesting time adjust"
" (slow down) of %d for host %d",
World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
@ -251,11 +250,17 @@ void GameProtocol::handleControllerAction(Event *event)
void GameProtocol::adjustTimeForClient(STKPeer *peer, int ticks)
{
assert(NetworkConfig::get()->isServer());
if (m_last_adjustments.find(peer) != m_last_adjustments.end() &&
StkTime::getRealTime() - m_last_adjustments.at(peer) < 3.0)
return;
NetworkString *ns = getNetworkString(5);
ns->addUInt8(GP_ADJUST_TIME).addUInt32(ticks);
// This message can be send unreliable, it's not critical if it doesn't
// get delivered, the server will request again later anyway.
peer->sendPacket(ns, /*reliable*/false);
m_last_adjustments[peer] = StkTime::getRealTime();
delete ns;
} // adjustTimeForClient
@ -266,8 +271,8 @@ void GameProtocol::adjustTimeForClient(STKPeer *peer, int ticks)
void GameProtocol::handleAdjustTime(Event *event)
{
int ticks = event->data().getUInt32();
World::getWorld()->setAdjustTime(
int(stk_config->ticks2Time(ticks) * 1000.0f));
main_loop->setTicksAdjustment(ticks);
Log::verbose("GameProtocol", "%d ticks adjustment", ticks);
} // handleAdjustTime
// ----------------------------------------------------------------------------

View File

@ -74,6 +74,7 @@ private:
void handleItemEventConfirmation(Event *event);
static std::weak_ptr<GameProtocol> m_game_protocol;
std::map<STKPeer*, int> m_initial_ticks;
std::map<STKPeer*, double> m_last_adjustments;
public:
GameProtocol();