diff --git a/src/main_loop.cpp b/src/main_loop.cpp index 9bc909c53..8dbb84115 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -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; isendAllActions(); } - m_is_last_substep = false; PROFILER_POP_CPU_MARKER(); // MainLoop pop PROFILER_SYNC_FRAME(); } // while !m_abort diff --git a/src/main_loop.hpp b/src/main_loop.hpp index 574628a48..1d28405d2 100644 --- a/src/main_loop.hpp +++ b/src/main_loop.hpp @@ -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 /** 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 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; diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index a0874995d..5b01f8a82 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -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 diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp index 4240891bb..dc905904c 100644 --- a/src/modes/world_status.hpp +++ b/src/modes/world_status.hpp @@ -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 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 diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index ab9caaf53..ca19236c7 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -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::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 // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/game_protocol.hpp b/src/network/protocols/game_protocol.hpp index 22681bbb2..4e1f387fe 100644 --- a/src/network/protocols/game_protocol.hpp +++ b/src/network/protocols/game_protocol.hpp @@ -74,6 +74,7 @@ private: void handleItemEventConfirmation(Event *event); static std::weak_ptr m_game_protocol; std::map m_initial_ticks; + std::map m_last_adjustments; public: GameProtocol();