ixed handling of adding states to time step info to minimise
rewindw by assigning new events to existing time step info events.
This commit is contained in:
parent
34af963cc1
commit
3747427c5f
@ -114,8 +114,15 @@
|
||||
<explosion impulse-objects="500.0" />
|
||||
|
||||
<!-- Networking - the current networking code is outdated and will not
|
||||
work anymore - so for now don't enable this. -->
|
||||
<networking enable="false"/>
|
||||
work anymore - so for now don't enable this.
|
||||
For the new networking code:
|
||||
combine-threshold: Maximum time a network event can be different
|
||||
from an existing time step info to be combined into one. This
|
||||
reduces the number of time steps necessary (for slightly larger
|
||||
inaccuracies).
|
||||
-->
|
||||
<networking enable="false"
|
||||
combine-threshold="0.05" />
|
||||
|
||||
<!-- The field od views for 1-4 player split screen. fov-3 is
|
||||
actually not used (since 3 player split screen uses the
|
||||
|
@ -138,6 +138,8 @@ void STKConfig::load(const std::string &filename)
|
||||
CHECK_NEG(m_replay_delta_pos2, "replay delta-position" );
|
||||
CHECK_NEG(m_replay_dt, "replay delta-t" );
|
||||
CHECK_NEG(m_smooth_angle_limit, "physics smooth-angle-limit" );
|
||||
CHECK_NEG(m_network_combine_threshold, "network combine-threshold" );
|
||||
|
||||
|
||||
// Square distance to make distance checks cheaper (no sqrt)
|
||||
m_replay_delta_pos2 *= m_replay_delta_pos2;
|
||||
@ -170,6 +172,7 @@ void STKConfig::init_defaults()
|
||||
m_replay_delta_angle = -100;
|
||||
m_replay_delta_pos2 = -100;
|
||||
m_replay_dt = -100;
|
||||
m_network_combine_threshold = -100;
|
||||
m_title_music = NULL;
|
||||
m_enable_networking = true;
|
||||
m_smooth_normals = false;
|
||||
@ -342,8 +345,11 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
ai_node->get("acceleration", &m_ai_acceleration);
|
||||
}
|
||||
|
||||
if(const XMLNode *networking_node= root->getNode("networking"))
|
||||
if (const XMLNode *networking_node = root->getNode("networking"))
|
||||
{
|
||||
networking_node->get("enable", &m_enable_networking);
|
||||
networking_node->get("combine-threshold", &m_network_combine_threshold);
|
||||
}
|
||||
|
||||
if(const XMLNode *replay_node = root->getNode("replay"))
|
||||
{
|
||||
|
@ -81,6 +81,12 @@ public:
|
||||
int m_max_karts; /**<Maximum number of karts. */
|
||||
bool m_smooth_normals; /**< If normals for raycasts for wheels
|
||||
should be interpolated. */
|
||||
|
||||
/** Network events that are less than this value apart will be executed
|
||||
* at the same time (instead of adding a new time step, which causes
|
||||
* one more time step to be simulated). */
|
||||
float m_network_combine_threshold;
|
||||
|
||||
/** If the angle between a normal on a vertex and the normal of the
|
||||
* triangle are more than this value, the physics will use the normal
|
||||
* of the triangle in smoothing normal. */
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "race/history.hpp"
|
||||
@ -235,6 +236,14 @@ void MainLoop::run()
|
||||
m_prev_time = m_curr_time;
|
||||
float dt = getLimitedDt();
|
||||
|
||||
// Add a Time step entry to the rewind list, which can store all
|
||||
// all input ecents being issued during the driver update.
|
||||
if (World::getWorld() && RewindManager::get()->isEnabled())
|
||||
{
|
||||
RewindManager::get()
|
||||
->addNextTimeStep(World::getWorld()->getTime(), dt);
|
||||
}
|
||||
|
||||
if (!m_abort && !ProfileWorld::isNoGraphics())
|
||||
{
|
||||
// Render the previous frame, and also handle all user input.
|
||||
|
@ -97,6 +97,22 @@ void RewindManager::reset()
|
||||
m_rewind_queue.reset();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Adds a new TimeStep entry. Only exception is time=0 (which happens during
|
||||
* all of 'ready, set, go') - for which only one entry is created.
|
||||
*/
|
||||
void RewindManager::addNextTimeStep(float time, float dt)
|
||||
{
|
||||
// Add a timestep entry each timestep, except at 'ready, set, go'
|
||||
// at which time is 0 - we add only one entry there
|
||||
if (time>0 || m_rewind_queue.isEmpty())
|
||||
{
|
||||
Log::info("RewindManager", "Adding new timestamp %f dt %f at %lf",
|
||||
time, dt, StkTime::getRealTime());
|
||||
m_rewind_queue.addNewTimeStep(time, dt);
|
||||
}
|
||||
} // addNextTimeStep
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Adds an event to the rewind data. The data to be stored must be allocated
|
||||
* and not freed by the caller!
|
||||
@ -172,12 +188,6 @@ void RewindManager::update(float dt)
|
||||
float time = World::getWorld()->getTime();
|
||||
m_not_rewound_time = time;
|
||||
|
||||
// Avoid duplicating time step during ready-set-go, all with time 0
|
||||
if (time > m_last_saved_state)
|
||||
{
|
||||
m_rewind_queue.addNewTimeStep(World::getWorld()->getTime(), dt);
|
||||
}
|
||||
|
||||
// Clients don't save state, so they just update m_last_saved_state
|
||||
// (only for the above if test) and exit.
|
||||
if ( NetworkConfig::get()->isClient() ||
|
||||
@ -196,7 +206,8 @@ void RewindManager::update(float dt)
|
||||
{
|
||||
m_overall_state_size += buffer->size();
|
||||
// Add to the previously created container
|
||||
m_rewind_queue.addLocalState(*rewinder, buffer, /*confirmed*/true);
|
||||
m_rewind_queue.addLocalState(*rewinder, buffer, /*confirmed*/true,
|
||||
World::getWorld()->getTime());
|
||||
GameProtocol::getInstance()->addState(buffer);
|
||||
} // size >= 0
|
||||
else
|
||||
@ -218,14 +229,19 @@ void RewindManager::update(float dt)
|
||||
*/
|
||||
void RewindManager::playEventsTill(float time, float *dt)
|
||||
{
|
||||
bool needs_rewind;
|
||||
float rewind_time;
|
||||
|
||||
// Merge in all network events that have happened since the last
|
||||
// merge and that have happened before the current time (which will
|
||||
// be getTime()+dt - world time has not been updated yet).
|
||||
m_rewind_queue.mergeNetworkData(World::getWorld()->getTime(), *dt,
|
||||
&needs_rewind, &rewind_time);
|
||||
|
||||
// No events, nothing to do
|
||||
if (m_rewind_queue.isEmpty())
|
||||
return;
|
||||
|
||||
bool needs_rewind;
|
||||
float rewind_time;
|
||||
|
||||
m_rewind_queue.mergeNetworkData(&needs_rewind, &rewind_time);
|
||||
if(needs_rewind)
|
||||
Log::info("RewindManager", "At %f merging states from %f needs rewind",
|
||||
World::getWorld()->getTime(), rewind_time);
|
||||
@ -308,9 +324,6 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
// if the next event is not a state
|
||||
float dt = -1.0f;
|
||||
|
||||
// Restore the state, then all events for the specified time
|
||||
current->replayAllStates();
|
||||
|
||||
// Need to exit loop if in-game menu is open, since world clock
|
||||
// will not be increased while the game is paused
|
||||
if (World::getWorld()->getPhase() == WorldStatus::IN_GAME_MENU_PHASE)
|
||||
|
@ -145,6 +145,7 @@ public:
|
||||
BareNetworkString *buffer, float time);
|
||||
void addNetworkState(int rewinder_index, BareNetworkString *buffer,
|
||||
float time);
|
||||
void addNextTimeStep(float time, float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds a Rewinder to the list of all rewinders.
|
||||
* \return true If rewinding is enabled, false otherwise.
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "network/rewind_queue.hpp"
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
@ -29,6 +30,7 @@
|
||||
*/
|
||||
RewindQueue::RewindQueue()
|
||||
{
|
||||
m_current = m_time_step_info.begin();
|
||||
reset();
|
||||
} // RewindQueue
|
||||
|
||||
@ -99,7 +101,10 @@ void RewindQueue::addNewTimeStep(float time, float dt)
|
||||
}
|
||||
};
|
||||
|
||||
m_time_step_info.insert(i, tsi);
|
||||
// If current was not initialised
|
||||
AllTimeStepInfo::iterator new_tsi = m_time_step_info.insert(i, tsi);
|
||||
if (m_current == m_time_step_info.end())
|
||||
m_current = new_tsi;
|
||||
} // addNewTimeStep
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -109,13 +114,17 @@ void RewindQueue::addNewTimeStep(float time, float dt)
|
||||
* new TimeStepInfo object).
|
||||
* \param Time at which the event that needs to be added hapened.
|
||||
*/
|
||||
TimeStepInfo *RewindQueue::findClosestTimeStepInfo(float t)
|
||||
RewindQueue::AllTimeStepInfo::iterator
|
||||
RewindQueue::findPreviousTimeStepInfo(float t)
|
||||
{
|
||||
AllTimeStepInfo::reverse_iterator i = m_time_step_info.rbegin();
|
||||
while (i != m_time_step_info.rend() && (*i)->getTime() > t)
|
||||
i++;
|
||||
return *i;
|
||||
} // findClosestTimeStepInfo
|
||||
AllTimeStepInfo::iterator i = m_time_step_info.end();
|
||||
while(i!=m_time_step_info.begin())
|
||||
{
|
||||
i--;
|
||||
if ((*i)->getTime() <= t) return i;
|
||||
}
|
||||
return i;
|
||||
} // findPreviousTimeStepInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** A compare function used when sorting the event lists. It sorts events by
|
||||
@ -137,8 +146,11 @@ bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri
|
||||
*/
|
||||
void RewindQueue::insertRewindInfo(RewindInfo *ri)
|
||||
{
|
||||
TimeStepInfo *bucket = findClosestTimeStepInfo(ri->getTime());
|
||||
bucket->insert(ri);
|
||||
// FIXME: this should always be the last element in the list(??)
|
||||
AllTimeStepInfo::iterator bucket = findPreviousTimeStepInfo(ri->getTime());
|
||||
Log::verbose("RewindQueue", "Insert rewind from %f at %f",
|
||||
ri->getTime(), (*bucket)->getTime());
|
||||
(*bucket)->insert(ri);
|
||||
} // insertRewindInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -165,12 +177,12 @@ void RewindQueue::addLocalEvent(EventRewinder *event_rewinder,
|
||||
* \param confirmed If this state is confirmed to be correct (e.g. is
|
||||
* being received from the servrer), or just a local state for
|
||||
* faster rewinds.
|
||||
* \param time Time at which the state was captured.
|
||||
*/
|
||||
void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
bool confirmed)
|
||||
bool confirmed, float time)
|
||||
{
|
||||
RewindInfo *ri = new RewindInfoState(World::getWorld()->getTime(), rewinder,
|
||||
buffer, confirmed);
|
||||
RewindInfo *ri = new RewindInfoState(time, rewinder, buffer, confirmed);
|
||||
assert(ri);
|
||||
insertRewindInfo(ri);
|
||||
} // addLocalState
|
||||
@ -216,48 +228,81 @@ void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Merges thread-safe all data received from the network with the current
|
||||
* local rewind information.
|
||||
* \param world_time Current world time up to which network events will be
|
||||
* merged in.
|
||||
* \param needs_rewind True if network rewind information was received which
|
||||
* was in the past (of this simulation), so a rewind must be performed.
|
||||
* \param rewind_time If needs_rewind is true, the time to which a rewind must
|
||||
* be performed (at least). Otherwise undefined, but the value might
|
||||
* be modified in this function.
|
||||
*/
|
||||
void RewindQueue::mergeNetworkData(bool *needs_rewind, float *rewind_time)
|
||||
void RewindQueue::mergeNetworkData(float world_time, float dt,
|
||||
bool *needs_rewind, float *rewind_time)
|
||||
{
|
||||
*needs_rewind = false;
|
||||
m_network_events.lock();
|
||||
Log::verbose("RewindQueue", "#events in queue at %f %f are %d",
|
||||
world_time, dt, m_network_events.getData().size());
|
||||
if(m_network_events.getData().empty())
|
||||
{
|
||||
m_network_events.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
/** Merge all newly received network events into the main
|
||||
* event list */
|
||||
/* Merge all newly received network events into the main event list. */
|
||||
|
||||
*rewind_time = 99999.9f;
|
||||
bool adjust_next = false;
|
||||
float world_time = World::getWorld()->getTime();
|
||||
|
||||
AllNetworkRewindInfo::iterator i;
|
||||
for (i = m_network_events.getData().begin();
|
||||
i != m_network_events.getData().end(); ++i)
|
||||
// FIXME: making m_network_events sorted would prevent the need to
|
||||
// go through the whole list of events
|
||||
AllNetworkRewindInfo::iterator i = m_network_events.getData().begin();
|
||||
while( i!=m_network_events.getData().end() )
|
||||
{
|
||||
// Check if a rewind is necessary
|
||||
float t= (*i)->getTime();
|
||||
if (t < world_time)
|
||||
// Ignore any events that will happen in the future.
|
||||
if ((*i)->getTime() > world_time+dt)
|
||||
{
|
||||
*needs_rewind = true;
|
||||
if (t < *rewind_time) *rewind_time = t;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
TimeStepInfo *tsi = findClosestTimeStepInfo(t);
|
||||
// FIXME We could try to find the closest TimeStepInfo, or even
|
||||
// perhaps add a new TimeStepInfo if this new entry is
|
||||
// 'close to the middle'.
|
||||
// Find closest previous time step.
|
||||
AllTimeStepInfo::iterator prev =
|
||||
findPreviousTimeStepInfo((*i)->getTime());
|
||||
AllTimeStepInfo::iterator next = prev;
|
||||
next++;
|
||||
|
||||
float event_time = (*i)->getTime();
|
||||
|
||||
TimeStepInfo *tsi;
|
||||
|
||||
// Assign this event to the closest of the two existing timesteps
|
||||
// prev and next (inserting an additional event in the past would
|
||||
// mean more CPU work in the rewind this will very likely trigger.
|
||||
if (next == m_time_step_info.end())
|
||||
tsi = *prev;
|
||||
else if ( (*next)->getTime()-event_time < event_time-(*prev)->getTime() )
|
||||
tsi = *next;
|
||||
else
|
||||
tsi = *prev;
|
||||
|
||||
tsi->insert(*i);
|
||||
|
||||
Log::info("Rewind", "Inserting event from time %f to timstepinfo %f prev %f next %f",
|
||||
(*i)->getTime(), tsi->getTime(),
|
||||
(*prev)->getTime(),
|
||||
next != m_time_step_info.end() ? (*next)->getTime() : 9999 );
|
||||
|
||||
|
||||
// Check if a rewind is necessary
|
||||
if (tsi->getTime() < world_time)
|
||||
{
|
||||
*needs_rewind = true;
|
||||
if (tsi->getTime() < *rewind_time) *rewind_time = tsi->getTime();
|
||||
}
|
||||
i = m_network_events.getData().erase(i);
|
||||
} // for i in m_network_events
|
||||
m_network_events.getData().clear();
|
||||
|
||||
m_network_events.unlock();
|
||||
|
||||
} // mergeNetworkData
|
||||
@ -336,42 +381,9 @@ void RewindQueue::undoUntil(float undo_time)
|
||||
|
||||
} // undoUntil
|
||||
|
||||
|
||||
#ifdef XXXXXXXXXXXXXXX
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Tests the sorting order of events with the same time stamp: states must
|
||||
* be first, then time info, then events.
|
||||
*/
|
||||
void RewindQueue::testingSortingOrderType(EventRewinder *rewinder, int types[3])
|
||||
{
|
||||
for(unsigned int i=0; i<3; i++)
|
||||
{
|
||||
switch (types[i])
|
||||
{
|
||||
case 1: // Insert State
|
||||
{
|
||||
BareNetworkString *s = new BareNetworkString();
|
||||
s->addUInt8(1);
|
||||
addState(NULL, s, true, 0.0f, 0.1f);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
addTimeEvent(0.0f, 0.1f);
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
BareNetworkString *s = new BareNetworkString();
|
||||
s->addUInt8(2);
|
||||
addEvent(rewinder, s, true, 0.0f);
|
||||
break;
|
||||
}
|
||||
default: assert(false);
|
||||
} // switch
|
||||
} // for i =0; i<3
|
||||
|
||||
// This should go back to the first state
|
||||
undoUntil(0.0);
|
||||
|
||||
#ifdef XX
|
||||
// Now test if the three events are sorted in the right order:
|
||||
// State, then time, then event
|
||||
assert(hasMoreRewindInfo());
|
||||
@ -405,64 +417,7 @@ void RewindQueue::testingSortingOrderType(EventRewinder *rewinder, int types[3])
|
||||
assert(!hasMoreRewindInfo());
|
||||
|
||||
} // testingSortingOrderType
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Tests sorting of rewind infos according to their time. It assumes
|
||||
* different times for all events.
|
||||
* \param types The types for the three events.
|
||||
* \param times The times at which the events happened. Must be >0
|
||||
* (since an additional state at t=0 is added to avoid
|
||||
* warnings during undoUntil() ).
|
||||
*/
|
||||
void RewindQueue::testingSortingOrderTime(EventRewinder *rewinder,
|
||||
int types[3], float times[3])
|
||||
{
|
||||
float min_rewind_time = std::min({ times[0], times[1], times[2] });
|
||||
|
||||
// Avoid warnings about 'no state found' when rewinding
|
||||
// and there is indeed no state at the given time.
|
||||
addState(NULL, new BareNetworkString(), true, 0, 0.1f);
|
||||
for (unsigned int i = 0; i<3; i++)
|
||||
{
|
||||
switch (types[i])
|
||||
{
|
||||
case 1: // Insert State
|
||||
{
|
||||
BareNetworkString *s = new BareNetworkString();
|
||||
s->addUInt8(1);
|
||||
addState(NULL, s, true, times[i], 0.1f);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
addTimeEvent(times[i], 0.1f);
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
BareNetworkString *s = new BareNetworkString();
|
||||
s->addUInt8(2);
|
||||
addEvent(rewinder, s, true, times[i]);
|
||||
break;
|
||||
}
|
||||
default: assert(false);
|
||||
} // switch
|
||||
|
||||
} // for i =0; i<3
|
||||
|
||||
// This should go back to the first state
|
||||
undoUntil(min_rewind_time);
|
||||
|
||||
RewindInfo *ri_prev = getCurrent();
|
||||
operator++();
|
||||
while (hasMoreRewindInfo())
|
||||
{
|
||||
RewindInfo *ri = getCurrent();
|
||||
assert(ri_prev->getTime() < ri->getTime());
|
||||
ri_prev = ri;
|
||||
operator++();
|
||||
} // while hasMoreRewindInfo
|
||||
|
||||
} // testingSortingOrderTime
|
||||
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Unit tests for RewindQueue. It tests:
|
||||
* - Sorting order of RewindInfos at the same time (i.e. state before time
|
||||
@ -494,53 +449,70 @@ void RewindQueue::unitTesting()
|
||||
|
||||
RewindQueue q0;
|
||||
assert(q0.isEmpty());
|
||||
assert(!q0.hasMoreRewindInfo());
|
||||
|
||||
// Test sorting of different RewindInfo with identical time stamps.
|
||||
// ----------------------------------------------------------------
|
||||
int types[6][3] = { { 1,2,3 }, { 1,3,2 }, { 2,1,3 },
|
||||
{ 2,3,1 }, { 3,1,2 }, { 3,2,1 } };
|
||||
float times[6][3] = { { 1,2,3 }, { 1,3,2 }, { 2,1,3 },
|
||||
{ 2,3,1 }, { 3,1,2 }, { 3,2,1 } };
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
{
|
||||
RewindQueue *rq = new RewindQueue();
|
||||
rq->testingSortingOrderType(dummy_rewinder, types[i]);
|
||||
delete rq;
|
||||
}
|
||||
q0.addNewTimeStep(0.0f, 0.5f);
|
||||
q0.m_current = q0.m_time_step_info.begin();
|
||||
assert(!q0.isEmpty());
|
||||
assert(q0.hasMoreRewindInfo());
|
||||
assert(q0.m_time_step_info.size() == 1);
|
||||
|
||||
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 0);
|
||||
q0.addLocalState(NULL, NULL, true, 0.0f);
|
||||
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1);
|
||||
|
||||
q0.addNewTimeStep(1.0f, 0.5f);
|
||||
assert(q0.m_time_step_info.size() == 2);
|
||||
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0.0f);
|
||||
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1);
|
||||
|
||||
bool needs_rewind;
|
||||
float rewind_time;
|
||||
float world_time = 0.0f;
|
||||
float dt = 0.01f;
|
||||
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time);
|
||||
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 2);
|
||||
|
||||
// This will add a third TimeStep at t=0.5
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0.5f);
|
||||
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time);
|
||||
assert(q0.m_time_step_info.size() == 3);
|
||||
|
||||
// This event will get added to the last time step info at 1.0:
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 1.0f);
|
||||
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time);
|
||||
// Note that end() is behind the list, i.e. invalid, but rbegin()
|
||||
// is the last element
|
||||
assert((*q0.m_time_step_info.rbegin())->getNumberOfEvents() == 1);
|
||||
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 1.5f);
|
||||
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time);
|
||||
assert(q0.m_time_step_info.size() == 4);
|
||||
|
||||
// Add events within the thresold size to the last event and make sure
|
||||
// no new time step info is created, but the events are all added to the
|
||||
// last entry:
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL,
|
||||
1.5f - stk_config->m_network_combine_threshold / 2.0f);
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL,
|
||||
1.5f + stk_config->m_network_combine_threshold / 2.0f);
|
||||
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time);
|
||||
assert(q0.m_time_step_info.size() == 4);
|
||||
assert((*q0.m_time_step_info.rbegin())->getNumberOfEvents() == 3);
|
||||
|
||||
// Test sorting of different RewindInfo at different times
|
||||
// Checks all combinations of times and types.
|
||||
// -------------------------------------------------------
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
{
|
||||
for (unsigned int j = 0; j < 6; j++)
|
||||
{
|
||||
RewindQueue *rq = new RewindQueue();
|
||||
rq->testingSortingOrderTime(dummy_rewinder, types[i], times[j]);
|
||||
delete rq;
|
||||
} // for j in times
|
||||
} // for i in types
|
||||
|
||||
// Bugs seen before
|
||||
// ----------------
|
||||
// 1) Current pointer was not reset from end of list when an event
|
||||
// was added and the pointer was already at end of list
|
||||
RewindQueue b1;
|
||||
b1.addState(NULL, new BareNetworkString(), true, 1.0f, 0.1f);
|
||||
b1.addNewTimeStep(1.0f, 0.1f);
|
||||
++b1; // Should now point at end of list
|
||||
b1.hasMoreRewindInfo();
|
||||
b1.addEvent(NULL, new BareNetworkString(), true, 2.0f);
|
||||
RewindInfo *ri = b1.getCurrent();
|
||||
assert(ri->getTime() == 2.0f);
|
||||
assert(ri->isEvent());
|
||||
|
||||
} // unitTesting
|
||||
|
||||
|
||||
|
||||
b1.addNewTimeStep(2.0f, 0.1f);
|
||||
TimeStepInfo *tsi = b1.getCurrent();
|
||||
assert(tsi->getTime() == 2.0f);
|
||||
#ifdef XX
|
||||
#endif
|
||||
|
||||
void RewindQueue::unitTesting()
|
||||
{
|
||||
|
||||
}
|
||||
} // unitTesting
|
||||
|
@ -55,7 +55,7 @@ private:
|
||||
* always be at the same time as World::getTime(). */
|
||||
AllTimeStepInfo::iterator m_current;
|
||||
|
||||
TimeStepInfo *findClosestTimeStepInfo(float t);
|
||||
AllTimeStepInfo::iterator findPreviousTimeStepInfo(float t);
|
||||
void insertRewindInfo(RewindInfo *ri);
|
||||
|
||||
struct _TimeStepInfoCompare
|
||||
@ -77,12 +77,13 @@ public:
|
||||
void addLocalEvent(EventRewinder *event_rewinder, BareNetworkString *buffer,
|
||||
bool confirmed, float time);
|
||||
void addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
bool confirmed);
|
||||
bool confirmed, float time);
|
||||
void addNetworkEvent(EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, float time);
|
||||
void addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
float time, float dt);
|
||||
void mergeNetworkData(bool *needs_rewind, float *rewind_time);
|
||||
void mergeNetworkData(float world_time, float dt,
|
||||
bool *needs_rewind, float *rewind_time);
|
||||
bool isEmpty() const;
|
||||
bool hasMoreRewindInfo() const;
|
||||
void undoUntil(float undo_time);
|
||||
|
@ -29,8 +29,12 @@ TimeStepInfo::TimeStepInfo(float time, float dt)
|
||||
{
|
||||
m_time = time;
|
||||
m_dt = dt;
|
||||
m_local_physics_time = Physics::getInstance()->getPhysicsWorld()
|
||||
->getLocalTime();
|
||||
// In case of unit testing physics does not exist
|
||||
if (Physics::getInstance())
|
||||
m_local_physics_time = Physics::getInstance()->getPhysicsWorld()
|
||||
->getLocalTime();
|
||||
else
|
||||
m_local_physics_time = 0.0f;
|
||||
} // StateEventList
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@ -55,7 +59,7 @@ void TimeStepInfo::insert(RewindInfo *ri)
|
||||
// Events at the same time are just added to the end
|
||||
m_list_of_events.push_back(ri);
|
||||
}
|
||||
} // addStaet
|
||||
} // insert
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** Undos all events and states for this time step.
|
||||
@ -68,6 +72,7 @@ void TimeStepInfo::undoAll()
|
||||
(*i)->undo();
|
||||
}
|
||||
} // undoAll
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** Replays all events for this TimeStepInfo.
|
||||
*/
|
||||
|
@ -62,12 +62,18 @@ private:
|
||||
* 60 fps. Restoring this value exactly improves accuracy of rewinds. */
|
||||
float m_local_physics_time;
|
||||
public:
|
||||
TimeStepInfo(float time, float dt);
|
||||
TimeStepInfo(float time, float dt);
|
||||
void insert(RewindInfo *ri);
|
||||
void undoAll();
|
||||
void replayAllEvents();
|
||||
void replayAllStates();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the tiem of this object. */
|
||||
void setTime(float time) { m_time = time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the time step size of this object. */
|
||||
void setDT(float dt) { m_dt = dt; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time for this TimeStepInfo instance. */
|
||||
float getTime() const { return m_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
@ -86,6 +92,10 @@ public:
|
||||
const RewindInfo *ri = m_list_of_events[0];
|
||||
return ri->isState() && ri->isConfirmed();
|
||||
} // hasConfirmedState
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of events (and states) at this time step. Used
|
||||
* in unit testing. */
|
||||
int getNumberOfEvents() const { return m_list_of_events.size(); }
|
||||
}; // TimeStepInfo
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user