Only send state for moving track object

This commit is contained in:
Benau 2018-07-13 10:47:30 +08:00
parent ab528e2840
commit 565dfcef96
18 changed files with 223 additions and 114 deletions

View File

@ -197,8 +197,9 @@ void NetworkItemManager::setItemConfirmationTime(std::weak_ptr<STKPeer> peer,
* to save the initial state, which is the first confirmed state by all
* clients.
*/
BareNetworkString* NetworkItemManager::saveState()
BareNetworkString* NetworkItemManager::saveState(std::vector<std::string>* ru)
{
ru->push_back(getUniqueIdentity());
// On the server:
// ==============
m_item_events.lock();

View File

@ -76,7 +76,8 @@ public:
virtual void collectedItem(Item *item, AbstractKart *kart) OVERRIDE;
virtual Item* dropNewItem(ItemState::ItemType type, const AbstractKart *kart,
const Vec3 *xyz=NULL) OVERRIDE;
virtual BareNetworkString* saveState() OVERRIDE;
virtual BareNetworkString* saveState(std::vector<std::string>* ru)
OVERRIDE;
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
// ------------------------------------------------------------------------
virtual void rewindToEvent(BareNetworkString *bns) OVERRIDE {};

View File

@ -95,13 +95,16 @@ void KartRewinder::computeError()
// ----------------------------------------------------------------------------
/** Saves all state information for a kart in a memory buffer. The memory
* is allocated here and the address returned. It will then be managed
* by the RewindManager. The size is used to keep track of memory usage
* for rewinding.
* \param[out] buffer Address of the memory buffer.
* \returns Size of allocated memory, or -1 in case of an error.
* by the RewindManager.
* \param[out] ru The unique identity of rewinder writing to.
* \return The address of the memory buffer with the state.
*/
BareNetworkString* KartRewinder::saveState()
BareNetworkString* KartRewinder::saveState(std::vector<std::string>* ru)
{
if (m_eliminated)
return nullptr;
ru->push_back(getUniqueIdentity());
const int MEMSIZE = 17*sizeof(float) + 9+3;
BareNetworkString *buffer = new BareNetworkString(MEMSIZE);
@ -230,6 +233,9 @@ void KartRewinder::rewindToEvent(BareNetworkString *buffer)
// ----------------------------------------------------------------------------
std::function<void()> KartRewinder::getLocalStateRestoreFunction()
{
if (m_eliminated)
return nullptr;
// In theory all ticks / boolean related stuff can be saved locally
int bubblegum_ticks = m_bubblegum_ticks;
int bounce_back_ticks = m_bounce_back_ticks;

View File

@ -44,7 +44,8 @@ public:
~KartRewinder() {}
virtual void saveTransform() OVERRIDE;
virtual void computeError() OVERRIDE;
virtual BareNetworkString* saveState() OVERRIDE;
virtual BareNetworkString* saveState(std::vector<std::string>* ru)
OVERRIDE;
void reset() OVERRIDE;
virtual void restoreState(BareNetworkString *p, int count) OVERRIDE;
virtual void rewindToEvent(BareNetworkString *p) OVERRIDE;

View File

@ -69,6 +69,7 @@
#include "states_screens/state_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "tracks/track_object_manager.hpp"
#include "utils/constants.hpp"
#include "utils/profiler.hpp"
#include "utils/translation.hpp"
@ -1031,6 +1032,10 @@ void World::update(int ticks)
RewindManager::get()->update(ticks);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("World::update (Track object manager)", 0x20, 0x7F, 0x40);
Track::getCurrentTrack()->getTrackObjectManager()->update(stk_config->ticks2Time(ticks));
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("World::update (Kart::upate)", 0x40, 0x7F, 0x00);
// Update all the karts. This in turn will also update the controller,

View File

@ -82,9 +82,9 @@ void GameSetup::loadWorld()
if (PlayerManager::getCurrentPlayer())
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
race_manager->setTimeTarget(0.0f);
race_manager->setReverseTrack(m_reverse);
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
race_manager->setReverseTrack(false);
if (isSoccerGoalTarget())
race_manager->setMaxGoal(m_laps);
else
@ -92,6 +92,7 @@ void GameSetup::loadWorld()
}
else
{
race_manager->setReverseTrack(m_reverse);
race_manager->startSingleRace(m_tracks.back(), m_laps,
false/*from_overworld*/);
}

View File

@ -304,22 +304,13 @@ void GameProtocol::handleItemEventConfirmation(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 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 local_save)
void GameProtocol::startNewState()
{
assert(local_save || NetworkConfig::get()->isServer());
assert(NetworkConfig::get()->isServer());
m_data_to_send->clear();
// 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());
}
m_data_to_send->addUInt8(GP_STATE)
.addUInt32(World::getWorld()->getTimeTicks());
} // startNewState
// ----------------------------------------------------------------------------
@ -329,10 +320,43 @@ void GameProtocol::startNewState(bool local_save)
*/
void GameProtocol::addState(BareNetworkString *buffer)
{
assert(NetworkConfig::get()->isServer());
m_data_to_send->addUInt16(buffer->size());
(*m_data_to_send) += *buffer;
} // addState
// ----------------------------------------------------------------------------
/** Called by a server to finalize the current state, which add updated
* names of rewinder using to the beginning of state buffer
* \param prev_rewinder List of previous rewinder using.
* \param cur_rewinder List of current rewinder using.
*/
void GameProtocol::finalizeState(std::vector<std::string>& prev_rewinder,
std::vector<std::string>& cur_rewinder)
{
assert(NetworkConfig::get()->isServer());
auto& buffer = m_data_to_send->getBuffer();
auto pos = buffer.begin() + 1/*protocol type*/ + 1 /*gp event type*/+
4/*time*/;
if (prev_rewinder != cur_rewinder)
{
m_data_to_send->reset();
std::vector<uint8_t> names;
names.push_back((uint8_t)cur_rewinder.size());
for (std::string& name : cur_rewinder)
{
names.push_back((uint8_t)name.size());
std::vector<uint8_t> rewinder(name.begin(), name.end());
names.insert(names.end(), rewinder.begin(), rewinder.end());
}
buffer.insert(pos, names.begin(), names.end());
std::swap(prev_rewinder, cur_rewinder);
}
else
buffer.insert(pos, 0);
} // finalizeState
// ----------------------------------------------------------------------------
/** Called when the last state information has been added and the message
* can be sent to the clients.
@ -355,6 +379,19 @@ void GameProtocol::handleState(Event *event)
assert(NetworkConfig::get()->isClient());
const NetworkString &data = event->data();
int ticks = data.getUInt32();
// Check for updated rewinder using
unsigned new_rewinder_size = data.getUInt8();
std::vector<std::string> new_rewinder_using;
for (unsigned i = 0; i < new_rewinder_size; i++)
{
std::string name;
data.decodeString(&name);
new_rewinder_using.push_back(name);
}
if (!new_rewinder_using.empty())
RewindManager::get()->setRewinderUsing(new_rewinder_using);
// Now copy the state data (without ticks etc) to a new
// string, so it can be reset to the beginning easily
// when restoring the state:

View File

@ -86,9 +86,11 @@ public:
void controllerAction(int kart_id, PlayerAction action,
int value, int val_l, int val_r);
void startNewState(bool local_save);
void startNewState();
void addState(BareNetworkString *buffer);
void sendState();
void finalizeState(std::vector<std::string>& prev_rewinder,
std::vector<std::string>& cur_rewinder);
void adjustTimeForClient(STKPeer *peer, int ticks);
void sendItemEventConfirmation(int ticks);

View File

@ -49,6 +49,7 @@ RewindInfoState::RewindInfoState(int ticks, BareNetworkString *buffer,
bool is_confirmed)
: RewindInfo(ticks, is_confirmed)
{
m_rewinder_using = RewindManager::get()->getRewinderUsing();
m_buffer = buffer;
} // RewindInfoState
@ -59,8 +60,21 @@ RewindInfoState::RewindInfoState(int ticks, BareNetworkString *buffer,
*/
void RewindInfoState::restore()
{
RewindManager::get()->restoreState(m_buffer);
} // rewind
m_buffer->reset();
for (const std::string& name : m_rewinder_using)
{
uint16_t count = m_buffer->getUInt16();
Rewinder* r = RewindManager::get()->getRewinder(name);
if (r == NULL)
{
Log::error("RewindInfoState", "Missing rewinder %s",
name.c_str());
m_buffer->skip(count);
continue;
}
r->restoreState(m_buffer, count);
} // for all rewinder
} // restore
// ============================================================================
RewindInfoEvent::RewindInfoEvent(int ticks, EventRewinder *event_rewinder,

View File

@ -91,6 +91,8 @@ public:
class RewindInfoState: public RewindInfo
{
private:
std::vector<std::string> m_rewinder_using;
/** Pointer to the buffer which stores all states. */
BareNetworkString *m_buffer;
public:

View File

@ -82,16 +82,15 @@ void RewindManager::reset()
if (!m_enable_rewind_manager) return;
AllRewinder::iterator r = m_all_rewinder.begin();
while (r != m_all_rewinder.end())
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
{
if (!(*r)->canBeDestroyed())
if (!it->second->canBeDestroyed())
{
r++;
it++;
continue;
}
Rewinder *rewinder = *r;
r = m_all_rewinder.erase(r);
Rewinder* rewinder = it->second;
it = m_all_rewinder.erase(it);
delete rewinder;
}
@ -150,54 +149,35 @@ void RewindManager::addNetworkState(BareNetworkString *buffer, int ticks)
} // addNetworkState
// ----------------------------------------------------------------------------
/** Saves a local state using the GameProtocol function to combine several
* independent rewinders to write one state. Typically only the server needs
* to save a state (which is then send to the clients), except that each
* client needs one initial state (in case that it receives an event from
* a client before a state from the serer).
* \param allow_local_save Do a local save.
/** Saves a state using the GameProtocol function to combine several
* independent rewinders to write one state.
*/
void RewindManager::saveState(bool local_save)
void RewindManager::saveState()
{
PROFILER_PUSH_CPU_MARKER("RewindManager - save state", 0x20, 0x7F, 0x20);
auto gp = GameProtocol::lock();
if (!gp)
return;
gp->startNewState(local_save);
AllRewinder::const_iterator rewinder;
for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder)
gp->startNewState();
m_overall_state_size = 0;
std::vector<std::string> rewinder_using;
for (auto& p : m_all_rewinder)
{
// TODO: check if it's worth passing in a sufficiently large buffer from
// GameProtocol - this would save the copy operation.
BareNetworkString *buffer = (*rewinder)->saveState();
if (buffer)
BareNetworkString* buffer = p.second->saveState(&rewinder_using);
if (buffer != NULL)
{
m_overall_state_size += buffer->size();
gp->addState(buffer);
} // size >= 0
}
delete buffer; // buffer can be freed
}
gp->finalizeState(m_current_rewinder_using, rewinder_using);
PROFILER_POP_CPU_MARKER();
} // saveState
// ----------------------------------------------------------------------------
/** Restores a given state by calling rewindToState for each available rewinder
* with its correct data.
* \param data The data string used to store the whole game state.
*
*/
void RewindManager::restoreState(BareNetworkString *data)
{
data->reset();
for (auto rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder)
{
uint16_t count = data->getUInt16();
(*rewinder)->restoreState(data, count);
} // for all rewinder
} // restoreState
// ----------------------------------------------------------------------------
/** Determines if a new state snapshot should be taken, and if so calls all
* rewinder to do so.
@ -221,12 +201,12 @@ void RewindManager::update(int ticks_not_used)
if (NetworkConfig::get()->isClient())
{
auto& ret = m_local_state[ticks];
for (Rewinder* r : m_all_rewinder)
ret[r] = r->getLocalStateRestoreFunction();
for (auto& p : m_all_rewinder)
ret.push_back(p.second->getLocalStateRestoreFunction());
}
else
{
saveState(/**allow_local_save*/false);
saveState();
PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40);
if (auto gp = GameProtocol::lock())
gp->sendState();
@ -293,12 +273,8 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
// First save all current transforms so that the error
// can be computed between the transforms before and after
// the rewind.
AllRewinder::iterator rewinder;
for (rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder)
{
(*rewinder)->saveTransform();
}
for (auto& p : m_all_rewinder)
p.second->saveTransform();
// Then undo the rewind infos going backwards in time
// --------------------------------------------------
@ -327,10 +303,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
auto it = m_local_state.find(exact_rewind_ticks);
if (it != m_local_state.end())
{
for (auto& local_state : it->second)
for (auto& restore_local_state : it->second)
{
if (local_state.second)
local_state.second();
if (restore_local_state)
restore_local_state();
}
for (auto it = m_local_state.begin(); it != m_local_state.end();)
{
@ -356,7 +332,7 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
}
// Now go forward through the list of rewind infos till we reach 'now':
while(world->getTimeTicks() < now_ticks )
while (world->getTimeTicks() < now_ticks)
{
m_rewind_queue.replayAllEvents(world->getTimeTicks());
@ -371,11 +347,8 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
} // while (world->getTicks() < current_ticks)
// Now compute the errors which need to be visually smoothed
for (rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder)
{
(*rewinder)->computeError();
}
for (auto& p : m_all_rewinder)
p.second->computeError();
history->setReplayHistory(is_history);
m_is_rewinding = false;

View File

@ -88,12 +88,12 @@ private:
* rewind data in case of local races only. */
static bool m_enable_rewind_manager;
typedef std::vector<Rewinder *> AllRewinder;
std::vector<std::string> m_current_rewinder_using;
std::map<int, std::map<Rewinder*, std::function<void()> > > m_local_state;
std::map<int, std::vector<std::function<void()> > > m_local_state;
/** A list of all objects that can be rewound. */
AllRewinder m_all_rewinder;
std::map<std::string, Rewinder*> m_all_rewinder;
/** The queue that stores all rewind infos. */
RewindQueue m_rewind_queue;
@ -149,16 +149,26 @@ public:
void addNetworkEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, int ticks);
void addNetworkState(BareNetworkString *buffer, int ticks);
void saveState(bool local_save);
void restoreState(BareNetworkString *buffer);
void saveState();
// ------------------------------------------------------------------------
Rewinder* getRewinder(const std::string& name)
{
auto it = m_all_rewinder.find(name);
if (it == m_all_rewinder.end())
return NULL;
return it->second;
}
// ------------------------------------------------------------------------
/** Adds a Rewinder to the list of all rewinders.
* \return true If rewinding is enabled, false otherwise.
*/
bool addRewinder(Rewinder *rewinder)
{
if(!m_enable_rewind_manager) return false;
m_all_rewinder.push_back(rewinder);
if (!m_enable_rewind_manager) return false;
// Maximum 1 bit to store no of rewinder used
if (m_all_rewinder.size() == 255)
return false;
m_all_rewinder[rewinder->getUniqueIdentity()] = rewinder;
return true;
} // addRewinder
@ -179,6 +189,15 @@ public:
{
return m_rewind_queue.getLatestConfirmedState();
} // getLatestConfirmedState
// ------------------------------------------------------------------------
/* Used by client to update rewinder using. */
void setRewinderUsing(std::vector<std::string>& ru)
{ m_current_rewinder_using = std::move(ru); }
// ------------------------------------------------------------------------
/* Used by client to get a copied list of rewinder using to be used
in different thread safely. */
const std::vector<std::string>& getRewinderUsing() const
{ return m_current_rewinder_using; }
}; // RewindManager

View File

@ -408,7 +408,8 @@ void RewindQueue::unitTesting()
class DummyRewinder : public Rewinder, public EventRewinder
{
public:
BareNetworkString* saveState() { return NULL; }
BareNetworkString* saveState(std::vector<std::string>* ru)
{ return NULL; }
virtual void undoEvent(BareNetworkString *s) {}
virtual void rewindToEvent(BareNetworkString *s) {}
virtual void restoreState(BareNetworkString *s, int count) {}
@ -417,7 +418,7 @@ void RewindQueue::unitTesting()
virtual void rewind(BareNetworkString *s) {}
virtual void saveTransform() {}
virtual void computeError() {}
DummyRewinder() : Rewinder("", true) {}
DummyRewinder() : Rewinder("dummy_rewinder", true) {}
};
DummyRewinder *dummy_rewinder = new DummyRewinder();

View File

@ -26,6 +26,7 @@
Rewinder::Rewinder(const std::string& ui, bool can_be_destroyed, bool auto_add)
: m_unique_identity(ui)
{
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
m_can_be_destroyed = can_be_destroyed;
if (auto_add)
add();

View File

@ -19,8 +19,9 @@
#ifndef HEADER_REWINDER_HPP
#define HEADER_REWINDER_HPP
#include <string>
#include <functional>
#include <string>
#include <vector>
class BareNetworkString;
@ -54,10 +55,10 @@ public:
/** Provides a copy of the state of the object in one memory buffer.
* The memory is managed by the RewindManager.
* \param[out] buffer The address of the memory buffer with the state.
* \return Size of the buffer, or -1 in case of an error.
* \param[out] ru The unique identity of rewinder writing to.
* \return The address of the memory buffer with the state.
*/
virtual BareNetworkString* saveState() = 0;
virtual BareNetworkString* saveState(std::vector<std::string>* ru) = 0;
/** Called when an event needs to be undone. This is called while going
* backwards for rewinding - all stored events will get an 'undo' call.

View File

@ -29,6 +29,7 @@
#include "physics/physics.hpp"
#include "physics/triangle_mesh.hpp"
#include "network/network_string.hpp"
#include "network/rewind_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object.hpp"
#include "utils/constants.hpp"
@ -171,7 +172,9 @@ PhysicalObject::PhysicalObject(bool is_dynamic,
m_current_transform.setOrigin(Vec3());
m_current_transform.setRotation(
btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
m_previous_transform = m_current_transform;
m_last_transform = m_current_transform;
m_no_server_state = false;
m_body_added = false;
@ -638,7 +641,7 @@ void PhysicalObject::update(float dt)
{
if (!m_is_dynamic) return;
m_motion_state->getWorldTransform(m_current_transform);
m_current_transform = m_body->getWorldTransform();
const Vec3 &xyz = m_current_transform.getOrigin();
if(m_reset_when_too_low && xyz.getY()<m_reset_height)
@ -687,6 +690,9 @@ void PhysicalObject::reset()
m_body->setAngularVelocity(btVector3(0,0,0));
m_body->setLinearVelocity(btVector3(0,0,0));
m_body->activate();
m_last_transform = m_init_pos;
m_last_lv = m_last_av = Vec3(0.0f);
} // reset
// ----------------------------------------------------------------------------
@ -787,6 +793,7 @@ void PhysicalObject::addForRewind()
// ----------------------------------------------------------------------------
void PhysicalObject::saveTransform()
{
m_no_server_state = true;
} // saveTransform
// ----------------------------------------------------------------------------
@ -795,37 +802,72 @@ void PhysicalObject::computeError()
} // computeError
// ----------------------------------------------------------------------------
BareNetworkString* PhysicalObject::saveState()
BareNetworkString* PhysicalObject::saveState(std::vector<std::string>* ru)
{
btTransform cur_transform = m_body->getWorldTransform();
if ((cur_transform.getOrigin() - m_last_transform.getOrigin())
.length() == 0.0f &&
m_body->getLinearVelocity() == m_last_lv &&
m_body->getLinearVelocity() == m_last_av)
return nullptr;
ru->push_back(getUniqueIdentity());
BareNetworkString *buffer = new BareNetworkString();
buffer->add(m_current_transform.getOrigin());
buffer->add(m_current_transform.getRotation());
buffer->add(m_body->getLinearVelocity());
buffer->add(m_body->getAngularVelocity());
m_last_transform = cur_transform;
m_last_lv = m_body->getLinearVelocity();
m_last_av = m_body->getAngularVelocity();
buffer->add(m_last_transform.getOrigin());
buffer->add(m_last_transform.getRotation());
buffer->add(m_last_lv);
buffer->add(m_last_av);
return buffer;
} // saveState
// ----------------------------------------------------------------------------
void PhysicalObject::restoreState(BareNetworkString *buffer, int count)
{
btTransform t;
t.setOrigin(buffer->getVec3());
t.setRotation(buffer->getQuat());
m_body->setLinearVelocity(buffer->getVec3());
m_body->setAngularVelocity(buffer->getVec3());
m_body->proceedToTransform(t);
m_no_server_state = false;
m_last_transform.setOrigin(buffer->getVec3());
m_last_transform.setRotation(buffer->getQuat());
m_last_lv = buffer->getVec3();
m_last_av = buffer->getVec3();
m_body->setWorldTransform(m_last_transform);
m_motion_state->setWorldTransform(m_last_transform);
m_body->setInterpolationWorldTransform(m_last_transform);
m_body->setLinearVelocity(m_last_lv);
m_body->setAngularVelocity(m_last_av);
m_body->setInterpolationLinearVelocity(m_last_lv);
m_body->setInterpolationAngularVelocity(m_last_av);
} // restoreState
// ----------------------------------------------------------------------------
std::function<void()> PhysicalObject::getLocalStateRestoreFunction()
{
btTransform t = m_current_transform;
btTransform t = m_body->getWorldTransform();
Vec3 lv = m_body->getLinearVelocity();
Vec3 av = m_body->getAngularVelocity();
return [t, lv, av, this]()
{
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->proceedToTransform(t);
if (m_no_server_state)
{
m_body->setWorldTransform(m_last_transform);
m_motion_state->setWorldTransform(m_last_transform);
m_body->setInterpolationWorldTransform(m_last_transform);
m_body->setLinearVelocity(m_last_lv);
m_body->setAngularVelocity(m_last_av);
m_body->setInterpolationLinearVelocity(m_last_lv);
m_body->setInterpolationAngularVelocity(m_last_av);
}
else
{
m_body->setWorldTransform(t);
m_motion_state->setWorldTransform(t);
m_body->setInterpolationWorldTransform(t);
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->setInterpolationLinearVelocity(lv);
m_body->setInterpolationAngularVelocity(av);
}
};
} // getLocalStateRestoreFunction

View File

@ -142,8 +142,6 @@ private:
* world transform. */
btTransform m_current_transform;
btTransform m_previous_transform;
/** The mesh might not have the same center as bullet does. This
* offset is used to offset the location of the graphical mesh
* so that the graphics are aligned with the bullet collision shape. */
@ -188,6 +186,11 @@ private:
/** Non-null only if the shape is exact */
TriangleMesh *m_triangle_mesh;
btTransform m_last_transform;
Vec3 m_last_lv;
Vec3 m_last_av;
bool m_no_server_state;
public:
PhysicalObject(bool is_dynamic, const Settings& settings,
TrackObject* object);
@ -275,7 +278,7 @@ public:
void addForRewind();
virtual void saveTransform();
virtual void computeError();
virtual BareNetworkString* saveState();
virtual BareNetworkString* saveState(std::vector<std::string>* ru);
virtual void undoEvent(BareNetworkString *buffer) {}
virtual void rewindToEvent(BareNetworkString *buffer) {}
virtual void restoreState(BareNetworkString *buffer, int count);

View File

@ -1550,7 +1550,6 @@ void Track::update(int ticks)
m_startup_run = true;
}
float dt = stk_config->ticks2Time(ticks);
m_track_object_manager->update(dt);
CheckManager::get()->update(dt);
ItemManager::get()->update(ticks);