Removed support for position-based history files, now only

physics history files are supported.
This commit is contained in:
hiker 2018-03-20 23:52:02 +11:00 committed by Benau
parent edbc7233d2
commit ac3c99a3ca
8 changed files with 126 additions and 335 deletions

View File

@ -316,11 +316,7 @@ void PlayerController::skidBonusTriggered()
*/ */
void PlayerController::update(int ticks) void PlayerController::update(int ticks)
{ {
// Don't do steering if it's replay. In position only replay it doesn't steer(ticks, m_steer_val);
// matter, but if it's physics replay the gradual steering causes
// incorrect results, since the stored values are already adjusted.
if (!history->replayHistory() || !history->dontDoPhysics())
steer(ticks, m_steer_val);
if (World::getWorld()->getPhase() == World::GOAL_PHASE) if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{ {

View File

@ -1268,8 +1268,7 @@ void Kart::update(int ticks)
// is used furthermore for engine power, camera distance etc // is used furthermore for engine power, camera distance etc
updateSpeed(); updateSpeed();
if(!history->replayHistory() || !history->dontDoPhysics()) m_controller->update(ticks);
m_controller->update(ticks);
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
#undef DEBUG_CAMERA_SHAKE #undef DEBUG_CAMERA_SHAKE

View File

@ -580,9 +580,6 @@ void cmdLineHelp()
" --demo-laps=n Number of laps to use in a demo.\n" " --demo-laps=n Number of laps to use in a demo.\n"
" --demo-karts=n Number of karts to use in a demo.\n" " --demo-karts=n Number of karts to use in a demo.\n"
// " --history Replay history file 'history.dat'.\n" // " --history Replay history file 'history.dat'.\n"
// " --history=n Replay history file 'history.dat' using:\n"
// " n=1: recorded positions\n"
// " n=2: recorded key strokes\n"
// " --test-ai=n Use the test-ai for every n-th AI kart.\n" // " --test-ai=n Use the test-ai for every n-th AI kart.\n"
// " (so n=1 means all Ais will be the test ai)\n" // " (so n=1 means all Ais will be the test ai)\n"
// " // "
@ -1373,21 +1370,13 @@ int handleCmdLine()
race_manager->setNumLaps(999999); // profile end depends on time race_manager->setNumLaps(999999); // profile end depends on time
} // --profile-time } // --profile-time
if(CommandLine::has("--history", &n)) if(CommandLine::has("--history"))
{ {
history->doReplayHistory( (History::HistoryReplayMode)n); history->setReplayHistory(true);
// Force the no-start screen flag, since this initialises // Force the no-start screen flag, since this initialises
// the player structures correctly. // the player structures correctly.
if(!MainMenuScreen::m_enable_online) if(!MainMenuScreen::m_enable_online)
UserConfigParams::m_no_start_screen = true; UserConfigParams::m_no_start_screen = true;
} // --history=%d
if(CommandLine::has("--history")) // handy default for --history=1
{
history->doReplayHistory(History::HISTORY_POSITION);
// Force the no-start screen flag, since this initialises
// the player structures correctly.
UserConfigParams::m_no_start_screen = true;
} // --history } // --history
// Demo mode // Demo mode

View File

@ -189,13 +189,6 @@ float MainLoop::getLimitedDt()
dt = World::getWorld()->adjustDT(dt); dt = World::getWorld()->adjustDT(dt);
} }
// If we are doing a replay, use the dt from the history file if this
// is not networked, otherwise history will use current time and dt
// to findout which events to replay
if (World::getWorld() && history->replayHistory() )
{
history->updateReplay(World::getWorld()->getTimeTicks(), dt);
}
return dt; return dt;
} // getLimitedDt } // getLimitedDt
@ -386,7 +379,8 @@ void MainLoop::run()
input_manager->update(frame_duration); input_manager->update(frame_duration);
GUIEngine::update(frame_duration); GUIEngine::update(frame_duration);
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
if (World::getWorld() && history->replayHistory())
history->updateReplay(World::getWorld()->getTimeTicks());
PROFILER_PUSH_CPU_MARKER("Music", 0x7F, 0x00, 0x00); PROFILER_PUSH_CPU_MARKER("Music", 0x7F, 0x00, 0x00);
SFXManager::get()->update(); SFXManager::get()->update();
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();

View File

@ -864,13 +864,6 @@ void World::updateWorld(int ticks)
getPhase() == IN_GAME_MENU_PHASE ) getPhase() == IN_GAME_MENU_PHASE )
return; return;
if (!history->replayHistory() &&
! (NetworkConfig::get()->isClient() &&
RewindManager::get()->isRewinding() ) )
{
history->updateSaving(ticks); // updating the saved state
}
try try
{ {
update(ticks); update(ticks);
@ -1038,10 +1031,7 @@ void World::update(int ticks)
Scripting::ScriptEngine *script_engine = Scripting::ScriptEngine::getInstance(); Scripting::ScriptEngine *script_engine = Scripting::ScriptEngine::getInstance();
if (script_engine) script_engine->update(ticks); if (script_engine) script_engine->update(ticks);
if (!history->dontDoPhysics()) Physics::getInstance()->update(ticks);
{
Physics::getInstance()->update(ticks);
}
PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00); PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
projectile_manager->update(ticks); projectile_manager->update(ticks);

View File

@ -33,7 +33,7 @@
#include <algorithm> #include <algorithm>
RewindManager* RewindManager::m_rewind_manager = NULL; RewindManager* RewindManager::m_rewind_manager = NULL;
bool RewindManager::m_enable_rewind_manager = false; bool RewindManager::m_enable_rewind_manager = false;
/** Creates the singleton. */ /** Creates the singleton. */
@ -74,19 +74,19 @@ RewindManager::~RewindManager()
*/ */
void RewindManager::reset() void RewindManager::reset()
{ {
m_is_rewinding = false; m_is_rewinding = false;
m_not_rewound_ticks = 0; m_not_rewound_ticks = 0;
m_overall_state_size = 0; m_overall_state_size = 0;
m_last_saved_state = -1; // forces initial state save m_last_saved_state = -1; // forces initial state save
m_state_frequency = m_state_frequency =
stk_config->getPhysicsFPS() / stk_config->m_network_state_frequeny; stk_config->getPhysicsFPS() / stk_config->m_network_state_frequeny;
if(!m_enable_rewind_manager) return; if (!m_enable_rewind_manager) return;
AllRewinder::iterator r = m_all_rewinder.begin(); AllRewinder::iterator r = m_all_rewinder.begin();
while(r!=m_all_rewinder.end()) while (r != m_all_rewinder.end())
{ {
if(!(*r)->canBeDestroyed()) if (!(*r)->canBeDestroyed())
{ {
r++; r++;
continue; continue;
@ -107,8 +107,8 @@ void RewindManager::addNextTimeStep(int time, float dt)
{ {
// Add a timestep entry each timestep, except at 'ready, set, go' // Add a timestep entry each timestep, except at 'ready, set, go'
// at which time is 0 - we add only one entry there // at which time is 0 - we add only one entry there
if ( ( time>0 || m_rewind_queue.isEmpty() ) && if ((time > 0 || m_rewind_queue.isEmpty()) &&
World::getWorld()->getPhase() != WorldStatus::IN_GAME_MENU_PHASE ) World::getWorld()->getPhase() != WorldStatus::IN_GAME_MENU_PHASE)
{ {
m_rewind_queue.addNewTimeStep(time, dt); m_rewind_queue.addNewTimeStep(time, dt);
} }
@ -119,13 +119,13 @@ void RewindManager::addNextTimeStep(int time, float dt)
* and not freed by the caller! * and not freed by the caller!
* \param time Time at which the event was recorded. If time is not specified * \param time Time at which the event was recorded. If time is not specified
* (or set to -1), the current world time is used. * (or set to -1), the current world time is used.
* \param buffer Pointer to the event data. * \param buffer Pointer to the event data.
*/ */
void RewindManager::addEvent(EventRewinder *event_rewinder, void RewindManager::addEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, bool confirmed, BareNetworkString *buffer, bool confirmed,
int ticks ) int ticks)
{ {
if(m_is_rewinding) if (m_is_rewinding)
{ {
delete buffer; delete buffer;
Log::error("RewindManager", "Adding event when rewinding"); Log::error("RewindManager", "Adding event when rewinding");
@ -146,7 +146,7 @@ void RewindManager::addEvent(EventRewinder *event_rewinder,
* \param buffer Pointer to the event data. * \param buffer Pointer to the event data.
*/ */
void RewindManager::addNetworkEvent(EventRewinder *event_rewinder, void RewindManager::addNetworkEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, int ticks) BareNetworkString *buffer, int ticks)
{ {
m_rewind_queue.addNetworkEvent(event_rewinder, buffer, ticks); m_rewind_queue.addNetworkEvent(event_rewinder, buffer, ticks);
} // addNetworkEvent } // addNetworkEvent
@ -160,13 +160,13 @@ void RewindManager::addNetworkEvent(EventRewinder *event_rewinder,
* \param buffer Pointer to the event data. * \param buffer Pointer to the event data.
*/ */
void RewindManager::addNetworkState(int rewinder_index, BareNetworkString *buffer, void RewindManager::addNetworkState(int rewinder_index, BareNetworkString *buffer,
int ticks) int ticks)
{ {
assert(NetworkConfig::get()->isClient()); assert(NetworkConfig::get()->isClient());
// On a client dt from a state is never used, it maintains // On a client dt from a state is never used, it maintains
// its own dt information (using TimeEvents). // its own dt information (using TimeEvents).
m_rewind_queue.addNetworkState(m_all_rewinder[rewinder_index], buffer, m_rewind_queue.addNetworkState(m_all_rewinder[rewinder_index], buffer,
ticks, -99); ticks, -99);
} // addNetworkState } // addNetworkState
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -177,9 +177,9 @@ void RewindManager::addNetworkState(int rewinder_index, BareNetworkString *buffe
void RewindManager::update(int ticks_not_used) void RewindManager::update(int ticks_not_used)
{ {
// FIXME: rename ticks_not_used // FIXME: rename ticks_not_used
if(!m_enable_rewind_manager || if (!m_enable_rewind_manager ||
m_all_rewinder.size()==0 || m_all_rewinder.size() == 0 ||
m_is_rewinding ) return; m_is_rewinding) return;
float time = World::getWorld()->getTime(); float time = World::getWorld()->getTime();
int ticks = World::getWorld()->getTimeTicks(); int ticks = World::getWorld()->getTimeTicks();
@ -187,8 +187,8 @@ void RewindManager::update(int ticks_not_used)
m_not_rewound_ticks = ticks; m_not_rewound_ticks = ticks;
// Clients don't save state, so they just exit. // Clients don't save state, so they just exit.
if ( NetworkConfig::get()->isClient() || if (NetworkConfig::get()->isClient() ||
ticks - m_last_saved_state < m_state_frequency ) ticks - m_last_saved_state < m_state_frequency)
{ {
return; return;
} }
@ -197,15 +197,15 @@ void RewindManager::update(int ticks_not_used)
// Save state // Save state
GameProtocol::lock()->startNewState(); GameProtocol::lock()->startNewState();
AllRewinder::const_iterator rewinder; AllRewinder::const_iterator rewinder;
for(rewinder=m_all_rewinder.begin(); rewinder!=m_all_rewinder.end(); ++rewinder) for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder)
{ {
BareNetworkString *buffer = (*rewinder)->saveState(); BareNetworkString *buffer = (*rewinder)->saveState();
if(buffer && buffer->size()>=0) if (buffer && buffer->size() >= 0)
{ {
m_overall_state_size += buffer->size(); m_overall_state_size += buffer->size();
// Add to the previously created container // Add to the previously created container
m_rewind_queue.addLocalState(*rewinder, buffer, /*confirmed*/true, m_rewind_queue.addLocalState(*rewinder, buffer, /*confirmed*/true,
World::getWorld()->getTimeTicks()); World::getWorld()->getTimeTicks());
GameProtocol::lock()->addState(buffer); GameProtocol::lock()->addState(buffer);
} // size >= 0 } // size >= 0
else else
@ -224,7 +224,7 @@ void RewindManager::update(int ticks_not_used)
* \param dt Number of time steps - should be 1. * \param dt Number of time steps - should be 1.
*/ */
void RewindManager::playEventsTill(float time, int *ticks) void RewindManager::playEventsTill(float time, int *ticks)
{ {
bool needs_rewind; bool needs_rewind;
int rewind_ticks; int rewind_ticks;
@ -233,7 +233,7 @@ void RewindManager::playEventsTill(float time, int *ticks)
// merge and that have happened before the current time (which will // merge and that have happened before the current time (which will
// be getTime()+dt - world time has not been updated yet). // be getTime()+dt - world time has not been updated yet).
m_rewind_queue.mergeNetworkData(World::getWorld()->getTimeTicks(), m_rewind_queue.mergeNetworkData(World::getWorld()->getTimeTicks(),
&needs_rewind, &rewind_ticks); &needs_rewind, &rewind_ticks);
if (needs_rewind) if (needs_rewind)
{ {
@ -260,7 +260,7 @@ void RewindManager::playEventsTill(float time, int *ticks)
TimeStepInfo *tsi = m_rewind_queue.getLast(); TimeStepInfo *tsi = m_rewind_queue.getLast();
// ++m_rewind_queue; // Point to end of queue now // ++m_rewind_queue; // Point to end of queue now
tsi->replayAllEvents(); tsi->replayAllEvents();
if (tsi->hasConfirmedState() && NetworkConfig::get()->isClient()) if (tsi->hasConfirmedState() && NetworkConfig::get()->isClient())
@ -282,14 +282,14 @@ void RewindManager::rewindTo(int rewind_ticks)
{ {
assert(!m_is_rewinding); assert(!m_is_rewinding);
bool is_history = history->replayHistory(); bool is_history = history->replayHistory();
history->doReplayHistory(History::HISTORY_NONE); history->setReplayHistory(false);
// First save all current transforms so that the error // First save all current transforms so that the error
// can be computed between the transforms before and after // can be computed between the transforms before and after
// the rewind. // the rewind.
AllRewinder::iterator rewinder; AllRewinder::iterator rewinder;
for (rewinder = m_all_rewinder.begin(); for (rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder) rewinder != m_all_rewinder.end(); ++rewinder)
{ {
(*rewinder)->saveTransform(); (*rewinder)->saveTransform();
} }
@ -323,7 +323,7 @@ void RewindManager::rewindTo(int rewind_ticks)
if (World::getWorld()->getPhase() == WorldStatus::IN_GAME_MENU_PHASE) if (World::getWorld()->getPhase() == WorldStatus::IN_GAME_MENU_PHASE)
{ {
m_is_rewinding = false; m_is_rewinding = false;
history->doReplayHistory(History::HISTORY_PHYSICS); history->setReplayHistory(is_history);
return; return;
} }
@ -334,7 +334,7 @@ void RewindManager::rewindTo(int rewind_ticks)
// info for the current time has already been added previously, so // info for the current time has already been added previously, so
// we rewind till we have reached the last timestep entry (which is // we rewind till we have reached the last timestep entry (which is
// the current time step). // the current time step).
while (current !=m_rewind_queue.getLast()) while (current != m_rewind_queue.getLast())
{ {
// Now handle all events(!) at the current time (i.e. between // Now handle all events(!) at the current time (i.e. between
// World::getTime() and World::getTime()+dt) before updating // World::getTime() and World::getTime()+dt) before updating
@ -359,8 +359,8 @@ void RewindManager::rewindTo(int rewind_ticks)
{ {
(*rewinder)->computeError(); (*rewinder)->computeError();
} }
if(is_history)
history->doReplayHistory(History::HISTORY_PHYSICS); history->setReplayHistory(is_history);
m_is_rewinding = false; m_is_rewinding = false;
} // rewindTo } // rewindTo

View File

@ -39,7 +39,7 @@ History* history = 0;
*/ */
History::History() History::History()
{ {
m_replay_mode = HISTORY_NONE; m_replay_history = false;
} // History } // History
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -48,12 +48,7 @@ History::History()
*/ */
void History::initRecording() void History::initRecording()
{ {
unsigned int max_frames = (unsigned int)( stk_config->m_replay_max_time allocateMemory();
/ stk_config->m_replay_dt );
allocateMemory(max_frames);
m_current = -1;
m_wrapped = false;
m_size = 0;
m_event_index = 0; m_event_index = 0;
m_all_input_events.clear(); m_all_input_events.clear();
} // initRecording } // initRecording
@ -63,13 +58,13 @@ void History::initRecording()
* as when replaying (since in replay the data is read into memory first). * as when replaying (since in replay the data is read into memory first).
* \param number_of_frames Maximum number of frames to store. * \param number_of_frames Maximum number of frames to store.
*/ */
void History::allocateMemory(int number_of_frames) void History::allocateMemory(int size)
{ {
m_all_deltas.resize (number_of_frames); m_all_input_events.clear();
unsigned int num_karts = race_manager->getNumberOfKarts(); if(size<0)
m_all_controls.resize (number_of_frames*num_karts); m_all_input_events.reserve(1024);
m_all_xyz.resize (number_of_frames*num_karts); else
m_all_rotations.resize(number_of_frames*num_karts); m_all_input_events.resize(size);
} // allocateMemory } // allocateMemory
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -85,7 +80,6 @@ void History::addEvent(int kart_id, PlayerAction pa, int value)
InputEvent ie; InputEvent ie;
// The event is added before m_current is increased. So in order to // The event is added before m_current is increased. So in order to
// save the right index for this event, we need to use m_current+1. // save the right index for this event, we need to use m_current+1.
ie.m_index = m_current+1;
ie.m_world_ticks = World::getWorld()->getTimeTicks(); ie.m_world_ticks = World::getWorld()->getTimeTicks();
ie.m_action = pa; ie.m_action = pa;
ie.m_value = value; ie.m_value = value;
@ -93,76 +87,32 @@ void History::addEvent(int kart_id, PlayerAction pa, int value)
m_all_input_events.emplace_back(ie); m_all_input_events.emplace_back(ie);
} // addEvent } // addEvent
//-----------------------------------------------------------------------------
/** Saves the current history.
* \param dt Time step size.
*/
void History::updateSaving(int ticks)
{
m_current++;
if(m_current>=(int)m_all_deltas.size())
{
m_wrapped = true;
m_current = 0;
}
else
{
// m_size must be m_all_deltas.size() or smaller
if(m_size<(int)m_all_deltas.size())
m_size ++;
}
m_all_deltas[m_current] = ticks;
World *world = World::getWorld();
unsigned int num_karts = world->getNumKarts();
unsigned int index = m_current*num_karts;
for(unsigned int i=0; i<num_karts; i++)
{
const AbstractKart *kart = world->getKart(i);
m_all_controls[index+i] = kart->getControls();
m_all_xyz[index+i] = kart->getXYZ();
m_all_rotations[index+i] = kart->getVisualRotation();
} // for i
} // updateSaving
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Sets the kart position and controls to the recorded history value. /** Sets the kart position and controls to the recorded history value.
* \param world_ticks WOrld time in ticks. * \param world_ticks WOrld time in ticks.
* \param ticks Number of time steps. * \param ticks Number of time steps.
*/ */
void History::updateReplay(int world_ticks, float dt) void History::updateReplay(int world_ticks)
{ {
World *world = World::getWorld(); World *world = World::getWorld();
// Networking
// ---------- while (m_event_index < m_all_input_events.size() &&
// Networking is handled differently, it only uses the events, m_all_input_events[m_event_index].m_world_ticks <= world_ticks)
// not the recorded time steps.
if (NetworkConfig::get()->isNetworking())
{ {
while (m_event_index < m_all_input_events.size() && const InputEvent &ie = m_all_input_events[m_event_index];
m_all_input_events[m_event_index].m_world_ticks <= world_ticks) AbstractKart *kart = world->getKart(ie.m_kart_index);
{ Log::verbose("history", "time %d event-time %d action %d %d",
const InputEvent &ie = m_all_input_events[m_event_index]; world->getTimeTicks(), ie.m_world_ticks, ie.m_action,
AbstractKart *kart = world->getKart(ie.m_kart_index); ie.m_value);
Log::verbose("history", "time %d event-time %d action %d %d", kart->getController()->action(ie.m_action, ie.m_value);
world->getTimeTicks(), ie.m_world_ticks, ie.m_action, m_event_index++;
ie.m_value); } // while we have events for current time step.
kart->getController()->action(ie.m_action, ie.m_value);
m_event_index++;
}
return;
}
// Now handle the non-networking case
// ----------------------------------
m_current++;
// Check if we have reached the end of the buffer // Check if we have reached the end of the buffer
if (m_current >= (int)m_all_deltas.size()) if(m_event_index >= m_all_input_events.size())
{ {
Log::info("History", "Replay finished"); Log::info("History", "Replay finished");
m_current = 0; m_event_index= 0;
// This is useful to use a reproducable rewind problem: // This is useful to use a reproducable rewind problem:
// replay it with history, for debugging only // replay it with history, for debugging only
#undef DO_REWIND_AT_END_OF_HISTORY #undef DO_REWIND_AT_END_OF_HISTORY
@ -170,37 +120,9 @@ void History::updateReplay(int world_ticks, float dt)
RewindManager::get()->rewindTo(5.0f); RewindManager::get()->rewindTo(5.0f);
exit(-1); exit(-1);
#else #else
// Note that for physics replay all physics parameters
// need to be reset, e.g. velocity, ...
world->reset(); world->reset();
#endif #endif
} } // if m_event_index >= m_all_input_events.size()
if (m_replay_mode == HISTORY_POSITION)
{
unsigned int num_karts = world->getNumKarts();
for (unsigned k = 0; k < num_karts; k++)
{
AbstractKart *kart = world->getKart(k);
unsigned int index = m_current*num_karts + k;
kart->setXYZ(m_all_xyz[index]);
kart->setRotation(m_all_rotations[index]);
} // for k < karts
} // if HISTORY_POSITION
else // HISTORY_PHYSICS
{
while (m_event_index < m_all_input_events.size() &&
m_all_input_events[m_event_index].m_index == m_current)
{
const InputEvent &ie = m_all_input_events[m_event_index];
AbstractKart *kart = world->getKart(ie.m_kart_index);
Log::verbose("history", "time %d event-time %d action %d %d",
world->getTimeTicks(), ie.m_world_ticks, ie.m_action,
ie.m_value);
kart->getController()->action(ie.m_action, ie.m_value);
m_event_index++;
}
}
} // updateReplay } // updateReplay
@ -230,13 +152,14 @@ void History::Save()
World *world = World::getWorld(); World *world = World::getWorld();
const int num_karts = world->getNumKarts(); const int num_karts = world->getNumKarts();
fprintf(fd, "Version-2: %s\n", STK_VERSION); fprintf(fd, "STK-version: %s\n", STK_VERSION);
fprintf(fd, "numkarts: %d\n", num_karts); fprintf(fd, "History-version: %d\n", 1);
fprintf(fd, "numplayers: %d\n", race_manager->getNumPlayers()); fprintf(fd, "numkarts: %d\n", num_karts);
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); fprintf(fd, "numplayers: %d\n", race_manager->getNumPlayers());
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
fprintf(fd, "reverse: %c\n", race_manager->getReverseTrack() ? 'y' : 'n'); fprintf(fd, "reverse: %c\n", race_manager->getReverseTrack() ? 'y' : 'n');
fprintf(fd, "track: %s\n", Track::getCurrentTrack()->getIdent().c_str()); fprintf(fd, "track: %s\n", Track::getCurrentTrack()->getIdent().c_str());
assert(num_karts > 0); assert(num_karts > 0);
@ -245,52 +168,17 @@ void History::Save()
{ {
fprintf(fd, "model %d: %s\n",k, world->getKart(k)->getIdent().c_str()); fprintf(fd, "model %d: %s\n",k, world->getKart(k)->getIdent().c_str());
} }
fprintf(fd, "size: %d\n", m_size); fprintf(fd, "count: %d\n", m_all_input_events.size());
int index = m_wrapped ? m_current : 0; for (unsigned int i = 0; i < m_all_input_events.size(); i++)
for(int i=0; i<m_size; i++)
{ {
fprintf(fd, "delta: %12.9f\n",m_all_deltas[index]); fprintf(fd, "%d %d %d %d\n",
index=(index+1)%m_size; m_all_input_events[i].m_world_ticks,
} m_all_input_events[i].m_kart_index,
m_all_input_events[i].m_action,
index = m_wrapped ? m_current : 0; m_all_input_events[i].m_value );
int event_index = 0;
for(int i=0; i<m_size; i++)
{
int base_index = index * num_karts;
for(int k=0; k<num_karts; k++)
{
fprintf(fd, "%f %f %d %f %f %f %f %f %f %f\n",
m_all_controls[base_index+k].getSteer(),
m_all_controls[base_index+k].getAccel(),
m_all_controls[base_index+k].getButtonsCompressed(),
m_all_xyz[base_index+k].getX(), m_all_xyz[base_index+k].getY(),
m_all_xyz[base_index+k].getZ(),
m_all_rotations[base_index+k].getX(),
m_all_rotations[base_index+k].getY(),
m_all_rotations[base_index+k].getZ(),
m_all_rotations[base_index+k].getW() );
} // for k
// Find number of events for this frame
int count = 0;
while ( event_index+count < (int)m_all_input_events.size() &&
m_all_input_events[event_index+count].m_index == index )
{
count++;
}
fprintf(fd, "%d\n", count);
for (int k = 0; k < count; k++)
{
fprintf(fd, "%d %d %d %12.9f\n",
m_all_input_events[event_index].m_kart_index,
m_all_input_events[event_index].m_action,
m_all_input_events[event_index].m_value,
m_all_input_events[event_index].m_world_ticks);
event_index++;
}
index=(index+1)%m_size;
} // for i } // for i
fprintf(fd, "History file end.\n"); fprintf(fd, "History file end.\n");
fclose(fd); fclose(fd);
} // Save } // Save
@ -319,16 +207,29 @@ void History::Load()
if (fgets(s, 1023, fd) == NULL) if (fgets(s, 1023, fd) == NULL)
Log::fatal("History", "Could not read history.dat."); Log::fatal("History", "Could not read history.dat.");
int version = 0; // Check for unsupported hsitory file formats:
if (sscanf(s, "Version-2: %1023s", s1) == 1) if (sscanf(s, "Version-2: %1023s", s1) == 1 ||
version = 2; sscanf(s, "Version-1: %1023s", s1) == 1)
else if (sscanf(s,"Version: %1023s",s1)!=1) {
Log::fatal("History",
"Old history file format is not supported anymore.");
}
if (sscanf(s,"STK-version: %1023s",s1)!=1)
Log::fatal("History", "No Version information found in history " Log::fatal("History", "No Version information found in history "
"file (bogus history file)."); "file (bogus history file).");
if (strcmp(s1,STK_VERSION)) if (strcmp(s1,STK_VERSION))
Log::warn("History", "History is version '%s', STK version is '%s'.", Log::warn("History", "History is version '%s', STK version is '%s'.",
s1, STK_VERSION); s1, STK_VERSION);
if (version != 2)
if (fgets(s, 1023, fd) == NULL)
Log::fatal("History", "Could not read history.dat.");
int version;
if (sscanf(s, "History-version: %1023d", &version) != 1)
Log::fatal("Invalid version number found: '%s'", s);
if (version != 1)
Log::fatal("History", Log::fatal("History",
"Old-style history files are not supported anymore."); "Old-style history files are not supported anymore.");
@ -351,22 +252,19 @@ void History::Load()
race_manager->setDifficulty((RaceManager::Difficulty)n); race_manager->setDifficulty((RaceManager::Difficulty)n);
// Optional (not supported in older history files): include reverse
fgets(s, 1023, fd); fgets(s, 1023, fd);
char r; char r;
if (sscanf(s, "reverse: %c", &r) == 1) if (sscanf(s, "reverse: %c", &r) != 1)
{ Log::fatal("History", "Could not read reverse information: '%s'", s);
fgets(s, 1023, fd); race_manager->setReverseTrack(r == 'y');
race_manager->setReverseTrack(r == 'y');
}
fgets(s, 1023, fd);
if(sscanf(s, "track: %1023s",s1)!=1) if(sscanf(s, "track: %1023s",s1)!=1)
Log::warn("History", "Track not found in history file."); Log::warn("History", "Track not found in history file.");
race_manager->setTrack(s1); race_manager->setTrack(s1);
// This value doesn't really matter, but should be defined, otherwise // This value doesn't really matter, but should be defined, otherwise
// the racing phase can switch to 'ending' // the racing phase can switch to 'ending'
race_manager->setNumLaps(10); race_manager->setNumLaps(100);
for(unsigned int i=0; i<num_karts; i++) for(unsigned int i=0; i<num_karts; i++)
{ {
@ -380,60 +278,29 @@ void History::Load()
} }
} // for i<nKarts } // for i<nKarts
// FIXME: The model information is currently ignored // FIXME: The model information is currently ignored
fgets(s, 1023, fd); fgets(s, 1023, fd);
if(sscanf(s,"size: %d",&m_size)!=1) int count;
if(sscanf(s,"count: %d",&count)!=1)
Log::fatal("History", "Number of records not found in history file."); Log::fatal("History", "Number of records not found in history file.");
allocateMemory(m_size); allocateMemory(count);
m_current = -1;
m_event_index = 0; m_event_index = 0;
for(int i=0; i<m_size; i++)
{
fgets(s, 1023, fd);
sscanf(s, "delta: %f\n",&m_all_deltas[i]);
}
// We need to disable the rewind manager here (otherwise setting the // We need to disable the rewind manager here (otherwise setting the
// KartControl data would access the rewind manager). // KartControl data would access the rewind manager).
bool rewind_manager_was_enabled = RewindManager::isEnabled(); bool rewind_manager_was_enabled = RewindManager::isEnabled();
RewindManager::setEnable(false); RewindManager::setEnable(false);
m_all_input_events.clear();
for(int i=0; i<m_size; i++) for (int i=0; i<count; i++)
{ {
for(unsigned int k=0; k<num_karts; k++)
{
unsigned int index = num_karts * i+k;
fgets(s, 1023, fd);
int buttonsCompressed;
float x,y,z,rx,ry,rz,rw, steer, accel;
sscanf(s, "%f %f %d %f %f %f %f %f %f %f\n",
&steer, &accel, &buttonsCompressed,
&x, &y, &z,
&rx, &ry, &rz, &rw
);
m_all_controls[index].setSteer(steer);
m_all_controls[index].setAccel(accel);
m_all_xyz[index] = Vec3(x,y,z);
m_all_rotations[index] = btQuaternion(rx,ry,rz,rw);
m_all_controls[index].setButtonsCompressed(char(buttonsCompressed));
} // for k
fgets(s, 1023, fd); fgets(s, 1023, fd);
int count; InputEvent &ie = m_all_input_events[i];
if (sscanf(s, "%d\n", &count) != 1) if (sscanf(s, "%d %d %d %d\n", &ie.m_world_ticks, &ie.m_kart_index,
Log::warn("History", "Problems reading event count: '%s'.", s); &ie.m_action, &ie.m_value) != 4 )
for (int k = 0; k < count; k++)
{ {
fgets(s, 1023, fd); Log::warn("History", "Problems reading event: '%s'", s);
InputEvent ie; }
ie.m_index = i;
if (sscanf(s, "%d %d %d %f\n", &ie.m_kart_index, &ie.m_action,
&ie.m_value, &ie.m_world_ticks) != 4)
{
Log::warn("History", "Problems reading event: '%s'", s);
}
m_all_input_events.emplace_back(ie);
} // for k < count
} // for i } // for i
RewindManager::setEnable(rewind_manager_was_enabled); RewindManager::setEnable(rewind_manager_was_enabled);

View File

@ -19,15 +19,12 @@
#ifndef HEADER_HISTORY_HPP #ifndef HEADER_HISTORY_HPP
#define HEADER_HISTORY_HPP #define HEADER_HISTORY_HPP
#include <vector>
#include <string>
#include "LinearMath/btQuaternion.h"
#include "input/input.hpp" #include "input/input.hpp"
#include "karts/controller/kart_control.hpp" #include "karts/controller/kart_control.hpp"
#include "utils/aligned_array.hpp"
#include "utils/vec3.hpp" #include <string>
#include <vector>
class Kart; class Kart;
@ -36,55 +33,19 @@ class Kart;
*/ */
class History class History
{ {
public:
/** Determines which replay mode is selected:
* HISTORY_NONE: no history replay.
* HISTORY_POSITION: replay the positions and orientations of the karts,
* but don't simulate the physics.
* HISTORY_PHYSICS: Simulate the phyics based on the recorded actions.
* These values can be used together, e.g. HISTORY_POSITION|HISTORY_CONTROL
*/
enum HistoryReplayMode { HISTORY_NONE = 0,
HISTORY_POSITION = 1,
HISTORY_PHYSICS = 2 };
private: private:
/** maximum number of history events to store. */ /** True if a history should be replayed, */
HistoryReplayMode m_replay_mode; bool m_replay_history;
/** Points to the last used entry, and will wrap around. */
int m_current;
/** Points to the last used input event index. */ /** Points to the last used input event index. */
unsigned int m_event_index; unsigned int m_event_index;
/** True if the buffer has wrapped around. */
bool m_wrapped;
/** Counts how many entries in the arrays are used. So if
* the buffer hasn't wrapped around, this will indicate
* how many entries to save. */
int m_size;
/** Stores all time step sizes. */
std::vector<float> m_all_deltas;
/** Stores the kart controls being used (for physics replay). */
std::vector<KartControl> m_all_controls;
/** Stores the coordinates (for simple replay). */
AlignedArray<Vec3> m_all_xyz;
/** Stores the rotations of the karts. */
AlignedArray<btQuaternion> m_all_rotations;
/** The identities of the karts to use. */ /** The identities of the karts to use. */
std::vector<std::string> m_kart_ident; std::vector<std::string> m_kart_ident;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
struct InputEvent struct InputEvent
{ {
/** Index at which the even happened. */
int m_index;
/* Time at which this event occurred. */ /* Time at which this event occurred. */
int m_world_ticks; int m_world_ticks;
/** For which kart the event was. */ /** For which kart the event was. */
@ -99,14 +60,13 @@ private:
/** All input events. */ /** All input events. */
std::vector<InputEvent> m_all_input_events; std::vector<InputEvent> m_all_input_events;
void allocateMemory(int number_of_frames); void allocateMemory(int size=-1);
public: public:
History (); History ();
void initRecording (); void initRecording ();
void Save (); void Save ();
void Load (); void Load ();
void updateSaving(int ticks); void updateReplay(int world_ticks);
void updateReplay(int world_ticks, float dt);
void addEvent(int kart_id, PlayerAction pa, int value); void addEvent(int kart_id, PlayerAction pa, int value);
// -------------------I----------------------------------------------------- // -------------------I-----------------------------------------------------
@ -117,14 +77,10 @@ public:
} // getKartIdent } // getKartIdent
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns if a history is replayed, i.e. the history mode is not none. */ /** Returns if a history is replayed, i.e. the history mode is not none. */
bool replayHistory () const { return m_replay_mode != HISTORY_NONE; } bool replayHistory() const { return m_replay_history; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Enable replaying a history, enabled from the command line. */ /** Set if replay is enabled or not. */
void doReplayHistory(HistoryReplayMode m) {m_replay_mode = m; } void setReplayHistory(bool b) { m_replay_history=b; }
// ------------------------------------------------------------------------
/** Returns true if the physics should not be simulated in replay mode.
* I.e. either no replay mode, or physics replay mode. */
bool dontDoPhysics () const { return m_replay_mode == HISTORY_POSITION;}
}; };
extern History* history; extern History* history;