Save an initial state at t=0 on the client, to make sure they

can always rewind (e.g. in case that an event from another client
arrives before a state from the server).
This commit is contained in:
hiker 2018-04-17 18:42:16 +10:00
parent 70e7625282
commit a9a73e643b
5 changed files with 50 additions and 16 deletions

View File

@ -302,6 +302,14 @@ void WorldStatus::updateTime(int ticks)
{
// set phase is over, go to the next one
m_phase = GO_PHASE;
// Save one initial state on a client, in case that an event
// is received from a client (trieggering a rollback) before
// a state from the server has been received.
if (NetworkConfig::get()->isClient())
{
RewindManager::get()->saveLocalState();
// FIXME TODO: save state in rewind queue!
}
if (m_play_ready_set_go_sounds)
{
m_start_sound->play();

View File

@ -245,18 +245,22 @@ void GameProtocol::handleAdjustTime(Event *event)
// ----------------------------------------------------------------------------
/** Called by the server before assembling a new message containing the full
* state of the race to be sent to a client.
* \param allow_local_save If set it allows a state to be saved on a client.
* \param local_save If set it allows a state to be saved on a client.
* This only happens at the very first time step to ensure each client
* has a state in case it receives an event before a server state.
*/
void GameProtocol::startNewState(bool allow_local_save)
void GameProtocol::startNewState(bool local_save)
{
assert(allow_local_save || NetworkConfig::get()->isServer());
assert(local_save || NetworkConfig::get()->isServer());
m_data_to_send->clear();
m_data_to_send->addUInt8(GP_STATE).addUInt32(World::getWorld()->getTimeTicks());
Log::info("GameProtocol", "Starting new state at %d.",
World::getWorld()->getTimeTicks());
// Local saves don't neet this info, they pass time directly to the
// RewindInfo in RewindManager::saveLocalState.
if (!local_save)
{
m_data_to_send->addUInt8(GP_STATE)
.addUInt32(World::getWorld()->getTimeTicks());
}
} // startNewState
// ----------------------------------------------------------------------------
@ -264,9 +268,8 @@ void GameProtocol::startNewState(bool allow_local_save)
* is copied, so the data can be freed after this call/.
* \param buffer Adds the data in the buffer to the current state.
*/
void GameProtocol::addState(bool allow_local_save, BareNetworkString *buffer)
void GameProtocol::addState(BareNetworkString *buffer)
{
assert(allow_local_save || NetworkConfig::get()->isServer());
m_data_to_send->addUInt16(buffer->size());
(*m_data_to_send) += *buffer;
} // addState

View File

@ -78,8 +78,8 @@ public:
void controllerAction(int kart_id, PlayerAction action,
int value, int val_l, int val_r);
void startNewState(bool allow_local_save);
void addState(bool allow_local_save, BareNetworkString *buffer);
void startNewState(bool local_save);
void addState(BareNetworkString *buffer);
void sendState();
void adjustTimeForClient(STKPeer *peer, int ticks);
@ -101,6 +101,9 @@ public:
{
return m_game_protocol.lock();
} // lock
// ------------------------------------------------------------------------
/** Returns the NetworkString in which a state was saved. */
NetworkString* getState() const { return m_data_to_send; }
}; // class GameProtocol

View File

@ -172,10 +172,10 @@ void RewindManager::addNetworkState(BareNetworkString *buffer, int ticks)
* a client before a state from the serer).
* \param allow_local_save Do a local save.
*/
void RewindManager::saveState(bool allow_local_save)
void RewindManager::saveState(bool local_save)
{
PROFILER_PUSH_CPU_MARKER("RewindManager - save state", 0x20, 0x7F, 0x20);
GameProtocol::lock()->startNewState(allow_local_save);
GameProtocol::lock()->startNewState(local_save);
AllRewinder::const_iterator rewinder;
for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder)
{
@ -185,14 +185,33 @@ void RewindManager::saveState(bool allow_local_save)
if (buffer && buffer->size() >= 0)
{
m_overall_state_size += buffer->size();
GameProtocol::lock()->addState(allow_local_save, buffer);
GameProtocol::lock()->addState(buffer);
} // size >= 0
delete buffer; // buffer can be freed
}
PROFILER_POP_CPU_MARKER();
} // saveState
// ----------------------------------------------------------------------------
/** Saves a state on the client. Used to save an initial state at t=0 for each
* client in case that we receive an event from another client (which will
* trigger a rewind) before a state from the server.
*/
void RewindManager::saveLocalState()
{
int ticks = World::getWorld()->getTimeTicks();
saveState(/*local_state*/true);
NetworkString *state = GameProtocol::lock()->getState();
// Copy the data to a new string, making the buffer in
// GameProtocol availble for again.
BareNetworkString *bns =
new BareNetworkString(state->getCurrentData(),
state->size() );
m_rewind_queue.addLocalState(bns, /*confirmed*/true, ticks);
} // saveLocalState
// ----------------------------------------------------------------------------
/** Restores a given state by calling rewindToState for each available rewinder
* with its correct data.

View File

@ -146,7 +146,8 @@ public:
BareNetworkString *buffer, int ticks);
void addNetworkState(BareNetworkString *buffer, int ticks);
void addNextTimeStep(int ticks, float dt);
void saveState(bool allow_local_save);
void saveState(bool local_save);
void saveLocalState();
void restoreState(BareNetworkString *buffer);
// ------------------------------------------------------------------------
/** Adds a Rewinder to the list of all rewinders.