Use rewinder with shared_ptr for easier item destroy handling
This commit is contained in:
parent
6369256022
commit
bbf5c54f87
@ -39,8 +39,7 @@ void NetworkItemManager::create()
|
|||||||
/** Creates a new instance of the item manager. This is done at startup
|
/** Creates a new instance of the item manager. This is done at startup
|
||||||
* of each race. */
|
* of each race. */
|
||||||
NetworkItemManager::NetworkItemManager()
|
NetworkItemManager::NetworkItemManager()
|
||||||
: Rewinder("N", /*can be deleted*/false),
|
: Rewinder("N"), ItemManager()
|
||||||
ItemManager()
|
|
||||||
{
|
{
|
||||||
m_last_confirmed_item_ticks.clear();
|
m_last_confirmed_item_ticks.clear();
|
||||||
|
|
||||||
|
@ -38,8 +38,7 @@ KartRewinder::KartRewinder(const std::string& ident,
|
|||||||
const btTransform& init_transform,
|
const btTransform& init_transform,
|
||||||
PerPlayerDifficulty difficulty,
|
PerPlayerDifficulty difficulty,
|
||||||
std::shared_ptr<RenderInfo> ri)
|
std::shared_ptr<RenderInfo> ri)
|
||||||
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id),
|
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id))
|
||||||
/*can_be_destroyed*/ false)
|
|
||||||
, Kart(ident, world_kart_id, position, init_transform, difficulty,
|
, Kart(ident, world_kart_id, position, init_transform, difficulty,
|
||||||
ri)
|
ri)
|
||||||
{
|
{
|
||||||
|
@ -64,8 +64,9 @@ void RewindInfoState::restore()
|
|||||||
for (const std::string& name : m_rewinder_using)
|
for (const std::string& name : m_rewinder_using)
|
||||||
{
|
{
|
||||||
uint16_t count = m_buffer->getUInt16();
|
uint16_t count = m_buffer->getUInt16();
|
||||||
Rewinder* r = RewindManager::get()->getRewinder(name);
|
std::shared_ptr<Rewinder> r =
|
||||||
if (r == NULL)
|
RewindManager::get()->getRewinder(name);
|
||||||
|
if (!r)
|
||||||
{
|
{
|
||||||
Log::error("RewindInfoState", "Missing rewinder %s",
|
Log::error("RewindInfoState", "Missing rewinder %s",
|
||||||
name.c_str());
|
name.c_str());
|
||||||
|
@ -82,18 +82,7 @@ void RewindManager::reset()
|
|||||||
|
|
||||||
if (!m_enable_rewind_manager) return;
|
if (!m_enable_rewind_manager) return;
|
||||||
|
|
||||||
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
|
clearExpiredRewinder();
|
||||||
{
|
|
||||||
if (!it->second->canBeDestroyed())
|
|
||||||
{
|
|
||||||
it++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Rewinder* rewinder = it->second;
|
|
||||||
it = m_all_rewinder.erase(it);
|
|
||||||
delete rewinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rewind_queue.reset();
|
m_rewind_queue.reset();
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
@ -166,7 +155,9 @@ void RewindManager::saveState()
|
|||||||
{
|
{
|
||||||
// TODO: check if it's worth passing in a sufficiently large buffer from
|
// TODO: check if it's worth passing in a sufficiently large buffer from
|
||||||
// GameProtocol - this would save the copy operation.
|
// GameProtocol - this would save the copy operation.
|
||||||
BareNetworkString* buffer = p.second->saveState(&rewinder_using);
|
BareNetworkString* buffer = NULL;
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
buffer = r->saveState(&rewinder_using);
|
||||||
if (buffer != NULL)
|
if (buffer != NULL)
|
||||||
{
|
{
|
||||||
m_overall_state_size += buffer->size();
|
m_overall_state_size += buffer->size();
|
||||||
@ -197,12 +188,16 @@ void RewindManager::update(int ticks_not_used)
|
|||||||
if (ticks - m_last_saved_state < m_state_frequency)
|
if (ticks - m_last_saved_state < m_state_frequency)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Save state
|
// Save state, remove expired rewinder first
|
||||||
|
clearExpiredRewinder();
|
||||||
if (NetworkConfig::get()->isClient())
|
if (NetworkConfig::get()->isClient())
|
||||||
{
|
{
|
||||||
auto& ret = m_local_state[ticks];
|
auto& ret = m_local_state[ticks];
|
||||||
for (auto& p : m_all_rewinder)
|
for (auto& p : m_all_rewinder)
|
||||||
ret.push_back(p.second->getLocalStateRestoreFunction());
|
{
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
ret.push_back(r->getLocalStateRestoreFunction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -255,6 +250,20 @@ void RewindManager::playEventsTill(int world_ticks, int *ticks)
|
|||||||
m_is_rewinding = false;
|
m_is_rewinding = false;
|
||||||
} // playEventsTill
|
} // playEventsTill
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Adds a Rewinder to the list of all rewinders.
|
||||||
|
* \return true If successfully added, false otherwise.
|
||||||
|
*/
|
||||||
|
bool RewindManager::addRewinder(std::shared_ptr<Rewinder> 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
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** Rewinds to the specified time, then goes forward till the current
|
/** Rewinds to the specified time, then goes forward till the current
|
||||||
* World::getTime() is reached again: it will replay everything before
|
* World::getTime() is reached again: it will replay everything before
|
||||||
@ -274,7 +283,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
|
|||||||
// can be computed between the transforms before and after
|
// can be computed between the transforms before and after
|
||||||
// the rewind.
|
// the rewind.
|
||||||
for (auto& p : m_all_rewinder)
|
for (auto& p : m_all_rewinder)
|
||||||
p.second->saveTransform();
|
{
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
r->saveTransform();
|
||||||
|
}
|
||||||
|
|
||||||
// Then undo the rewind infos going backwards in time
|
// Then undo the rewind infos going backwards in time
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
@ -348,7 +360,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
|
|||||||
|
|
||||||
// Now compute the errors which need to be visually smoothed
|
// Now compute the errors which need to be visually smoothed
|
||||||
for (auto& p : m_all_rewinder)
|
for (auto& p : m_all_rewinder)
|
||||||
p.second->computeError();
|
{
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
r->computeError();
|
||||||
|
}
|
||||||
|
|
||||||
history->setReplayHistory(is_history);
|
history->setReplayHistory(is_history);
|
||||||
m_is_rewinding = false;
|
m_is_rewinding = false;
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#ifndef HEADER_REWIND_MANAGER_HPP
|
#ifndef HEADER_REWIND_MANAGER_HPP
|
||||||
#define HEADER_REWIND_MANAGER_HPP
|
#define HEADER_REWIND_MANAGER_HPP
|
||||||
|
|
||||||
#include "network/rewinder.hpp"
|
|
||||||
#include "network/rewind_queue.hpp"
|
#include "network/rewind_queue.hpp"
|
||||||
#include "utils/ptr_vector.hpp"
|
#include "utils/ptr_vector.hpp"
|
||||||
#include "utils/synchronised.hpp"
|
#include "utils/synchronised.hpp"
|
||||||
@ -27,9 +26,11 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class Rewinder;
|
||||||
class RewindInfo;
|
class RewindInfo;
|
||||||
class EventRewinder;
|
class EventRewinder;
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ private:
|
|||||||
std::map<int, std::vector<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. */
|
/** A list of all objects that can be rewound. */
|
||||||
std::map<std::string, Rewinder*> m_all_rewinder;
|
std::map<std::string, std::weak_ptr<Rewinder> > m_all_rewinder;
|
||||||
|
|
||||||
/** The queue that stores all rewind infos. */
|
/** The queue that stores all rewind infos. */
|
||||||
RewindQueue m_rewind_queue;
|
RewindQueue m_rewind_queue;
|
||||||
@ -117,6 +118,19 @@ private:
|
|||||||
|
|
||||||
RewindManager();
|
RewindManager();
|
||||||
~RewindManager();
|
~RewindManager();
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void clearExpiredRewinder()
|
||||||
|
{
|
||||||
|
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
|
||||||
|
{
|
||||||
|
if (it->second.expired())
|
||||||
|
{
|
||||||
|
it = m_all_rewinder.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// First static functions to manage rewinding.
|
// First static functions to manage rewinding.
|
||||||
@ -151,27 +165,18 @@ public:
|
|||||||
void addNetworkState(BareNetworkString *buffer, int ticks);
|
void addNetworkState(BareNetworkString *buffer, int ticks);
|
||||||
void saveState();
|
void saveState();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
Rewinder* getRewinder(const std::string& name)
|
std::shared_ptr<Rewinder> getRewinder(const std::string& name)
|
||||||
{
|
{
|
||||||
auto it = m_all_rewinder.find(name);
|
auto it = m_all_rewinder.find(name);
|
||||||
if (it == m_all_rewinder.end())
|
if (it != m_all_rewinder.end())
|
||||||
return NULL;
|
{
|
||||||
return it->second;
|
if (auto r = it->second.lock())
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Adds a Rewinder to the list of all rewinders.
|
bool addRewinder(std::shared_ptr<Rewinder> rewinder);
|
||||||
* \return true If rewinding is enabled, false otherwise.
|
|
||||||
*/
|
|
||||||
bool addRewinder(Rewinder *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
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns true if currently a rewind is happening. */
|
/** Returns true if currently a rewind is happening. */
|
||||||
bool isRewinding() const { return m_is_rewinding; }
|
bool isRewinding() const { return m_is_rewinding; }
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "config/stk_config.hpp"
|
#include "config/stk_config.hpp"
|
||||||
#include "modes/world.hpp"
|
#include "modes/world.hpp"
|
||||||
#include "network/network_config.hpp"
|
#include "network/network_config.hpp"
|
||||||
|
#include "network/rewinder.hpp"
|
||||||
#include "network/rewind_info.hpp"
|
#include "network/rewind_info.hpp"
|
||||||
#include "network/rewind_manager.hpp"
|
#include "network/rewind_manager.hpp"
|
||||||
|
|
||||||
@ -418,9 +419,9 @@ void RewindQueue::unitTesting()
|
|||||||
virtual void rewind(BareNetworkString *s) {}
|
virtual void rewind(BareNetworkString *s) {}
|
||||||
virtual void saveTransform() {}
|
virtual void saveTransform() {}
|
||||||
virtual void computeError() {}
|
virtual void computeError() {}
|
||||||
DummyRewinder() : Rewinder("dummy_rewinder", true) {}
|
DummyRewinder() : Rewinder() {}
|
||||||
};
|
};
|
||||||
DummyRewinder *dummy_rewinder = new DummyRewinder();
|
auto dummy_rewinder = std::make_shared<DummyRewinder>();
|
||||||
|
|
||||||
// First tests: add a state first, then an event, and make
|
// First tests: add a state first, then an event, and make
|
||||||
// sure the state stays first
|
// sure the state stays first
|
||||||
@ -434,7 +435,7 @@ void RewindQueue::unitTesting()
|
|||||||
assert(q0.hasMoreRewindInfo());
|
assert(q0.hasMoreRewindInfo());
|
||||||
assert(q0.undoUntil(0) == 0);
|
assert(q0.undoUntil(0) == 0);
|
||||||
|
|
||||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0);
|
q0.addNetworkEvent(dummy_rewinder.get(), NULL, 0);
|
||||||
// Network events are not immediately merged
|
// Network events are not immediately merged
|
||||||
assert(q0.m_all_rewind_info.size() == 1);
|
assert(q0.m_all_rewind_info.size() == 1);
|
||||||
|
|
||||||
@ -462,9 +463,9 @@ void RewindQueue::unitTesting()
|
|||||||
assert((*rii)->isEvent());
|
assert((*rii)->isEvent());
|
||||||
|
|
||||||
// Test time base comparisons: adding an event to the end
|
// Test time base comparisons: adding an event to the end
|
||||||
q0.addLocalEvent(dummy_rewinder, NULL, true, 4);
|
q0.addLocalEvent(dummy_rewinder.get(), NULL, true, 4);
|
||||||
// Then adding an earlier event
|
// Then adding an earlier event
|
||||||
q0.addLocalEvent(dummy_rewinder, NULL, false, 1);
|
q0.addLocalEvent(dummy_rewinder.get(), NULL, false, 1);
|
||||||
// rii points to the 3rd element, the ones added just now
|
// rii points to the 3rd element, the ones added just now
|
||||||
// should be elements4 and 5:
|
// should be elements4 and 5:
|
||||||
rii++;
|
rii++;
|
||||||
|
@ -19,14 +19,13 @@
|
|||||||
#ifndef HEADER_REWIND_QUEUE_HPP
|
#ifndef HEADER_REWIND_QUEUE_HPP
|
||||||
#define HEADER_REWIND_QUEUE_HPP
|
#define HEADER_REWIND_QUEUE_HPP
|
||||||
|
|
||||||
#include "network/rewinder.hpp"
|
|
||||||
#include "utils/ptr_vector.hpp"
|
|
||||||
#include "utils/synchronised.hpp"
|
#include "utils/synchronised.hpp"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class BareNetworkString;
|
||||||
class EventRewinder;
|
class EventRewinder;
|
||||||
class RewindInfo;
|
class RewindInfo;
|
||||||
class TimeStepInfo;
|
class TimeStepInfo;
|
||||||
|
@ -20,27 +20,11 @@
|
|||||||
|
|
||||||
#include "network/rewind_manager.hpp"
|
#include "network/rewind_manager.hpp"
|
||||||
|
|
||||||
/** Constructor. It will add this object to the list of all rewindable
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Add this object to the list of all rewindable
|
||||||
* objects in the rewind manager.
|
* objects in the rewind manager.
|
||||||
*/
|
*/
|
||||||
Rewinder::Rewinder(const std::string& ui, bool can_be_destroyed, bool auto_add)
|
bool Rewinder::add()
|
||||||
: m_unique_identity(ui)
|
|
||||||
{
|
{
|
||||||
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
|
return RewindManager::get()->addRewinder(shared_from_this());
|
||||||
m_can_be_destroyed = can_be_destroyed;
|
} // add
|
||||||
if (auto_add)
|
|
||||||
add();
|
|
||||||
} // Rewinder
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
/** Destructor.
|
|
||||||
*/
|
|
||||||
Rewinder::~Rewinder()
|
|
||||||
{
|
|
||||||
} // ~Rewinder
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
void Rewinder::add()
|
|
||||||
{
|
|
||||||
RewindManager::get()->addRewinder(this);
|
|
||||||
} // Rewinder
|
|
||||||
|
@ -19,33 +19,26 @@
|
|||||||
#ifndef HEADER_REWINDER_HPP
|
#ifndef HEADER_REWINDER_HPP
|
||||||
#define HEADER_REWINDER_HPP
|
#define HEADER_REWINDER_HPP
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class BareNetworkString;
|
class BareNetworkString;
|
||||||
|
|
||||||
class Rewinder
|
class Rewinder : public std::enable_shared_from_this<Rewinder>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void add();
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
void setUniqueIdentity(const std::string& uid) { m_unique_identity = uid; }
|
void setUniqueIdentity(const std::string& uid) { m_unique_identity = uid; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_unique_identity;
|
std::string m_unique_identity;
|
||||||
|
|
||||||
/** True if this object can be destroyed, i.e. if this object is a 'stand
|
|
||||||
* alone' (i.e. not used in inheritance). If the object is used in
|
|
||||||
* inheritance (e.g. KartRewinder, which is a Rewinder and Kart), then
|
|
||||||
* freeing the kart will free this rewinder instance as well.
|
|
||||||
*/
|
|
||||||
bool m_can_be_destroyed;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Rewinder(const std::string& ui, bool can_be_destroyed,
|
Rewinder(const std::string& ui = "") { m_unique_identity = ui; }
|
||||||
bool auto_add = true);
|
|
||||||
virtual ~Rewinder();
|
virtual ~Rewinder() {}
|
||||||
|
|
||||||
/** Called before a rewind. Is used to save the previous position of an
|
/** Called before a rewind. Is used to save the previous position of an
|
||||||
* object before a rewind, so that the error due to a rewind can be
|
* object before a rewind, so that the error due to a rewind can be
|
||||||
@ -89,14 +82,17 @@ public:
|
|||||||
/** Nothing to do here. */
|
/** Nothing to do here. */
|
||||||
virtual void reset() {}
|
virtual void reset() {}
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
/** True if this rewinder can be destroyed. Karts can not be destroyed,
|
|
||||||
* cakes can. This is used by the RewindManager in reset. */
|
|
||||||
bool canBeDestroyed() const { return m_can_be_destroyed; }
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
virtual std::function<void()> getLocalStateRestoreFunction()
|
virtual std::function<void()> getLocalStateRestoreFunction()
|
||||||
{ return nullptr; }
|
{ return nullptr; }
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
const std::string& getUniqueIdentity() const { return m_unique_identity; }
|
const std::string& getUniqueIdentity() const
|
||||||
|
{
|
||||||
|
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
|
||||||
|
return m_unique_identity;
|
||||||
|
}
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
bool add();
|
||||||
|
|
||||||
}; // Rewinder
|
}; // Rewinder
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -136,7 +136,6 @@ PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
|
|||||||
PhysicalObject::PhysicalObject(bool is_dynamic,
|
PhysicalObject::PhysicalObject(bool is_dynamic,
|
||||||
const PhysicalObject::Settings& settings,
|
const PhysicalObject::Settings& settings,
|
||||||
TrackObject* object)
|
TrackObject* object)
|
||||||
: Rewinder("P", false/*can_be_destroyed*/, false/*auto_add*/)
|
|
||||||
{
|
{
|
||||||
m_shape = NULL;
|
m_shape = NULL;
|
||||||
m_body = NULL;
|
m_body = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user