Move ticks adjustment to main_loop
This commit is contained in:
parent
75c8864e8f
commit
d3f7cb7999
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user