Merge remote-tracking branch 'origin/fix-timestep' into game_protocol.

Started to use ticks instead of time floating point values in networking.
This commit is contained in:
hiker 2018-03-13 18:37:12 +11:00
commit d3a60356c9
42 changed files with 502 additions and 412 deletions

View File

@ -59,9 +59,11 @@ public:
* - SAME: give it one more item of the type it currently has. * - SAME: give it one more item of the type it currently has.
* - ONLY_IF_SAME: only give it one more item if the randomly chosen item * - ONLY_IF_SAME: only give it one more item if the randomly chosen item
* has the same type as the currently held item. */ * has the same type as the currently held item. */
enum {POWERUP_MODE_NEW, enum {
POWERUP_MODE_NEW,
POWERUP_MODE_SAME, POWERUP_MODE_SAME,
POWERUP_MODE_ONLY_IF_SAME} POWERUP_MODE_ONLY_IF_SAME
}
m_same_powerup_mode; m_same_powerup_mode;
static float UNDEFINED; static float UNDEFINED;
@ -105,9 +107,6 @@ public:
/** Default friction to be used for any moveable, e.g. karts, balls. */ /** Default friction to be used for any moveable, e.g. karts, balls. */
float m_default_moveable_friction; float m_default_moveable_friction;
/** Default FPS rate for physics. */
int m_physics_fps;
int m_max_skidmarks; /**<Maximum number of skid marks/kart. */ int m_max_skidmarks; /**<Maximum number of skid marks/kart. */
float m_skid_fadeout_time; /**<Time till skidmarks fade away. */ float m_skid_fadeout_time; /**<Time till skidmarks fade away. */
float m_near_ground; /**<Determines when a kart is not near float m_near_ground; /**<Determines when a kart is not near
@ -182,6 +181,10 @@ private:
* loaded a user specified config file. */ * loaded a user specified config file. */
bool m_has_been_loaded; bool m_has_been_loaded;
/** Default FPS rate for physics. */
int m_physics_fps;
public: public:
STKConfig(); STKConfig();
~STKConfig(); ~STKConfig();
@ -190,6 +193,7 @@ public:
void load(const std::string &filename); void load(const std::string &filename);
const std::string &getMainMenuPicture(int n); const std::string &getMainMenuPicture(int n);
const std::string &getBackgroundPicture(int n); const std::string &getBackgroundPicture(int n);
void getAllScores(std::vector<int> *all_scores, int num_karts); void getAllScores(std::vector<int> *all_scores, int num_karts);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the default kart properties for each kart. */ /** Returns the default kart properties for each kart. */
@ -205,6 +209,15 @@ public:
{ {
return *m_kart_properties.at(type); return *m_kart_properties.at(type);
} // getKartProperties } // getKartProperties
// ------------------------------------------------------------------------
/** Converts a tick value (in physics time step size) into seconds. */
float ticks2Time(int ticks) { return float(ticks)/m_physics_fps; }
// ------------------------------------------------------------------------
/** Converts a time value into ticks (of physics time steps). */
int time2Ticks(float t) { return int(t * m_physics_fps); }
// ------------------------------------------------------------------------
/** Returns the physics frame per seconds rate. */
int getPhysicsFPS() const { return m_physics_fps; }
} }
; // STKConfig ; // STKConfig

View File

@ -167,8 +167,8 @@ void Camera::setupCamera()
m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight())); m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight()));
m_scaling = core::vector2df( m_scaling = core::vector2df(
irr_driver->getActualScreenSize().Width / m_viewport.getWidth() , float(irr_driver->getActualScreenSize().Width) / m_viewport.getWidth() ,
irr_driver->getActualScreenSize().Height / m_viewport.getHeight()); float(irr_driver->getActualScreenSize().Height) / m_viewport.getHeight());
m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov
[race_manager->getNumLocalPlayers() > 0 ? [race_manager->getNumLocalPlayers() > 0 ?

View File

@ -921,7 +921,7 @@ SColorf GetPlayerColor(int player_id)
SColorf color_rgb = { 0,0,0,1 }; SColorf color_rgb = { 0,0,0,1 };
col.Saturation = col.Saturation * (1.0F / (floor(player_id / 4) + 1) ); col.Saturation = col.Saturation * (1.0f / (floorf(float(player_id / 4)) + 1) );
col.toRGB(color_rgb); col.toRGB(color_rgb);
return color_rgb; return color_rgb;
} }
@ -1161,9 +1161,9 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget,
SColorf color_rgb = GetPlayerColor(i); SColorf color_rgb = GetPlayerColor(i);
parentRibbonWidget->m_skin_r = color_rgb.r * 255.0F; parentRibbonWidget->m_skin_r = short(color_rgb.r * 255.0f);
parentRibbonWidget->m_skin_g = color_rgb.g * 255.0F; parentRibbonWidget->m_skin_g = short(color_rgb.g * 255.0f);
parentRibbonWidget->m_skin_b = color_rgb.b * 255.0F; parentRibbonWidget->m_skin_b = short(color_rgb.b * 255.0f);
if (nPlayersOnThisItem > 0) if (nPlayersOnThisItem > 0)
{ {
@ -1270,9 +1270,9 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
{ {
params=&SkinConfig::m_render_params["spinner::neutral"]; params=&SkinConfig::m_render_params["spinner::neutral"];
} }
widget->m_skin_r = color_rgb.r * 255.0f; widget->m_skin_r = short(color_rgb.r * 255.0f);
widget->m_skin_g = color_rgb.g * 255.0f; widget->m_skin_g = short(color_rgb.g * 255.0f);
widget->m_skin_b = color_rgb.b * 255.0f; widget->m_skin_b = short(color_rgb.b * 255.0f);
for (int i = 1; i < MAX_PLAYER_COUNT + 1; i++) for (int i = 1; i < MAX_PLAYER_COUNT + 1; i++)
{ {

View File

@ -290,14 +290,14 @@ void InputManager::handleStaticAction(int key, int value)
case IRR_KEY_F11: case IRR_KEY_F11:
if(value && shift_is_pressed && world && RewindManager::isEnabled()) if(value && shift_is_pressed && world && RewindManager::isEnabled())
{ {
printf("Enter rewind to time:"); printf("Enter rewind to time in ticks:");
char s[256]; char s[256];
fgets(s, 256, stdin); fgets(s, 256, stdin);
float t; int t;
StringUtils::fromString(s,t); StringUtils::fromString(s,t);
RewindManager::get()->rewindTo(t); RewindManager::get()->rewindTo(t);
Log::info("Rewind", "Rewinding from %f to %f", Log::info("Rewind", "Rewinding from %d to %d",
world->getTime(), t); world->getTimeTicks(), t);
} }
break; break;

View File

@ -49,7 +49,7 @@ Attachment::Attachment(AbstractKart* kart)
: EventRewinder() : EventRewinder()
{ {
m_type = ATTACH_NOTHING; m_type = ATTACH_NOTHING;
m_time_left = 0.0; m_ticks_left = 0;
m_plugin = NULL; m_plugin = NULL;
m_kart = kart; m_kart = kart;
m_previous_owner = NULL; m_previous_owner = NULL;
@ -103,7 +103,7 @@ Attachment::~Attachment()
* can be passed back to the previous owner). NULL if a no * can be passed back to the previous owner). NULL if a no
* previous owner exists. * previous owner exists.
*/ */
void Attachment::set(AttachmentType type, float time, void Attachment::set(AttachmentType type, int ticks,
AbstractKart *current_kart) AbstractKart *current_kart)
{ {
bool was_bomb = (m_type == ATTACH_BOMB); bool was_bomb = (m_type == ATTACH_BOMB);
@ -162,7 +162,7 @@ void Attachment::set(AttachmentType type, float time,
m_node->setScale(core::vector3df(m_node_scale,m_node_scale,m_node_scale)); m_node->setScale(core::vector3df(m_node_scale,m_node_scale,m_node_scale));
m_type = type; m_type = type;
m_time_left = time; m_ticks_left = ticks;
m_previous_owner = current_kart; m_previous_owner = current_kart;
m_node->setRotation(core::vector3df(0, 0, 0)); m_node->setRotation(core::vector3df(0, 0, 0));
@ -188,7 +188,7 @@ void Attachment::set(AttachmentType type, float time,
speed_mult = 1.0f + (f * (temp_mult - 1.0f)); speed_mult = 1.0f + (f * (temp_mult - 1.0f));
m_time_left = m_time_left * speed_mult; m_ticks_left = int(m_ticks_left * speed_mult);
if (UserConfigParams::m_particles_effects > 1) if (UserConfigParams::m_particles_effects > 1)
{ {
@ -230,7 +230,7 @@ void Attachment::clear()
m_type=ATTACH_NOTHING; m_type=ATTACH_NOTHING;
m_time_left=0.0; m_ticks_left = 0;
m_node->setVisible(false); m_node->setVisible(false);
m_node->setPosition(core::vector3df()); m_node->setPosition(core::vector3df());
m_node->setRotation(core::vector3df()); m_node->setRotation(core::vector3df());
@ -254,7 +254,7 @@ void Attachment::saveState(BareNetworkString *buffer) const
buffer->addUInt8(type); buffer->addUInt8(type);
if(m_type!=ATTACH_NOTHING) if(m_type!=ATTACH_NOTHING)
{ {
buffer->addFloat(m_time_left); buffer->addUInt32(m_ticks_left);
if(m_type==ATTACH_BOMB && m_previous_owner) if(m_type==ATTACH_BOMB && m_previous_owner)
buffer->addUInt8(m_previous_owner->getWorldKartId()); buffer->addUInt8(m_previous_owner->getWorldKartId());
// m_initial_speed is not saved, on restore state it will // m_initial_speed is not saved, on restore state it will
@ -284,13 +284,13 @@ void Attachment::rewindTo(BareNetworkString *buffer)
return; return;
} }
float time_left = buffer->getFloat(); int ticks_left = buffer->getUInt32();
// Attaching an object can be expensive (loading new models, ...) // Attaching an object can be expensive (loading new models, ...)
// so avoid doing this if there is no change in attachment type // so avoid doing this if there is no change in attachment type
if(new_type == m_type) if(new_type == m_type)
{ {
setTimeLeft(time_left); setTicksLeft(ticks_left);
return; return;
} }
@ -305,7 +305,7 @@ void Attachment::rewindTo(BareNetworkString *buffer)
{ {
m_previous_owner = NULL; m_previous_owner = NULL;
} }
set(new_type, time_left, m_previous_owner); set(new_type, ticks_left, m_previous_owner);
} // rewindTo } // rewindTo
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/** Called when going forwards in time during a rewind. /** Called when going forwards in time during a rewind.
@ -333,11 +333,11 @@ void Attachment::hitBanana(Item *item, int new_attachment)
if(m_type == ATTACH_BUBBLEGUM_SHIELD || if(m_type == ATTACH_BUBBLEGUM_SHIELD ||
m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD) m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD)
{ {
m_time_left = 0.0f; m_ticks_left = 0;
return; return;
} }
float leftover_time = 0.0f; int leftover_ticks = 0;
bool add_a_new_item = true; bool add_a_new_item = true;
@ -374,11 +374,11 @@ void Attachment::hitBanana(Item *item, int new_attachment)
// if the kart already has an anvil, attach a new anvil, // if the kart already has an anvil, attach a new anvil,
// and increase the overall time // and increase the overall time
new_attachment = 1; new_attachment = 1;
leftover_time = m_time_left; leftover_ticks = m_ticks_left;
break; break;
case ATTACH_PARACHUTE: case ATTACH_PARACHUTE:
new_attachment = 0; new_attachment = 0;
leftover_time = m_time_left; leftover_ticks = m_ticks_left;
break; break;
default: default:
// There is no attachment currently, but there will be one // There is no attachment currently, but there will be one
@ -399,7 +399,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
switch (new_attachment) switch (new_attachment)
{ {
case 0: case 0:
set(ATTACH_PARACHUTE, kp->getParachuteDuration() + leftover_time); set(ATTACH_PARACHUTE, kp->getParachuteDuration() + leftover_ticks);
m_initial_speed = m_kart->getSpeed(); m_initial_speed = m_kart->getSpeed();
// if going very slowly or backwards, // if going very slowly or backwards,
@ -407,7 +407,8 @@ void Attachment::hitBanana(Item *item, int new_attachment)
if(m_initial_speed <= 1.5) m_initial_speed = 1.5; if(m_initial_speed <= 1.5) m_initial_speed = 1.5;
break ; break ;
case 1: case 1:
set(ATTACH_ANVIL, kp->getAnvilDuration() + leftover_time); set(ATTACH_ANVIL, stk_config->time2Ticks(kp->getAnvilDuration())
+ leftover_ticks );
// if ( m_kart == m_kart[0] ) // if ( m_kart == m_kart[0] )
// sound -> playSfx ( SOUND_SHOOMF ) ; // sound -> playSfx ( SOUND_SHOOMF ) ;
// Reduce speed once (see description above), all other changes are // Reduce speed once (see description above), all other changes are
@ -416,10 +417,9 @@ void Attachment::hitBanana(Item *item, int new_attachment)
m_kart->updateWeight(); m_kart->updateWeight();
break ; break ;
case 2: case 2:
set( ATTACH_BOMB, stk_config->m_bomb_time+leftover_time); set( ATTACH_BOMB, stk_config->time2Ticks(stk_config->m_bomb_time)
+ leftover_ticks );
// if ( m_kart == m_kart[0] )
// sound -> playSfx ( SOUND_SHOOMF ) ;
break ; break ;
} // switch } // switch
} }
@ -446,8 +446,8 @@ void Attachment::handleCollisionWithKart(AbstractKart *other)
// If both karts have a bomb, explode them immediately: // If both karts have a bomb, explode them immediately:
if(attachment_other->getType()==Attachment::ATTACH_BOMB) if(attachment_other->getType()==Attachment::ATTACH_BOMB)
{ {
setTimeLeft(0.0f); setTicksLeft(0);
attachment_other->setTimeLeft(0.0f); attachment_other->setTicksLeft(0);
} }
else // only this kart has a bomb, move it to the other else // only this kart has a bomb, move it to the other
{ {
@ -455,9 +455,10 @@ void Attachment::handleCollisionWithKart(AbstractKart *other)
if (getPreviousOwner() != other || World::getWorld()->getNumKarts() <= 2) if (getPreviousOwner() != other || World::getWorld()->getNumKarts() <= 2)
{ {
// Don't move if this bomb was from other kart originally // Don't move if this bomb was from other kart originally
other->getAttachment()->set(ATTACH_BOMB, other->getAttachment()
getTimeLeft()+ ->set(ATTACH_BOMB,
stk_config->m_bomb_time_increase, getTicksLeft()+stk_config->time2Ticks(
stk_config->m_bomb_time_increase),
m_kart); m_kart);
other->playCustomSFX(SFXManager::CUSTOM_ATTACH); other->playCustomSFX(SFXManager::CUSTOM_ATTACH);
clear(); clear();
@ -473,8 +474,10 @@ void Attachment::handleCollisionWithKart(AbstractKart *other)
m_kart->decreaseShieldTime(); m_kart->decreaseShieldTime();
return; return;
} }
set(ATTACH_BOMB, other->getAttachment()->getTimeLeft()+ set(ATTACH_BOMB,
stk_config->m_bomb_time_increase, other); other->getAttachment()->getTicksLeft()+
stk_config->time2Ticks(stk_config->m_bomb_time_increase),
other);
other->getAttachment()->clear(); other->getAttachment()->clear();
m_kart->playCustomSFX(SFXManager::CUSTOM_ATTACH); m_kart->playCustomSFX(SFXManager::CUSTOM_ATTACH);
} }
@ -496,7 +499,7 @@ void Attachment::update(float dt)
if (m_type == ATTACH_BOMB && m_kart->getKartAnimation() != NULL) if (m_type == ATTACH_BOMB && m_kart->getKartAnimation() != NULL)
return; return;
m_time_left -=dt; m_ticks_left--; // dt always physics time step
bool is_shield = m_type == ATTACH_BUBBLEGUM_SHIELD || bool is_shield = m_type == ATTACH_BUBBLEGUM_SHIELD ||
@ -504,20 +507,23 @@ void Attachment::update(float dt)
float m_wanted_node_scale = is_shield float m_wanted_node_scale = is_shield
? std::max(1.0f, m_kart->getHighestPoint()*1.1f) ? std::max(1.0f, m_kart->getHighestPoint()*1.1f)
: 1.0f; : 1.0f;
int slow_flashes = 3; int slow_flashes = stk_config->time2Ticks(3.0f);
if (is_shield && m_time_left < slow_flashes) if (is_shield && m_ticks_left < slow_flashes)
{ {
int flashes_per_second = 4; int flashes_per_second = 4;
int divisor = 2; int ticks_per_flash = stk_config->time2Ticks(0.25f);
float fast_flashes = 0.5F; int fast_flashes = stk_config->time2Ticks(0.5f);
if (m_time_left < fast_flashes) if (m_ticks_left < fast_flashes)
{ {
flashes_per_second = 12; flashes_per_second = 12;
ticks_per_flash = stk_config->time2Ticks(1.0f/12);
} }
int mod = (int)(m_time_left * flashes_per_second * 2) % divisor; //int divisor = 2;
m_node->setVisible(2*mod >= divisor); //int mod = (int)(m_ticks_left * flashes_per_second * 2) % divisor;
int mod = m_ticks_left % ticks_per_flash;
m_node->setVisible(mod > ticks_per_flash);
} }
if (m_node_scale < m_wanted_node_scale) if (m_node_scale < m_wanted_node_scale)
@ -558,7 +564,7 @@ void Attachment::update(float dt)
f * (kp->getParachuteUboundFraction() f * (kp->getParachuteUboundFraction()
- kp->getParachuteLboundFraction()))) - kp->getParachuteLboundFraction())))
{ {
m_time_left = -1; m_ticks_left = -1;
} }
} }
break; break;
@ -576,18 +582,19 @@ void Attachment::update(float dt)
assert(false); assert(false);
break; break;
case ATTACH_BOMB: case ATTACH_BOMB:
{
if (m_bomb_sound) m_bomb_sound->setPosition(m_kart->getXYZ()); if (m_bomb_sound) m_bomb_sound->setPosition(m_kart->getXYZ());
// Mesh animation frames are 1 to 61 frames (60 steps) // Mesh animation frames are 1 to 61 frames (60 steps)
// The idea is change second by second, counterclockwise 60 to 0 secs // The idea is change second by second, counterclockwise 60 to 0 secs
// If longer times needed, it should be a surprise "oh! bomb activated!" // If longer times needed, it should be a surprise "oh! bomb activated!"
if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame()-1)) float time_left = stk_config->ticks2Time(m_ticks_left);
if (time_left <= (m_node->getEndFrame() - m_node->getStartFrame() - 1))
{ {
m_node->setCurrentFrame(m_node->getEndFrame() m_node->setCurrentFrame(m_node->getEndFrame()
- m_node->getStartFrame()-1-m_time_left); - m_node->getStartFrame() - 1 - time_left);
} }
if(m_time_left<=0.0) if (m_ticks_left <= 0)
{ {
HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion",
"explosion_bomb.xml"); "explosion_bomb.xml");
@ -603,11 +610,12 @@ void Attachment::update(float dt)
} }
} }
break; break;
}
case ATTACH_BUBBLEGUM_SHIELD: case ATTACH_BUBBLEGUM_SHIELD:
case ATTACH_NOLOK_BUBBLEGUM_SHIELD: case ATTACH_NOLOK_BUBBLEGUM_SHIELD:
if (m_time_left < 0) if (m_ticks_left < 0)
{ {
m_time_left = 0.0f; m_ticks_left = 0;
if (m_bubble_explode_sound) m_bubble_explode_sound->deleteSFX(); if (m_bubble_explode_sound) m_bubble_explode_sound->deleteSFX();
m_bubble_explode_sound = m_bubble_explode_sound =
SFXManager::get()->createSoundSource("bubblegum_explode"); SFXManager::get()->createSoundSource("bubblegum_explode");
@ -638,7 +646,7 @@ void Attachment::update(float dt)
} // switch } // switch
// Detach attachment if its time is up. // Detach attachment if its time is up.
if ( m_time_left <= 0.0f) if ( m_ticks_left <= 0)
clear(); clear();
} // update } // update

View File

@ -78,7 +78,7 @@ private:
AbstractKart *m_kart; AbstractKart *m_kart;
/** Time left till attachment expires. */ /** Time left till attachment expires. */
float m_time_left; int m_ticks_left;
/** For parachutes only. */ /** For parachutes only. */
float m_initial_speed; float m_initial_speed;
@ -114,7 +114,7 @@ public:
void hitBanana(Item *item, int new_attachment=-1); void hitBanana(Item *item, int new_attachment=-1);
void update (float dt); void update (float dt);
void handleCollisionWithKart(AbstractKart *other); void handleCollisionWithKart(AbstractKart *other);
void set (AttachmentType type, float time, void set (AttachmentType type, int ticks,
AbstractKart *previous_kart=NULL); AbstractKart *previous_kart=NULL);
virtual void rewind(BareNetworkString *buffer); virtual void rewind(BareNetworkString *buffer);
void rewindTo(BareNetworkString *buffer); void rewindTo(BareNetworkString *buffer);
@ -122,16 +122,17 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets the type of the attachment, but keeps the old time left value. */ /** Sets the type of the attachment, but keeps the old time left value. */
void set (AttachmentType type) { set(type, m_time_left); } void set (AttachmentType type) { set(type, m_ticks_left); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the type of this attachment. */ /** Returns the type of this attachment. */
AttachmentType getType() const { return m_type; } AttachmentType getType() const { return m_type; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns how much time is left before this attachment is removed. */ /** Returns how much time (in ticks) is left before this attachment is
float getTimeLeft() const { return m_time_left; } * removed. */
int getTicksLeft() const { return m_ticks_left; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets how long this attachment will remain attached. */ /** Sets how long this attachment will remain attached. */
void setTimeLeft(float t){ m_time_left = t; } void setTicksLeft(int t){ m_ticks_left = t; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the previous owner of this attachment, used in bombs that /** Returns the previous owner of this attachment, used in bombs that
* are being passed between karts. */ * are being passed between karts. */

View File

@ -267,7 +267,8 @@ void Powerup::use()
case PowerupManager::POWERUP_SWATTER: case PowerupManager::POWERUP_SWATTER:
m_kart->getAttachment() m_kart->getAttachment()
->set(Attachment::ATTACH_SWATTER, kp->getSwatterDuration()); ->set(Attachment::ATTACH_SWATTER,
stk_config->time2Ticks(kp->getSwatterDuration()));
break; break;
case PowerupManager::POWERUP_BUBBLEGUM: case PowerupManager::POWERUP_BUBBLEGUM:
@ -302,26 +303,35 @@ void Powerup::use()
{ {
if (m_kart->getIdent() == "nolok") if (m_kart->getIdent() == "nolok")
{ {
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD, m_kart->getAttachment()
kp->getBubblegumShieldDuration()); ->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
stk_config->
time2Ticks(kp->getBubblegumShieldDuration()));
} }
else else
{ {
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD, m_kart->getAttachment()
kp->getBubblegumShieldDuration()); ->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
stk_config->
time2Ticks(kp->getBubblegumShieldDuration()));
} }
} }
else // using a bubble gum while still having a shield else // using a bubble gum while still having a shield
{ {
if (m_kart->getIdent() == "nolok") if (m_kart->getIdent() == "nolok")
{ {
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD, m_kart->getAttachment()
kp->getBubblegumShieldDuration() + m_kart->getShieldTime()); ->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
stk_config->
time2Ticks(kp->getBubblegumShieldDuration()));
} }
else else
{ {
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD, m_kart->getAttachment()
kp->getBubblegumShieldDuration() + m_kart->getShieldTime()); ->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
stk_config->
time2Ticks(kp->getBubblegumShieldDuration()
+ m_kart->getShieldTime() ) );
} }
} }
@ -350,7 +360,8 @@ void Powerup::use()
if(kart->getPosition() == 1) if(kart->getPosition() == 1)
{ {
kart->getAttachment()->set(Attachment::ATTACH_ANVIL, kart->getAttachment()->set(Attachment::ATTACH_ANVIL,
kp->getAnvilDuration()); stk_config->
time2Ticks(kp->getAnvilDuration()) );
kart->updateWeight(); kart->updateWeight();
kart->adjustSpeed(kp->getAnvilSpeedFactor() * 0.5f); kart->adjustSpeed(kp->getAnvilSpeedFactor() * 0.5f);
@ -397,14 +408,17 @@ void Powerup::use()
{ {
float rank_factor; float rank_factor;
rank_factor = (float)(kart->getPosition() - 1) / (float)(m_kart->getPosition() - 2); rank_factor = (float)(kart->getPosition() - 1)
/ (float)(m_kart->getPosition() - 2);
position_factor = 1.0f - rank_factor; position_factor = 1.0f - rank_factor;
} }
rank_mult = 1 + (position_factor * (kp->getParachuteDurationRankMult() - 1)); rank_mult = 1 + (position_factor *
(kp->getParachuteDurationRankMult() - 1));
kart->getAttachment()->set(Attachment::ATTACH_PARACHUTE, kart->getAttachment()
(kp->getParachuteDurationOther() * rank_mult)); ->set(Attachment::ATTACH_PARACHUTE,
int(kp->getParachuteDurationOther()*rank_mult) );
if(kart->getController()->isLocalPlayerController()) if(kart->getController()->isLocalPlayerController())
player_kart = kart; player_kart = kart;
@ -464,7 +478,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
// Check if rubber ball is the current power up held by the kart. If so, // Check if rubber ball is the current power up held by the kart. If so,
// reset the bBallCollectTime to 0 before giving new powerup. // reset the bBallCollectTime to 0 before giving new powerup.
if(m_type == PowerupManager::POWERUP_RUBBERBALL) if(m_type == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTime(0); powerup_manager->setBallCollectTicks(0);
// Check if two bouncing balls are collected less than getRubberBallTimer() // Check if two bouncing balls are collected less than getRubberBallTimer()
//seconds apart. If yes, then call getRandomPowerup again. If no, then break. //seconds apart. If yes, then call getRandomPowerup again. If no, then break.
@ -474,8 +488,8 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
{ {
new_powerup = powerup_manager->getRandomPowerup(position, &n); new_powerup = powerup_manager->getRandomPowerup(position, &n);
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL || if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
( World::getWorld()->getTimeSinceStart() - powerup_manager->getBallCollectTime()) > ( World::getWorld()->getTicksSinceStart() - powerup_manager->getBallCollectTicks()) >
RubberBall::getTimeBetweenRubberBalls() ) RubberBall::getTicksBetweenRubberBalls() )
break; break;
} }
} }
@ -486,7 +500,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
} }
if(new_powerup == PowerupManager::POWERUP_RUBBERBALL) if(new_powerup == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTime(World::getWorld()->getTime()); powerup_manager->setBallCollectTicks(World::getWorld()->getTimeTicks());
// Always add a new powerup in ITEM_MODE_NEW (or if the kart // Always add a new powerup in ITEM_MODE_NEW (or if the kart
// doesn't have a powerup atm). // doesn't have a powerup atm).

View File

@ -113,7 +113,7 @@ private:
float m_all_max_turn_angle[POWERUP_MAX]; float m_all_max_turn_angle[POWERUP_MAX];
/** Last time the bouncing ball was collected */ /** Last time the bouncing ball was collected */
float m_rubber_ball_collect_time; int m_rubber_ball_collect_ticks;
public: public:
/** The mesh for each model (if the powerup has a model), e.g. a switch /** The mesh for each model (if the powerup has a model), e.g. a switch
@ -165,8 +165,8 @@ public:
float getMaxTurnAngle (int type) const {return m_all_max_turn_angle[type];} float getMaxTurnAngle (int type) const {return m_all_max_turn_angle[type];}
const btVector3& const btVector3&
getExtend (int type) const {return m_all_extends[type];} getExtend (int type) const {return m_all_extends[type];}
float getBallCollectTime() const {return m_rubber_ball_collect_time;} int getBallCollectTicks() const {return m_rubber_ball_collect_ticks;}
void setBallCollectTime(float time) {m_rubber_ball_collect_time=time;} void setBallCollectTicks(int ticks) {m_rubber_ball_collect_ticks=ticks;}
}; };

View File

@ -47,7 +47,7 @@ float RubberBall::m_st_max_height_difference;
float RubberBall::m_st_fast_ping_distance; float RubberBall::m_st_fast_ping_distance;
float RubberBall::m_st_early_target_factor; float RubberBall::m_st_early_target_factor;
int RubberBall::m_next_id = 0; int RubberBall::m_next_id = 0;
float RubberBall::m_time_between_balls; int RubberBall::m_ticks_between_balls;
// Debug only, so that we can get a feel on how well balls are aiming etc. // Debug only, so that we can get a feel on how well balls are aiming etc.
@ -272,7 +272,7 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
m_st_max_height_difference = 10.0f; m_st_max_height_difference = 10.0f;
m_st_fast_ping_distance = 50.0f; m_st_fast_ping_distance = 50.0f;
m_st_early_target_factor = 1.0f; m_st_early_target_factor = 1.0f;
m_time_between_balls = 15; m_ticks_between_balls = stk_config->time2Ticks(15.0f);
if(!node.get("interval", &m_st_interval)) if(!node.get("interval", &m_st_interval))
Log::warn("powerup", "No interval specified for rubber ball."); Log::warn("powerup", "No interval specified for rubber ball.");
@ -306,9 +306,10 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
if(!node.get("early-target-factor", &m_st_early_target_factor)) if(!node.get("early-target-factor", &m_st_early_target_factor))
Log::warn("powerup", Log::warn("powerup",
"No early-target-factor specified for rubber ball."); "No early-target-factor specified for rubber ball.");
if(!node.get("time-between-balls", &m_time_between_balls)) if(!node.get("time-between-balls", &m_ticks_between_balls))
Log::warn("powerup", Log::warn("powerup",
"No time-between-balls specified for rubber ball."); "No time-between-balls specified for rubber ball.");
m_ticks_between_balls = stk_config->time2Ticks(float(m_ticks_between_balls));
Flyable::init(node, rubberball, PowerupManager::POWERUP_RUBBERBALL); Flyable::init(node, rubberball, PowerupManager::POWERUP_RUBBERBALL);
} // init } // init

View File

@ -84,7 +84,7 @@ private:
/** Timer before another rubber ball can be picked up. This is to ensure /** Timer before another rubber ball can be picked up. This is to ensure
* that there are not too many rubber balls on the track in races with many * that there are not too many rubber balls on the track in races with many
* karts. */ * karts. */
static float m_time_between_balls; static int m_ticks_between_balls;
/** This factor is used to influence how much the rubber ball should aim /** This factor is used to influence how much the rubber ball should aim
* at its target early. It used the 'distance to center of track' of its * at its target early. It used the 'distance to center of track' of its
@ -205,7 +205,10 @@ public:
virtual bool updateAndDelete(float dt); virtual bool updateAndDelete(float dt);
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL); virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
virtual void setAnimation(AbstractKartAnimation *animation); virtual void setAnimation(AbstractKartAnimation *animation);
static float getTimeBetweenRubberBalls() {return m_time_between_balls;} // ------------------------------------------------------------------------
/** Returns time (in ticks) between rubberballs, to avoid that in games
* with many karts too many rubber balls are in play at the same time. */
static int getTicksBetweenRubberBalls() { return m_ticks_between_balls; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** This object does not create an explosion, all affects on /** This object does not create an explosion, all affects on
* karts are handled by this hit() function. */ * karts are handled by this hit() function. */

View File

@ -18,6 +18,7 @@
#include "karts/abstract_characteristic.hpp" #include "karts/abstract_characteristic.hpp"
#include "config/stk_config.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/interpolation_array.hpp" #include "utils/interpolation_array.hpp"
@ -931,7 +932,7 @@ float AbstractCharacteristic::getParachuteFriction() const
} // getParachuteFriction } // getParachuteFriction
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float AbstractCharacteristic::getParachuteDuration() const int AbstractCharacteristic::getParachuteDuration() const
{ {
float result; float result;
bool is_set = false; bool is_set = false;
@ -939,11 +940,11 @@ float AbstractCharacteristic::getParachuteDuration() const
if (!is_set) if (!is_set)
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
getName(PARACHUTE_DURATION).c_str()); getName(PARACHUTE_DURATION).c_str());
return result; return stk_config->time2Ticks(result);
} // getParachuteDuration } // getParachuteDuration
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float AbstractCharacteristic::getParachuteDurationOther() const int AbstractCharacteristic::getParachuteDurationOther() const
{ {
float result; float result;
bool is_set = false; bool is_set = false;
@ -951,7 +952,7 @@ float AbstractCharacteristic::getParachuteDurationOther() const
if (!is_set) if (!is_set)
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
getName(PARACHUTE_DURATION_OTHER).c_str()); getName(PARACHUTE_DURATION_OTHER).c_str());
return result; return stk_config->time2Ticks(result);
} // getParachuteDurationOther } // getParachuteDurationOther
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -305,8 +305,8 @@ public:
float getAnvilSpeedFactor() const; float getAnvilSpeedFactor() const;
float getParachuteFriction() const; float getParachuteFriction() const;
float getParachuteDuration() const; int getParachuteDuration() const;
float getParachuteDurationOther() const; int getParachuteDurationOther() const;
float getParachuteDurationRankMult() const; float getParachuteDurationRankMult() const;
float getParachuteDurationSpeedMult() const; float getParachuteDurationSpeedMult() const;
float getParachuteLboundFraction() const; float getParachuteLboundFraction() const;

View File

@ -48,7 +48,7 @@ AIBaseController::AIBaseController(AbstractKart *kart)
void AIBaseController::reset() void AIBaseController::reset()
{ {
m_stuck = false; m_stuck = false;
m_collision_times.clear(); m_collision_ticks.clear();
} // reset } // reset
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -237,12 +237,12 @@ void AIBaseController::crashed(const Material *m)
// the track again if it is stuck (i.e. time for the push back plus // the track again if it is stuck (i.e. time for the push back plus
// time for the AI to accelerate and hit the terrain again). // time for the AI to accelerate and hit the terrain again).
const unsigned int NUM_COLLISION = 3; const unsigned int NUM_COLLISION = 3;
const float COLLISION_TIME = 1.5f; const int COLLISION_TICKS = stk_config->time2Ticks(3.0f);
float time = World::getWorld()->getTimeSinceStart(); int ticks = World::getWorld()->getTicksSinceStart();
if(m_collision_times.size()==0) if(m_collision_ticks.size()==0)
{ {
m_collision_times.push_back(time); m_collision_ticks.push_back(ticks);
return; return;
} }
@ -252,23 +252,24 @@ void AIBaseController::crashed(const Material *m)
// collisions to happen). The time of 0.2 seconds was experimentally // collisions to happen). The time of 0.2 seconds was experimentally
// found, typically it takes 0.5 seconds for a kart to be pushed back // found, typically it takes 0.5 seconds for a kart to be pushed back
// from the terrain and accelerate to hit the same terrain again. // from the terrain and accelerate to hit the same terrain again.
if(time - m_collision_times.back() < 0.2f) if(5 * (ticks - m_collision_ticks.back()) < stk_config->time2Ticks(1.0f))
return; return;
// Remove all outdated entries, i.e. entries that are older than the // Remove all outdated entries, i.e. entries that are older than the
// collision time plus 1 second. Older entries must be deleted, // collision time plus 1 second. Older entries must be deleted,
// otherwise a collision that happened (say) 10 seconds ago could // otherwise a collision that happened (say) 10 seconds ago could
// contribute to a stuck condition. // contribute to a stuck condition.
while(m_collision_times.size()>0 && while(m_collision_ticks.size()>0 &&
time - m_collision_times[0] > 1.0f+COLLISION_TIME) ticks - m_collision_ticks[0] > stk_config->time2Ticks(1.0f)
m_collision_times.erase(m_collision_times.begin()); + COLLISION_TICKS )
m_collision_ticks.erase(m_collision_ticks.begin());
m_collision_times.push_back(time); m_collision_ticks.push_back(ticks);
// Now detect if there are enough collision records in the // Now detect if there are enough collision records in the
// specified time interval. // specified time interval.
if(time - m_collision_times.front() > COLLISION_TIME if(ticks - m_collision_ticks.front() > COLLISION_TICKS &&
&& m_collision_times.size()>=NUM_COLLISION) m_collision_ticks.size()>=NUM_COLLISION )
{ {
// We can't call m_kart->forceRescue here, since crased() is // We can't call m_kart->forceRescue here, since crased() is
// called during physics processing, and forceRescue() removes the // called during physics processing, and forceRescue() removes the

View File

@ -36,7 +36,7 @@ private:
/** Stores the last N times when a collision happened. This is used /** Stores the last N times when a collision happened. This is used
* to detect when the AI is stuck, i.e. N collisions happened in * to detect when the AI is stuck, i.e. N collisions happened in
* a certain period of time. */ * a certain period of time. */
std::vector<float> m_collision_times; std::vector<int> m_collision_ticks;
/** A flag that is set during the physics processing to indicate that /** A flag that is set during the physics processing to indicate that
* this kart is stuck and needs to be rescued. */ * this kart is stuck and needs to be rescued. */

View File

@ -357,7 +357,7 @@ void Kart::reset()
m_has_started = false; m_has_started = false;
m_bounce_back_time = 0.0f; m_bounce_back_time = 0.0f;
m_brake_time = 0.0f; m_brake_time = 0.0f;
m_time_last_crash = 0.0f; m_ticks_last_crash = 0;
m_speed = 0.0f; m_speed = 0.0f;
m_smoothed_speed = 0.0f; m_smoothed_speed = 0.0f;
m_current_lean = 0.0f; m_current_lean = 0.0f;
@ -1051,7 +1051,7 @@ void Kart::collectedItem(Item *item, int add_info)
*/ */
float Kart::getStartupBoost() const float Kart::getStartupBoost() const
{ {
float t = World::getWorld()->getTimeSinceStart(); float t = stk_config->ticks2Time(World::getWorld()->getTicksSinceStart());
std::vector<float> startup_times = m_kart_properties->getStartupTime(); std::vector<float> startup_times = m_kart_properties->getStartupTime();
for (unsigned int i = 0; i < startup_times.size(); i++) for (unsigned int i = 0; i < startup_times.size(); i++)
{ {
@ -1110,16 +1110,16 @@ bool Kart::isNearGround() const
} // isNearGround } // isNearGround
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /** Enables a kart shield protection for a certain amount of time.
* Enables a kart shield protection for a certain amount of time.
*/ */
void Kart::setShieldTime(float t) void Kart::setShieldTime(float t)
{ {
if(isShielded()) if(isShielded())
{ {
getAttachment()->setTimeLeft(t); getAttachment()->setTicksLeft(stk_config->time2Ticks(t));
}
} }
} // setShieldTime
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns true if the kart is protected by a shield. * Returns true if the kart is protected by a shield.
@ -1145,7 +1145,7 @@ bool Kart::isShielded() const
float Kart::getShieldTime() const float Kart::getShieldTime() const
{ {
if (isShielded()) if (isShielded())
return getAttachment()->getTimeLeft(); return stk_config->ticks2Time(getAttachment()->getTicksLeft());
else else
return 0.0f; return 0.0f;
} // getShieldTime } // getShieldTime
@ -1159,7 +1159,7 @@ void Kart::decreaseShieldTime()
{ {
if (isShielded()) if (isShielded())
{ {
getAttachment()->setTimeLeft(0.0f); getAttachment()->setTicksLeft(0);
} }
} // decreaseShieldTime } // decreaseShieldTime
@ -2193,9 +2193,10 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
*/ */
void Kart::playCrashSFX(const Material* m, AbstractKart *k) void Kart::playCrashSFX(const Material* m, AbstractKart *k)
{ {
if(World::getWorld()->getTimeSinceStart()-m_time_last_crash < 0.5f) return; int ticks_since_start = World::getWorld()->getTicksSinceStart();
if(ticks_since_start-m_ticks_last_crash < 0.5f) return;
m_time_last_crash = World::getWorld()->getTimeSinceStart(); m_ticks_last_crash = ticks_since_start;
// After a collision disable the engine for a short time so that karts // After a collision disable the engine for a short time so that karts
// can 'bounce back' a bit (without this the engine force will prevent // can 'bounce back' a bit (without this the engine force will prevent
// karts from bouncing back, they will instead stuck towards the obstable). // karts from bouncing back, they will instead stuck towards the obstable).

View File

@ -223,7 +223,7 @@ protected:
SFXBuffer *m_crash_sounds[CRASH_SOUND_COUNT]; SFXBuffer *m_crash_sounds[CRASH_SOUND_COUNT];
SFXBuffer *m_goo_sound; SFXBuffer *m_goo_sound;
SFXBuffer *m_boing_sound; SFXBuffer *m_boing_sound;
float m_time_last_crash; int m_ticks_last_crash;
RaceManager::KartType m_type; RaceManager::KartType m_type;
/** To prevent using nitro in too short bursts */ /** To prevent using nitro in too short bursts */

View File

@ -773,13 +773,13 @@ float KartProperties::getParachuteFriction() const
} // getParachuteFriction } // getParachuteFriction
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float KartProperties::getParachuteDuration() const int KartProperties::getParachuteDuration() const
{ {
return m_cached_characteristic->getParachuteDuration(); return m_cached_characteristic->getParachuteDuration();
} // getParachuteDuration } // getParachuteDuration
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float KartProperties::getParachuteDurationOther() const int KartProperties::getParachuteDurationOther() const
{ {
return m_cached_characteristic->getParachuteDurationOther(); return m_cached_characteristic->getParachuteDurationOther();
} // getParachuteDurationOther } // getParachuteDurationOther

View File

@ -427,8 +427,8 @@ public:
float getAnvilSpeedFactor() const; float getAnvilSpeedFactor() const;
float getParachuteFriction() const; float getParachuteFriction() const;
float getParachuteDuration() const; int getParachuteDuration() const;
float getParachuteDurationOther() const; int getParachuteDurationOther() const;
float getParachuteDurationRankMult() const; float getParachuteDurationRankMult() const;
float getParachuteDurationSpeedMult() const; float getParachuteDurationSpeedMult() const;
float getParachuteLboundFraction() const; float getParachuteLboundFraction() const;

View File

@ -72,10 +72,12 @@ void Moveable::addError(const Vec3& pos_error,
const btQuaternion &rot_error) const btQuaternion &rot_error)
{ {
m_positional_error += pos_error; m_positional_error += pos_error;
#ifdef DEBUG_VISUAL_ERROR
Log::info("VisualError", "time %f addError %f %f %f size %f", Log::info("VisualError", "time %f addError %f %f %f size %f",
World::getWorld()->getTime(), World::getWorld()->getTime(),
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(), m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
m_positional_error.length()); m_positional_error.length());
#endif
m_rotational_error *= rot_error; m_rotational_error *= rot_error;
} // addError } // addError
@ -96,10 +98,12 @@ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
{ {
float error = m_positional_error.length(); float error = m_positional_error.length();
m_positional_error *= stk_config->m_positional_smoothing.get(error); m_positional_error *= stk_config->m_positional_smoothing.get(error);
#ifdef DEBUG_VISUAL_ERROR
Log::info("VisualError", "time %f reduceError %f %f %f size %f", Log::info("VisualError", "time %f reduceError %f %f %f size %f",
World::getWorld()->getTime(), World::getWorld()->getTime(),
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(), m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
m_positional_error.length()); m_positional_error.length());
#endif
} }
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error; Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;

View File

@ -273,8 +273,8 @@ void MainLoop::run()
PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7); PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7);
left_over_time += getLimitedDt(); left_over_time += getLimitedDt();
int num_steps = int(left_over_time * stk_config->m_physics_fps); int num_steps = stk_config->time2Ticks(left_over_time);
float dt = 1.0f / stk_config->m_physics_fps; float dt = stk_config->ticks2Time(1);
left_over_time -= num_steps * dt ; left_over_time -= num_steps * dt ;
if (STKHost::existHost() && if (STKHost::existHost() &&
@ -309,7 +309,7 @@ void MainLoop::run()
if (World::getWorld() && RewindManager::get()->isEnabled()) if (World::getWorld() && RewindManager::get()->isEnabled())
{ {
RewindManager::get() RewindManager::get()
->addNextTimeStep(World::getWorld()->getTime(), dt); ->addNextTimeStep(World::getWorld()->getTimeTicks(), dt);
} }
if (!m_abort) if (!m_abort)
@ -349,7 +349,7 @@ void MainLoop::run()
if (World::getWorld() && RewindManager::get()->isEnabled() && i>0) if (World::getWorld() && RewindManager::get()->isEnabled() && i>0)
{ {
RewindManager::get() RewindManager::get()
->addNextTimeStep(World::getWorld()->getTime(), dt); ->addNextTimeStep(World::getWorld()->getTimeTicks(), dt);
} }
// Enable last substep in last iteration // Enable last substep in last iteration

View File

@ -38,6 +38,7 @@
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
#include <climits>
#include <iostream> #include <iostream>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -49,7 +50,7 @@ LinearWorld::LinearWorld() : WorldWithRank()
m_last_lap_sfx = SFXManager::get()->createSoundSource("last_lap_fanfare"); m_last_lap_sfx = SFXManager::get()->createSoundSource("last_lap_fanfare");
m_last_lap_sfx_played = false; m_last_lap_sfx_played = false;
m_last_lap_sfx_playing = false; m_last_lap_sfx_playing = false;
m_fastest_lap = 9999999.9f; m_fastest_lap_ticks = INT_MAX;
} // LinearWorld } // LinearWorld
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -89,6 +90,7 @@ void LinearWorld::reset()
WorldWithRank::reset(); WorldWithRank::reset();
m_last_lap_sfx_played = false; m_last_lap_sfx_played = false;
m_last_lap_sfx_playing = false; m_last_lap_sfx_playing = false;
m_fastest_lap_ticks = INT_MAX;
const unsigned int kart_amount = (unsigned int) m_karts.size(); const unsigned int kart_amount = (unsigned int) m_karts.size();
for(unsigned int i=0; i<kart_amount; i++) for(unsigned int i=0; i<kart_amount; i++)
@ -274,7 +276,7 @@ void LinearWorld::newLap(unsigned int kart_index)
if(kart_info.m_race_lap+1 <= lap_count) if(kart_info.m_race_lap+1 <= lap_count)
{ {
assert(kart->getWorldKartId()==kart_index); assert(kart->getWorldKartId()==kart_index);
kart_info.m_time_at_last_lap=getTime(); kart_info.m_ticks_at_last_lap=getTimeTicks();
kart_info.m_race_lap++; kart_info.m_race_lap++;
m_kart_info[kart_index].m_overall_distance = m_kart_info[kart_index].m_overall_distance =
m_kart_info[kart_index].m_race_lap m_kart_info[kart_index].m_race_lap
@ -345,23 +347,23 @@ void LinearWorld::newLap(unsigned int kart_index)
{ {
kart->finishedRace(getTime()); kart->finishedRace(getTime());
} }
float time_per_lap; int ticks_per_lap;
if (kart_info.m_race_lap == 1) // just completed first lap if (kart_info.m_race_lap == 1) // just completed first lap
{ {
time_per_lap=getTime(); ticks_per_lap = getTimeTicks();
} }
else //completing subsequent laps else //completing subsequent laps
{ {
time_per_lap=getTime() - kart_info.m_lap_start_time; ticks_per_lap = getTimeTicks() - kart_info.m_lap_start_ticks;
} }
// if new fastest lap // if new fastest lap
if(time_per_lap < m_fastest_lap && raceHasLaps() && if(ticks_per_lap < m_fastest_lap_ticks && raceHasLaps() &&
kart_info.m_race_lap>0 ) kart_info.m_race_lap>0 )
{ {
m_fastest_lap = time_per_lap; m_fastest_lap_ticks = ticks_per_lap;
std::string s = StringUtils::timeToString(time_per_lap); std::string s = StringUtils::ticksTimeToString(ticks_per_lap);
// Store the temporary string because clang would mess this up // Store the temporary string because clang would mess this up
// (remove the stringw before the wchar_t* is used). // (remove the stringw before the wchar_t* is used).
@ -379,7 +381,7 @@ void LinearWorld::newLap(unsigned int kart_index)
} // end if new fastest lap } // end if new fastest lap
kart_info.m_lap_start_time = getTime(); kart_info.m_lap_start_ticks = getTimeTicks();
kart->getController()->newLap(kart_info.m_race_lap); kart->getController()->newLap(kart_info.m_race_lap);
} // newLap } // newLap
@ -422,18 +424,18 @@ float LinearWorld::getEstimatedFinishTime(const int kart_id) const
} // getEstimatedFinishTime } // getEstimatedFinishTime
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float LinearWorld::getTimeAtLapForKart(const int kart_id) const int LinearWorld::getTicksAtLapForKart(const int kart_id) const
{ {
assert(kart_id < (int)m_kart_info.size()); assert(kart_id < (int)m_kart_info.size());
return m_kart_info[kart_id].m_time_at_last_lap; return m_kart_info[kart_id].m_ticks_at_last_lap;
} // getTimeAtLapForKart } // getTicksAtLapForKart
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void LinearWorld::getKartsDisplayInfo( void LinearWorld::getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{ {
int laps_of_leader = -1; int laps_of_leader = -1;
float time_of_leader = -1; int ticks_of_leader = INT_MAX;
// Find the best time for the lap. We can't simply use // Find the best time for the lap. We can't simply use
// the time of the kart at position 1, since the kart // the time of the kart at position 1, since the kart
// might have been overtaken by now // might have been overtaken by now
@ -448,7 +450,7 @@ void LinearWorld::getKartsDisplayInfo(
rank_info.lap = -1; rank_info.lap = -1;
if(kart->isEliminated()) continue; if(kart->isEliminated()) continue;
const float lap_time = getTimeAtLapForKart(kart->getWorldKartId()); const int lap_ticks = getTicksAtLapForKart(kart->getWorldKartId());
const int current_lap = getLapForKart( kart->getWorldKartId() ); const int current_lap = getLapForKart( kart->getWorldKartId() );
rank_info.lap = current_lap; rank_info.lap = current_lap;
@ -457,11 +459,11 @@ void LinearWorld::getKartsDisplayInfo(
// more laps than current leader --> new leader and // more laps than current leader --> new leader and
// new time computation // new time computation
laps_of_leader = current_lap; laps_of_leader = current_lap;
time_of_leader = lap_time; ticks_of_leader = lap_ticks;
} else if(current_lap == laps_of_leader) } else if(current_lap == laps_of_leader)
{ {
// Same number of laps as leader: use fastest time // Same number of laps as leader: use fastest time
time_of_leader=std::min(time_of_leader,lap_time); ticks_of_leader=std::min(ticks_of_leader,lap_ticks);
} }
} }
@ -476,24 +478,24 @@ void LinearWorld::getKartsDisplayInfo(
// Don't compare times when crossing the start line first // Don't compare times when crossing the start line first
if(laps_of_leader>0 && if(laps_of_leader>0 &&
(getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f || (getTimeTicks() - getTicksAtLapForKart(kart->getWorldKartId())<5||
rank_info.lap != laps_of_leader) && rank_info.lap != laps_of_leader) &&
raceHasLaps()) raceHasLaps())
{ // Display for 5 seconds { // Display for 5 seconds
std::string str; std::string str;
if(position == 1) if(position == 1)
{ {
str = " " + StringUtils::timeToString( str = " " + StringUtils::ticksTimeToString(
getTimeAtLapForKart(kart->getWorldKartId()) ); getTicksAtLapForKart(kart->getWorldKartId()) );
} }
else else
{ {
float timeBehind; int ticks_behind;
timeBehind = (kart_info.m_race_lap==laps_of_leader ticks_behind = (kart_info.m_race_lap==laps_of_leader
? getTimeAtLapForKart(kart->getWorldKartId()) ? getTicksAtLapForKart(kart->getWorldKartId())
: getTime()) : getTimeTicks())
- time_of_leader; - ticks_of_leader;
str = "+" + StringUtils::timeToString(timeBehind); str = "+" + StringUtils::ticksTimeToString(ticks_behind);
} }
rank_info.m_text = irr::core::stringw(str.c_str()); rank_info.m_text = irr::core::stringw(str.c_str());
} }

View File

@ -18,11 +18,12 @@
#ifndef HEADER_LINEAR_WORLD_HPP #ifndef HEADER_LINEAR_WORLD_HPP
#define HEADER_LINEAR_WORLD_HPP #define HEADER_LINEAR_WORLD_HPP
#include <vector>
#include "modes/world_with_rank.hpp" #include "modes/world_with_rank.hpp"
#include "utils/aligned_array.hpp" #include "utils/aligned_array.hpp"
#include <climits>
#include <vector>
class SFXBase; class SFXBase;
/* /*
@ -42,8 +43,8 @@ private:
bool m_last_lap_sfx_playing; bool m_last_lap_sfx_playing;
/** The fastest lap time. */ /** The fastest lap time, in ticks of physics dt. */
float m_fastest_lap; int m_fastest_lap_ticks;
/** The track length returned by Track::getLength() only covers the /** The track length returned by Track::getLength() only covers the
* distance from start line to finish line, i.e. it does not include * distance from start line to finish line, i.e. it does not include
@ -65,10 +66,10 @@ private:
int m_race_lap; int m_race_lap;
/** Time at finishing last lap. */ /** Time at finishing last lap. */
float m_time_at_last_lap; int m_ticks_at_last_lap;
/** Time at start of a new lap. */ /** Time at start of a new lap. */
float m_lap_start_time; int m_lap_start_ticks;
/** During last lap only: estimated finishing time! */ /** During last lap only: estimated finishing time! */
float m_estimated_finish; float m_estimated_finish;
@ -84,8 +85,8 @@ private:
void reset() void reset()
{ {
m_race_lap = -1; m_race_lap = -1;
m_lap_start_time = 0; m_lap_start_ticks = 0;
m_time_at_last_lap = 99999.9f; m_ticks_at_last_lap = INT_MAX;
m_estimated_finish = -1.0f; m_estimated_finish = -1.0f;
m_overall_distance = 0.0f; m_overall_distance = 0.0f;
} // reset } // reset
@ -117,7 +118,7 @@ public:
float getDistanceToCenterForKart(const int kart_id) const; float getDistanceToCenterForKart(const int kart_id) const;
float getEstimatedFinishTime(const int kart_id) const; float getEstimatedFinishTime(const int kart_id) const;
int getLapForKart(const int kart_id) const; int getLapForKart(const int kart_id) const;
float getTimeAtLapForKart(const int kart_id) const; int getTicksAtLapForKart(const int kart_id) const;
virtual void getKartsDisplayInfo( virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE; std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
@ -155,11 +156,11 @@ public:
{ {
return m_kart_info[kart_index].m_overall_distance; return m_kart_info[kart_index].m_overall_distance;
} // getOverallDistance } // getOverallDistance
// ------------------------------------------------------------------------
/** Returns time for the fastest laps */ /** Returns time for the fastest laps */
float getFastestLap() const float getFastestLap() const
{ {
return m_fastest_lap; return stk_config->ticks2Time(m_fastest_lap_ticks);
} }
}; // LinearWorld }; // LinearWorld

View File

@ -625,26 +625,24 @@ void ThreeStrikesBattle::addKartLife(unsigned int id)
void ThreeStrikesBattle::spawnSpareTireKarts() void ThreeStrikesBattle::spawnSpareTireKarts()
{ {
if (m_spare_tire_karts.empty() || if (m_spare_tire_karts.empty() ||
getTimeSinceStart() < m_next_sta_spawn_time) getTicksSinceStart() < m_next_sta_spawn_time)
return; return;
const float period =
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST ? 40.0f :
race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 30.0f :
race_manager->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ?
25.0f : 20.0f;
const float inc_factor =
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST ? 0.7f :
race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 0.65f :
race_manager->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ?
0.6f : 0.55f;
// Spawn spare tire kart when necessary
// The lifespan for sta: inc_factor / period * 1000 / 2 // The lifespan for sta: inc_factor / period * 1000 / 2
// So in easier mode the sta lasts longer than spawn period // So in easier mode the sta lasts longer than spawn period
const float lifespan = inc_factor / period * 1000; float inc_factor, lifespan;
m_next_sta_spawn_time = lifespan + (getTimeSinceStart() * inc_factor) + switch (race_manager->getDifficulty())
getTimeSinceStart(); {
case RaceManager::DIFFICULTY_BEST: inc_factor = 0.7f; lifespan = 17.5f; break;
case RaceManager::DIFFICULTY_HARD: inc_factor = 0.65f; lifespan = 21.66f; break;
case RaceManager::DIFFICULTY_EASY: inc_factor = 0.6f; lifespan = 24.0f; break;
default: inc_factor = 0.55f; lifespan = 27.5f; break;
}
// Spawn spare tire kart when necessary
m_next_sta_spawn_time = stk_config->time2Ticks(lifespan)
+ getTicksSinceStart() * inc_factor
+ getTicksSinceStart();
int kart_has_few_lives = 0; int kart_has_few_lives = 0;
for (unsigned int i = 0; i < m_kart_info.size(); i++) for (unsigned int i = 0; i < m_kart_info.size(); i++)
{ {

View File

@ -311,7 +311,7 @@ void World::reset()
irr_driver->reset(); irr_driver->reset();
//Reset the Rubber Ball Collect Time to some negative value. //Reset the Rubber Ball Collect Time to some negative value.
powerup_manager->setBallCollectTime(-100); powerup_manager->setBallCollectTicks(-100);
} // reset } // reset
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -63,8 +63,9 @@ void WorldStatus::reset()
{ {
m_time = 0.0f; m_time = 0.0f;
m_adjust_time_by = 0.0f; m_adjust_time_by = 0.0f;
m_auxiliary_timer = 0.0f; m_time_ticks = 0;
m_count_up_timer = 0.0f; m_auxiliary_ticks = 0;
m_count_up_ticks = 0;
m_engines_started = false; m_engines_started = false;
@ -138,7 +139,8 @@ void WorldStatus::startEngines()
void WorldStatus::setClockMode(const ClockType mode, const float initial_time) void WorldStatus::setClockMode(const ClockType mode, const float initial_time)
{ {
m_clock_mode = mode; m_clock_mode = mode;
m_time = initial_time; m_time_ticks = stk_config->time2Ticks(initial_time);
m_time = stk_config->ticks2Time(m_time_ticks);
} // setClockMode } // setClockMode
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -154,7 +156,7 @@ void WorldStatus::enterRaceOverState()
return; return;
m_phase = DELAY_FINISH_PHASE; m_phase = DELAY_FINISH_PHASE;
m_auxiliary_timer = 0.0f; m_auxiliary_ticks = 0;
} // enterRaceOverState } // enterRaceOverState
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -190,7 +192,7 @@ void WorldStatus::updateTime(const float dt)
// tilt way too much. A separate setup phase for the first frame // tilt way too much. A separate setup phase for the first frame
// simplifies this handling // simplifies this handling
case SETUP_PHASE: case SETUP_PHASE:
m_auxiliary_timer = 0.0f; m_auxiliary_ticks= 0;
m_phase = TRACK_INTRO_PHASE; m_phase = TRACK_INTRO_PHASE;
if (m_play_track_intro_sound) if (m_play_track_intro_sound)
@ -205,7 +207,7 @@ void WorldStatus::updateTime(const float dt)
return; // Do not increase time return; // Do not increase time
case TRACK_INTRO_PHASE: case TRACK_INTRO_PHASE:
m_auxiliary_timer += dt; m_auxiliary_ticks++;
if (UserConfigParams::m_artist_debug_mode && if (UserConfigParams::m_artist_debug_mode &&
!NetworkConfig::get()->isNetworking() && !NetworkConfig::get()->isNetworking() &&
@ -213,7 +215,7 @@ void WorldStatus::updateTime(const float dt)
race_manager->getNumSpareTireKarts() == 1 && race_manager->getNumSpareTireKarts() == 1 &&
race_manager->getTrackName() != "tutorial") race_manager->getTrackName() != "tutorial")
{ {
m_auxiliary_timer += dt * 6; m_auxiliary_ticks += 6;
} }
// Work around a bug that occurred on linux once: // Work around a bug that occurred on linux once:
@ -223,21 +225,22 @@ void WorldStatus::updateTime(const float dt)
// long, we use the aux timer to force the next phase // long, we use the aux timer to force the next phase
// after 3.5 seconds. // after 3.5 seconds.
if (m_track_intro_sound->getStatus() == SFXBase::SFX_PLAYING && if (m_track_intro_sound->getStatus() == SFXBase::SFX_PLAYING &&
m_auxiliary_timer < 3.5f) m_auxiliary_ticks < stk_config->time2Ticks(3.5f) )
return; // Do not increase time return; // Do not increase time
// Wait before ready phase if sounds are disabled // Wait before ready phase if sounds are disabled
if (!UserConfigParams::m_sfx && m_auxiliary_timer < 3.0f) if (!UserConfigParams::m_sfx &&
m_auxiliary_ticks < stk_config->time2Ticks(3.0f))
return; return;
if (!m_play_track_intro_sound) if (!m_play_track_intro_sound)
{ {
startEngines(); startEngines();
if (m_auxiliary_timer < 3.0f) if (m_auxiliary_ticks < stk_config->time2Ticks(3.0f))
return; // Do not increase time return; // Do not increase time
} }
m_auxiliary_timer = 0.0f; m_auxiliary_ticks = 0;
if (m_play_ready_set_go_sounds) if (m_play_ready_set_go_sounds)
m_prestart_sound->play(); m_prestart_sound->play();
@ -269,8 +272,8 @@ void WorldStatus::updateTime(const float dt)
} }
case READY_PHASE: case READY_PHASE:
startEngines(); startEngines();
// One second
if (m_auxiliary_timer > 1.0) if (m_auxiliary_ticks > stk_config->getPhysicsFPS())
{ {
if (m_play_ready_set_go_sounds) if (m_play_ready_set_go_sounds)
{ {
@ -280,7 +283,7 @@ void WorldStatus::updateTime(const float dt)
m_phase = SET_PHASE; m_phase = SET_PHASE;
} }
m_auxiliary_timer += dt; m_auxiliary_ticks++;
// In artist debug mode, when without opponents, skip the // In artist debug mode, when without opponents, skip the
// ready/set/go counter faster // ready/set/go counter faster
@ -290,12 +293,12 @@ void WorldStatus::updateTime(const float dt)
race_manager->getNumSpareTireKarts() == 1 && race_manager->getNumSpareTireKarts() == 1 &&
race_manager->getTrackName() != "tutorial") race_manager->getTrackName() != "tutorial")
{ {
m_auxiliary_timer += dt*6; m_auxiliary_ticks += 6;
} }
return; // Do not increase time return; // Do not increase time
case SET_PHASE: case SET_PHASE:
if (m_auxiliary_timer > 2.0) if (m_auxiliary_ticks > 2*stk_config->getPhysicsFPS())
{ {
// set phase is over, go to the next one // set phase is over, go to the next one
m_phase = GO_PHASE; m_phase = GO_PHASE;
@ -308,7 +311,7 @@ void WorldStatus::updateTime(const float dt)
onGo(); onGo();
} }
m_auxiliary_timer += dt; m_auxiliary_ticks++;
// In artist debug mode, when without opponents, // In artist debug mode, when without opponents,
// skip the ready/set/go counter faster // skip the ready/set/go counter faster
@ -318,24 +321,25 @@ void WorldStatus::updateTime(const float dt)
race_manager->getNumSpareTireKarts() == 1 && race_manager->getNumSpareTireKarts() == 1 &&
race_manager->getTrackName() != "tutorial") race_manager->getTrackName() != "tutorial")
{ {
m_auxiliary_timer += dt*6; m_auxiliary_ticks += 6;
} }
return; // Do not increase time return; // Do not increase time
case GO_PHASE : case GO_PHASE :
// 2.5 seconds
if (m_auxiliary_timer>2.5f && music_manager->getCurrentMusic() && if (m_auxiliary_ticks>stk_config->time2Ticks(2.5f) &&
music_manager->getCurrentMusic() &&
!music_manager->getCurrentMusic()->isPlaying()) !music_manager->getCurrentMusic()->isPlaying())
{ {
music_manager->startMusic(); music_manager->startMusic();
} }
// how long to display the 'go' message
if (m_auxiliary_timer > 3.0f) // how long to display the 'go' message if (m_auxiliary_ticks > 3 * stk_config->getPhysicsFPS())
{ {
m_phase = MUSIC_PHASE; m_phase = MUSIC_PHASE;
} }
m_auxiliary_timer += dt; m_auxiliary_ticks++;
// In artist debug mode, when without opponents, // In artist debug mode, when without opponents,
// skip the ready/set/go counter faster // skip the ready/set/go counter faster
@ -344,7 +348,7 @@ void WorldStatus::updateTime(const float dt)
race_manager->getNumSpareTireKarts() == 1 && race_manager->getNumSpareTireKarts() == 1 &&
race_manager->getTrackName() != "tutorial") race_manager->getTrackName() != "tutorial")
{ {
m_auxiliary_timer += dt*6; m_auxiliary_ticks += 6;
} }
break; // Now the world time starts break; // Now the world time starts
@ -356,12 +360,13 @@ void WorldStatus::updateTime(const float dt)
UserConfigParams::m_race_now = false; UserConfigParams::m_race_now = false;
} }
// how long to display the 'music' message // how long to display the 'music' message
if (m_auxiliary_timer>stk_config->m_music_credit_time) if (m_auxiliary_ticks >
stk_config->time2Ticks(stk_config->m_music_credit_time) )
{ {
m_phase = RACE_PHASE; m_phase = RACE_PHASE;
} }
m_auxiliary_timer += dt; m_auxiliary_ticks++;
break; break;
case RACE_PHASE: case RACE_PHASE:
// Nothing to do for race phase, switch to delay finish phase // Nothing to do for race phase, switch to delay finish phase
@ -369,10 +374,11 @@ void WorldStatus::updateTime(const float dt)
break; break;
case DELAY_FINISH_PHASE: case DELAY_FINISH_PHASE:
{ {
m_auxiliary_timer += dt; m_auxiliary_ticks++;
// Change to next phase if delay is over // Change to next phase if delay is over
if (m_auxiliary_timer > stk_config->m_delay_finish_time) if (m_auxiliary_ticks >
stk_config->time2Ticks(stk_config->m_delay_finish_time))
{ {
m_phase = RESULT_DISPLAY_PHASE; m_phase = RESULT_DISPLAY_PHASE;
terminateRace(); terminateRace();
@ -400,26 +406,29 @@ void WorldStatus::updateTime(const float dt)
case CLOCK_CHRONO: case CLOCK_CHRONO:
if (!device->getTimer()->isStopped()) if (!device->getTimer()->isStopped())
{ {
m_time += dt; m_time_ticks++;
m_count_up_timer += dt; m_time = stk_config->ticks2Time(m_time_ticks);
m_count_up_ticks++;
} }
break; break;
case CLOCK_COUNTDOWN: case CLOCK_COUNTDOWN:
// stop countdown when race is over // stop countdown when race is over
if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE) if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE)
{ {
m_time_ticks = 0;
m_time = 0.0f; m_time = 0.0f;
m_count_up_timer = 0.0f; m_count_up_ticks = 0;
break; break;
} }
if (!device->getTimer()->isStopped()) if (!device->getTimer()->isStopped())
{ {
m_time -= dt; m_time_ticks--;
m_count_up_timer += dt; m_time = stk_config->ticks2Time(m_time_ticks);
m_count_up_ticks++;
} }
if(m_time <= 0.0) if(m_time_ticks <= 0.0)
{ {
// event // event
countdownReachedZero(); countdownReachedZero();
@ -484,10 +493,23 @@ void WorldStatus::startReadySetGo()
*/ */
void WorldStatus::setTime(const float time) void WorldStatus::setTime(const float time)
{ {
m_count_up_timer += (time - m_time); int new_time_ticks = stk_config->time2Ticks(time);
m_time = time; m_count_up_ticks += (new_time_ticks - m_time_ticks);
m_time_ticks = new_time_ticks;
m_time = stk_config->ticks2Time(new_time_ticks);
} // setTime } // setTime
//-----------------------------------------------------------------------------
/** Sets a new time for the world time, measured in ticks.
* \param ticks New time in ticks to set.
*/
void WorldStatus::setTicks(int ticks)
{
m_count_up_ticks += ticks - m_time_ticks;
m_time_ticks = ticks;
m_time = stk_config->ticks2Time(ticks);
} // setTicks
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Pauses the game and switches to the specified phase. /** Pauses the game and switches to the specified phase.
* \param phase Phase to switch to. * \param phase Phase to switch to.

View File

@ -91,6 +91,9 @@ protected:
/** Elasped/remaining time in seconds. */ /** Elasped/remaining time in seconds. */
double m_time; double m_time;
/** Time in number of ticks (in terms of physics time steps). */
int m_time_ticks;
/** If the start race should be played, disabled in cutscenes. */ /** If the start race should be played, disabled in cutscenes. */
bool m_play_racestart_sounds; bool m_play_racestart_sounds;
@ -129,9 +132,11 @@ private:
* Counts time during the initial 'ready/set/go' phase, or at the end of a race. * Counts time during the initial 'ready/set/go' phase, or at the end of a race.
* This timer basically kicks in when we need to calculate non-race time like labels. * This timer basically kicks in when we need to calculate non-race time like labels.
*/ */
float m_auxiliary_timer; int m_auxiliary_ticks;
float m_count_up_timer; /** Special counter to count ticks since start (in terms of physics
* timestep size). */
int m_count_up_ticks;
bool m_engines_started; bool m_engines_started;
/** In networked game a client must wait for the server to start 'ready /** In networked game a client must wait for the server to start 'ready
@ -155,6 +160,7 @@ public:
virtual void enterRaceOverState(); virtual void enterRaceOverState();
virtual void terminateRace(); virtual void terminateRace();
void setTime(const float time); void setTime(const float time);
void setTicks(int ticks);
float adjustDT(float dt); float adjustDT(float dt);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -192,6 +198,11 @@ public:
/** Returns the current race time. */ /** Returns the current race time. */
float getTime() const { return (float)m_time; } float getTime() const { return (float)m_time; }
// ------------------------------------------------------------------------
/** Returns the current race time in time ticks (i.e. based on the physics
* time step size). */
int getTimeTicks() const { return m_time_ticks; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Will be called to notify your derived class that the clock, /** Will be called to notify your derived class that the clock,
* which is in COUNTDOWN mode, has reached zero. */ * which is in COUNTDOWN mode, has reached zero. */
@ -202,8 +213,8 @@ public:
virtual void onGo() {}; virtual void onGo() {};
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Get the time since start regardless of which way the clock counts */ /** Get the ticks since start regardless of which way the clock counts */
float getTimeSinceStart() const { return m_count_up_timer; } int getTicksSinceStart() const { return m_count_up_ticks; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setReadyToRace() { m_server_is_ready = true; } void setReadyToRace() { m_server_is_ready = true; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -140,7 +140,7 @@ void GameProtocol::controllerAction(int kart_id, PlayerAction action,
s->addUInt8(kart_id).addUInt8(action).addUInt32(value) s->addUInt8(kart_id).addUInt8(action).addUInt32(value)
.addUInt32(val_l).addUInt32(val_r); .addUInt32(val_l).addUInt32(val_r);
RewindManager::get()->addEvent(this, s, /*confirmed*/true, RewindManager::get()->addEvent(this, s, /*confirmed*/true,
World::getWorld()->getTime() ); World::getWorld()->getTimeTicks() );
Log::info("GameProtocol", "Action at %f: %d value %d", Log::info("GameProtocol", "Action at %f: %d value %d",
World::getWorld()->getTime(), action, World::getWorld()->getTime(), action,
@ -158,19 +158,21 @@ void GameProtocol::handleControllerAction(Event *event)
NetworkString &data = event->data(); NetworkString &data = event->data();
uint8_t count = data.getUInt8(); uint8_t count = data.getUInt8();
bool will_trigger_rewind = false; bool will_trigger_rewind = false;
float rewind_delta = 0.0f; int rewind_delta = 0;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
float time = data.getFloat(); int ticks = data.getUInt32();
// Since this is running in a thread, it might be called during // Since this is running in a thread, it might be called during
// a rewind, i.e. with an incorrect world time. So the event // a rewind, i.e. with an incorrect world time. So the event
// time needs to be compared with the World time independent // time needs to be compared with the World time independent
// of any rewinding. // of any rewinding.
if (time < RewindManager::get()->getNotRewoundWorldTime() && if (ticks < RewindManager::get()->getNotRewoundWorldTicks() &&
!will_trigger_rewind ) !will_trigger_rewind )
{ {
will_trigger_rewind = true; will_trigger_rewind = true;
rewind_delta = time - RewindManager::get()->getNotRewoundWorldTime(); rewind_delta = ticks
- RewindManager::get()->getNotRewoundWorldTicks();
} }
uint8_t kart_id = data.getUInt8(); uint8_t kart_id = data.getUInt8();
assert(kart_id < World::getWorld()->getNumKarts()); assert(kart_id < World::getWorld()->getNumKarts());
@ -179,12 +181,12 @@ void GameProtocol::handleControllerAction(Event *event)
int value = data.getUInt32(); int value = data.getUInt32();
int value_l = data.getUInt32(); int value_l = data.getUInt32();
int value_r = data.getUInt32(); int value_r = data.getUInt32();
Log::info("GameProtocol", "Action at %f: %d %d %d %d %d", Log::info("GameProtocol", "Action at %d: %d %d %d %d %d",
time, kart_id, action, value, value_l, value_r); ticks, kart_id, action, value, value_l, value_r);
BareNetworkString *s = new BareNetworkString(3); BareNetworkString *s = new BareNetworkString(3);
s->addUInt8(kart_id).addUInt8(action).addUInt32(value) s->addUInt8(kart_id).addUInt8(action).addUInt32(value)
.addUInt32(value_l).addUInt32(value_r); .addUInt32(value_l).addUInt32(value_r);
RewindManager::get()->addNetworkEvent(this, s, time); RewindManager::get()->addNetworkEvent(this, s, ticks);
} }
if (data.size() > 0) if (data.size() > 0)
@ -200,9 +202,9 @@ void GameProtocol::handleControllerAction(Event *event)
if (will_trigger_rewind) if (will_trigger_rewind)
{ {
Log::info("GameProtocol", Log::info("GameProtocol",
"At %f %f %f requesting time adjust of %f for host %d", "At %d %f %d requesting time adjust of %d for host %d",
World::getWorld()->getTime(), StkTime::getRealTime(), World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
RewindManager::get()->getNotRewoundWorldTime(), RewindManager::get()->getNotRewoundWorldTicks(),
rewind_delta, event->getPeer()->getHostId()); rewind_delta, event->getPeer()->getHostId());
// This message from a client triggered a rewind in the server. // This message from a client triggered a rewind in the server.
// To avoid this, signal to the client that it should slow down. // To avoid this, signal to the client that it should slow down.
@ -219,11 +221,11 @@ void GameProtocol::handleControllerAction(Event *event)
* \param peer The peer that triggered the rewind. * \param peer The peer that triggered the rewind.
* \param t Time that the peer needs to slowdown (<0) or sped up(>0). * \param t Time that the peer needs to slowdown (<0) or sped up(>0).
*/ */
void GameProtocol::adjustTimeForClient(STKPeer *peer, float t) void GameProtocol::adjustTimeForClient(STKPeer *peer, int ticks)
{ {
assert(NetworkConfig::get()->isServer()); assert(NetworkConfig::get()->isServer());
NetworkString *ns = getNetworkString(5); NetworkString *ns = getNetworkString(5);
ns->addUInt8(GP_ADJUST_TIME).addFloat(t); ns->addUInt8(GP_ADJUST_TIME).addUInt32(ticks);
// This message can be send unreliable, it's not critical if it doesn't // This message can be send unreliable, it's not critical if it doesn't
// get delivered, the server will request again later anyway. // get delivered, the server will request again later anyway.
peer->sendPacket(ns, /*reliable*/false); peer->sendPacket(ns, /*reliable*/false);
@ -282,9 +284,9 @@ void GameProtocol::handleState(Event *event)
assert(NetworkConfig::get()->isClient()); assert(NetworkConfig::get()->isClient());
NetworkString &data = event->data(); NetworkString &data = event->data();
float time = data.getFloat(); int ticks = data.getUInt32();
Log::info("GameProtocol", "Received at %f state from %f", Log::info("GameProtocol", "Received at %d state from %d",
World::getWorld()->getTime(), time); World::getWorld()->getTimeTicks(), ticks);
int index = 0; int index = 0;
while (data.size() > 0) while (data.size() > 0)
{ {
@ -292,7 +294,7 @@ void GameProtocol::handleState(Event *event)
BareNetworkString *state = new BareNetworkString(data.getCurrentData(), BareNetworkString *state = new BareNetworkString(data.getCurrentData(),
count); count);
data.skip(count); data.skip(count);
RewindManager::get()->addNetworkState(index, state, time); RewindManager::get()->addNetworkState(index, state, ticks);
index++; index++;
} // while data.size()>0 } // while data.size()>0
} // handleState } // handleState

View File

@ -81,7 +81,7 @@ public:
void startNewState(); void startNewState();
void addState(BareNetworkString *buffer); void addState(BareNetworkString *buffer);
void sendState(); void sendState();
void adjustTimeForClient(STKPeer *peer, float t); void adjustTimeForClient(STKPeer *peer, int ticks);
virtual void undo(BareNetworkString *buffer) OVERRIDE; virtual void undo(BareNetworkString *buffer) OVERRIDE;
virtual void rewind(BareNetworkString *buffer) OVERRIDE; virtual void rewind(BareNetworkString *buffer) OVERRIDE;

View File

@ -1115,7 +1115,7 @@ void ServerLobby::startedRaceOnClient(Event *event)
void ServerLobby::playerFinishedResult(Event *event) void ServerLobby::playerFinishedResult(Event *event)
{ {
m_player_ready_counter++; m_player_ready_counter++;
if(m_player_ready_counter >= STKHost::get()->getPeerCount()) if(m_player_ready_counter >= (int)STKHost::get()->getPeerCount())
{ {
// We can't trigger the world/race exit here, since this is called // We can't trigger the world/race exit here, since this is called
// from the protocol manager thread. So instead we force the timeout // from the protocol manager thread. So instead we force the timeout

View File

@ -25,9 +25,9 @@
* for all state info. * for all state info.
* \param size Necessary buffer size for a state. * \param size Necessary buffer size for a state.
*/ */
RewindInfo::RewindInfo(float time, bool is_confirmed) RewindInfo::RewindInfo(int ticks, bool is_confirmed)
{ {
m_time = time; m_ticks = ticks;
m_is_confirmed = is_confirmed; m_is_confirmed = is_confirmed;
} // RewindInfo } // RewindInfo
@ -36,17 +36,17 @@ RewindInfo::RewindInfo(float time, bool is_confirmed)
* in case that an event is received in the past - in this case the server * in case that an event is received in the past - in this case the server
* needs to avoid a Rewind by moving this event forward to the current time. * needs to avoid a Rewind by moving this event forward to the current time.
*/ */
void RewindInfo::setTime(float time) void RewindInfo::setTicks(int ticks)
{ {
assert(NetworkConfig::get()->isServer()); assert(NetworkConfig::get()->isServer());
assert(m_time < time); assert(m_ticks < ticks);
m_time = time; m_ticks = ticks;
} // setTime } // setTicks
// ============================================================================ // ============================================================================
RewindInfoState::RewindInfoState(float time, Rewinder *rewinder, RewindInfoState::RewindInfoState(int ticks, Rewinder *rewinder,
BareNetworkString *buffer, bool is_confirmed) BareNetworkString *buffer, bool is_confirmed)
: RewindInfoRewinder(time, rewinder, buffer, is_confirmed) : RewindInfoRewinder(ticks, rewinder, buffer, is_confirmed)
{ {
// rewinder = NULL is used in unit testing, in which case no world exists // rewinder = NULL is used in unit testing, in which case no world exists
if(rewinder!=NULL) if(rewinder!=NULL)
@ -55,9 +55,9 @@ RewindInfoState::RewindInfoState(float time, Rewinder *rewinder,
} // RewindInfoState } // RewindInfoState
// ============================================================================ // ============================================================================
RewindInfoEvent::RewindInfoEvent(float time, EventRewinder *event_rewinder, RewindInfoEvent::RewindInfoEvent(int ticks, EventRewinder *event_rewinder,
BareNetworkString *buffer, bool is_confirmed) BareNetworkString *buffer, bool is_confirmed)
: RewindInfo(time, is_confirmed) : RewindInfo(ticks, is_confirmed)
{ {
m_event_rewinder = event_rewinder; m_event_rewinder = event_rewinder;
m_buffer = buffer; m_buffer = buffer;

View File

@ -46,7 +46,7 @@ private:
LEAK_CHECK(); LEAK_CHECK();
/** Time when this RewindInfo was taken. */ /** Time when this RewindInfo was taken. */
float m_time; int m_ticks;
/** A confirmed event is one that was sent from the server. When /** A confirmed event is one that was sent from the server. When
* rewinding we have to start with a confirmed state for each * rewinding we have to start with a confirmed state for each
@ -54,7 +54,7 @@ private:
bool m_is_confirmed; bool m_is_confirmed;
public: public:
RewindInfo(float time, bool is_confirmed); RewindInfo(int ticks, bool is_confirmed);
/** Called when going back in time to undo any rewind information. */ /** Called when going back in time to undo any rewind information. */
virtual void undo() = 0; virtual void undo() = 0;
@ -62,12 +62,12 @@ public:
/** This is called while going forwards in time again to reach current /** This is called while going forwards in time again to reach current
* time. */ * time. */
virtual void rewind() = 0; virtual void rewind() = 0;
void setTime(float time); void setTicks(int ticks);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual ~RewindInfo() { } virtual ~RewindInfo() { }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the time at which this RewindInfo was saved. */ /** Returns the time at which this RewindInfo was saved. */
float getTime() const { return m_time; } int getTicks() const { return m_ticks; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets if this RewindInfo is confirmed or not. */ /** Sets if this RewindInfo is confirmed or not. */
void setConfirmed(bool b) { m_is_confirmed = b; } void setConfirmed(bool b) { m_is_confirmed = b; }
@ -101,9 +101,9 @@ protected:
Rewinder *m_rewinder; Rewinder *m_rewinder;
public: public:
RewindInfoRewinder(float time, Rewinder *rewinder, RewindInfoRewinder(int ticks, Rewinder *rewinder,
BareNetworkString *buffer, bool is_confirmed) BareNetworkString *buffer, bool is_confirmed)
: RewindInfo(time, is_confirmed) : RewindInfo(ticks, is_confirmed)
{ {
m_rewinder = rewinder; m_rewinder = rewinder;
m_buffer = buffer; m_buffer = buffer;
@ -126,7 +126,7 @@ private:
float m_local_physics_time; float m_local_physics_time;
public: public:
RewindInfoState(float time, Rewinder *rewinder, RewindInfoState(int ticks, Rewinder *rewinder,
BareNetworkString *buffer, bool is_confirmed); BareNetworkString *buffer, bool is_confirmed);
virtual ~RewindInfoState() {}; virtual ~RewindInfoState() {};
@ -169,7 +169,7 @@ private:
/** Buffer with the event data. */ /** Buffer with the event data. */
BareNetworkString *m_buffer; BareNetworkString *m_buffer;
public: public:
RewindInfoEvent(float time, EventRewinder *event_rewinder, RewindInfoEvent(int ticks, EventRewinder *event_rewinder,
BareNetworkString *buffer, bool is_confirmed); BareNetworkString *buffer, bool is_confirmed);
virtual ~RewindInfoEvent() virtual ~RewindInfoEvent()
{ {

View File

@ -75,10 +75,11 @@ RewindManager::~RewindManager()
void RewindManager::reset() void RewindManager::reset()
{ {
m_is_rewinding = false; m_is_rewinding = false;
m_not_rewound_time = 0; m_not_rewound_ticks = 0;
m_overall_state_size = 0; m_overall_state_size = 0;
m_state_frequency = 1.0f / stk_config->m_network_state_frequeny; m_last_saved_state = -1; // forces initial state save
m_last_saved_state = -9999.9f; // forces initial state save m_state_frequency =
stk_config->getPhysicsFPS() / stk_config->m_network_state_frequeny;
if(!m_enable_rewind_manager) return; if(!m_enable_rewind_manager) return;
@ -102,7 +103,7 @@ void RewindManager::reset()
/** Adds a new TimeStep entry. Only exception is time=0 (which happens during /** 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. * all of 'ready, set, go') - for which only one entry is created.
*/ */
void RewindManager::addNextTimeStep(float time, float dt) 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
@ -122,7 +123,7 @@ void RewindManager::addNextTimeStep(float time, float dt)
*/ */
void RewindManager::addEvent(EventRewinder *event_rewinder, void RewindManager::addEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, bool confirmed, BareNetworkString *buffer, bool confirmed,
float time ) int ticks )
{ {
if(m_is_rewinding) if(m_is_rewinding)
{ {
@ -131,9 +132,9 @@ void RewindManager::addEvent(EventRewinder *event_rewinder,
return; return;
} }
if (time < 0) if (ticks < 0)
time = World::getWorld()->getTime(); ticks = World::getWorld()->getTimeTicks();
m_rewind_queue.addLocalEvent(event_rewinder, buffer, confirmed, time); m_rewind_queue.addLocalEvent(event_rewinder, buffer, confirmed, ticks);
} // addEvent } // addEvent
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -145,9 +146,9 @@ 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, float time) BareNetworkString *buffer, int ticks)
{ {
m_rewind_queue.addNetworkEvent(event_rewinder, buffer, time); m_rewind_queue.addNetworkEvent(event_rewinder, buffer, ticks);
} // addNetworkEvent } // addNetworkEvent
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -159,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,
float time) 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,
time, -99); ticks, -99);
} // addNetworkState } // addNetworkState
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -180,11 +181,13 @@ void RewindManager::update(float dt)
m_is_rewinding ) return; m_is_rewinding ) return;
float time = World::getWorld()->getTime(); float time = World::getWorld()->getTime();
m_not_rewound_time = time; int ticks = World::getWorld()->getTimeTicks();
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() ||
time - m_last_saved_state < m_state_frequency ) ticks - m_last_saved_state < m_state_frequency )
{ {
return; return;
} }
@ -201,7 +204,7 @@ void RewindManager::update(float dt)
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()->getTime()); World::getWorld()->getTimeTicks());
GameProtocol::lock()->addState(buffer); GameProtocol::lock()->addState(buffer);
} // size >= 0 } // size >= 0
else else
@ -211,7 +214,7 @@ void RewindManager::update(float dt)
PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40); PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40);
GameProtocol::lock()->sendState(); GameProtocol::lock()->sendState();
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
m_last_saved_state = time; m_last_saved_state = ticks;
} // update } // update
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -223,23 +226,23 @@ void RewindManager::update(float dt)
void RewindManager::playEventsTill(float time, float *dt) void RewindManager::playEventsTill(float time, float *dt)
{ {
bool needs_rewind; bool needs_rewind;
float rewind_time; int rewind_ticks;
// Merge in all network events that have happened since the last // Merge in all network events that have happened since the last
// 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()->getTime(), *dt, m_rewind_queue.mergeNetworkData(World::getWorld()->getTimeTicks(), *dt,
&needs_rewind, &rewind_time); &needs_rewind, &rewind_ticks);
if (needs_rewind) if (needs_rewind)
{ {
Log::setPrefix("Rewind"); Log::setPrefix("Rewind");
PROFILER_PUSH_CPU_MARKER("Rewind", 128, 128, 128); PROFILER_PUSH_CPU_MARKER("Rewind", 128, 128, 128);
rewindTo(rewind_time); rewindTo(rewind_ticks);
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
Log::setPrefix(""); Log::setPrefix("");
TimeStepInfo *tsi = m_rewind_queue.getCurrent(); TimeStepInfo *tsi = m_rewind_queue.getCurrent();
World::getWorld()->setTime(tsi->getTime()); World::getWorld()->setTicks(tsi->getTicks());
Physics::getInstance()->getPhysicsWorld()->resetLocalTime(); Physics::getInstance()->getPhysicsWorld()->resetLocalTime();
} }
@ -262,8 +265,8 @@ void RewindManager::playEventsTill(float time, float *dt)
if (tsi->hasConfirmedState() && NetworkConfig::get()->isClient()) if (tsi->hasConfirmedState() && NetworkConfig::get()->isClient())
{ {
Log::warn("RewindManager", Log::warn("RewindManager",
"Client has received state in the future: at %f state %f", "Client has received state in the future: at %d state %d",
World::getWorld()->getTime(), tsi->getTime()); World::getWorld()->getTimeTicks(), tsi->getTicks());
} }
m_is_rewinding = false; m_is_rewinding = false;
} // playEventsTill } // playEventsTill
@ -272,9 +275,9 @@ void RewindManager::playEventsTill(float time, float *dt)
/** 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
* World::getTime(), but not the events at World::getTime() (or later)/ * World::getTime(), but not the events at World::getTime() (or later)/
* \param rewind_time Time to rewind to. * \param rewind_ticks Time to rewind to.
*/ */
void RewindManager::rewindTo(float rewind_time) void RewindManager::rewindTo(int rewind_ticks)
{ {
assert(!m_is_rewinding); assert(!m_is_rewinding);
bool is_history = history->replayHistory(); bool is_history = history->replayHistory();
@ -293,7 +296,7 @@ void RewindManager::rewindTo(float rewind_time)
// Then undo the rewind infos going backwards in time // Then undo the rewind infos going backwards in time
// -------------------------------------------------- // --------------------------------------------------
m_is_rewinding = true; m_is_rewinding = true;
m_rewind_queue.undoUntil(rewind_time); m_rewind_queue.undoUntil(rewind_ticks);
// Rewind the required state(s) // Rewind the required state(s)
// ---------------------------- // ----------------------------
@ -304,11 +307,11 @@ void RewindManager::rewindTo(float rewind_time)
TimeStepInfo *current = m_rewind_queue.getCurrent(); TimeStepInfo *current = m_rewind_queue.getCurrent();
// Store the time to which we have to replay to, // Store the time to which we have to replay to,
// which can be earlier than rewind_time // which can be earlier than rewind_ticks
float exact_rewind_time = current->getTime(); int exact_rewind_ticks = current->getTicks();
// Now start the rewind with the full state: // Now start the rewind with the full state:
world->setTime(exact_rewind_time); world->setTicks(exact_rewind_ticks);
float local_physics_time = current->getLocalPhysicsTime(); float local_physics_time = current->getLocalPhysicsTime();
Physics::getInstance()->getPhysicsWorld()->setLocalTime(local_physics_time); Physics::getInstance()->getPhysicsWorld()->setLocalTime(local_physics_time);
@ -346,8 +349,8 @@ void RewindManager::rewindTo(float rewind_time)
++m_rewind_queue; ++m_rewind_queue;
current = m_rewind_queue.getCurrent(); current = m_rewind_queue.getCurrent();
world->setTime(current->getTime()); world->setTicks(current->getTicks());
} // while (world->getTime() < current_time) } // while (world->getTicks() < current_ticks)
// Now compute the errors which need to be visually smoothed // Now compute the errors which need to be visually smoothed
for (rewinder = m_all_rewinder.begin(); for (rewinder = m_all_rewinder.begin();

View File

@ -101,14 +101,15 @@ private:
bool m_is_rewinding; bool m_is_rewinding;
/** How much time between consecutive state saves. */ /** How much time between consecutive state saves. */
float m_state_frequency; int m_state_frequency;
/** Time at which the last state was saved. */ /** Ticks at which the last state was saved. */
float m_last_saved_state; int m_last_saved_state;
/** This stores the original World time during a rewind. It is used to /** This stores the original World time in ticks during a rewind. It is
* detect if a client's local time need adjustment to reduce rewinds. */ * used to detect if a client's local time need adjustment to reduce
float m_not_rewound_time; * rewinds. */
int m_not_rewound_ticks;
RewindManager(); RewindManager();
~RewindManager(); ~RewindManager();
@ -137,15 +138,15 @@ public:
void reset(); void reset();
void update(float dt); void update(float dt);
void rewindTo(float target_time); void rewindTo(int target_ticks);
void playEventsTill(float time, float *dt); void playEventsTill(float time, float *dt);
void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer,
bool confirmed, float time = -1.0f); bool confirmed, int ticks = -1);
void addNetworkEvent(EventRewinder *event_rewinder, void addNetworkEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, float time); BareNetworkString *buffer, int ticks);
void addNetworkState(int rewinder_index, BareNetworkString *buffer, void addNetworkState(int rewinder_index, BareNetworkString *buffer,
float time); int ticks);
void addNextTimeStep(float time, float dt); void addNextTimeStep(int ticks, float dt);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Adds a Rewinder to the list of all rewinders. /** Adds a Rewinder to the list of all rewinders.
* \return true If rewinding is enabled, false otherwise. * \return true If rewinding is enabled, false otherwise.
@ -160,7 +161,7 @@ public:
/** 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; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
float getNotRewoundWorldTime() const { return m_not_rewound_time; } int getNotRewoundWorldTicks() const { return m_not_rewound_ticks; }
}; // RewindManager }; // RewindManager

View File

@ -99,11 +99,11 @@ void RewindQueue::reset()
* \param time New time to add. * \param time New time to add.
* \param dt Time step size that is going to be used for this time step. * \param dt Time step size that is going to be used for this time step.
*/ */
void RewindQueue::addNewTimeStep(float time, float dt) void RewindQueue::addNewTimeStep(int ticks, float dt)
{ {
TimeStepInfo *tsi = new TimeStepInfo(time, dt); TimeStepInfo *tsi = new TimeStepInfo(ticks, dt);
assert(m_time_step_info.empty() || assert(m_time_step_info.empty() ||
time > m_time_step_info.back()->getTime() ); ticks > m_time_step_info.back()->getTicks() );
m_time_step_info.push_back(tsi); m_time_step_info.push_back(tsi);
// If current was not initialised // If current was not initialised
@ -121,13 +121,13 @@ void RewindQueue::addNewTimeStep(float time, float dt)
* \param Time at which the event that needs to be added hapened. * \param Time at which the event that needs to be added hapened.
*/ */
RewindQueue::AllTimeStepInfo::iterator RewindQueue::AllTimeStepInfo::iterator
RewindQueue::findPreviousTimeStepInfo(float t) RewindQueue::findPreviousTimeStepInfo(int ticks)
{ {
AllTimeStepInfo::iterator i = m_time_step_info.end(); AllTimeStepInfo::iterator i = m_time_step_info.end();
while(i!=m_time_step_info.begin()) while(i!=m_time_step_info.begin())
{ {
i--; i--;
if ((*i)->getTime() <= t) return i; if ((*i)->getTicks() <= ticks) return i;
} }
return i; return i;
} // findPreviousTimeStepInfo } // findPreviousTimeStepInfo
@ -140,7 +140,7 @@ RewindQueue::AllTimeStepInfo::iterator
bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri1, bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri1,
const TimeStepInfo * const ri2) const const TimeStepInfo * const ri2) const
{ {
return ri1->getTime() < ri2->getTime(); return ri1->getTicks() < ri2->getTicks();
} // RewindQueue::operator() } // RewindQueue::operator()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -153,7 +153,7 @@ bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri
void RewindQueue::insertRewindInfo(RewindInfo *ri) void RewindQueue::insertRewindInfo(RewindInfo *ri)
{ {
// FIXME: this should always be the last element in the list(??) // FIXME: this should always be the last element in the list(??)
AllTimeStepInfo::iterator bucket = findPreviousTimeStepInfo(ri->getTime()); AllTimeStepInfo::iterator bucket = findPreviousTimeStepInfo(ri->getTicks());
// FIXME: In case of a history replay an element could be inserted in the // FIXME: In case of a history replay an element could be inserted in the
// very first frame (on very quick recorded start, and if the first frame // very first frame (on very quick recorded start, and if the first frame
@ -172,9 +172,9 @@ void RewindQueue::insertRewindInfo(RewindInfo *ri)
*/ */
void RewindQueue::addLocalEvent(EventRewinder *event_rewinder, void RewindQueue::addLocalEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, bool confirmed, BareNetworkString *buffer, bool confirmed,
float time ) int ticks )
{ {
RewindInfo *ri = new RewindInfoEvent(time, event_rewinder, RewindInfo *ri = new RewindInfoEvent(ticks, event_rewinder,
buffer, confirmed); buffer, confirmed);
insertRewindInfo(ri); insertRewindInfo(ri);
} // addLocalEvent } // addLocalEvent
@ -191,9 +191,9 @@ void RewindQueue::addLocalEvent(EventRewinder *event_rewinder,
* \param time Time at which the state was captured. * \param time Time at which the state was captured.
*/ */
void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer, void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
bool confirmed, float time) bool confirmed, int ticks)
{ {
RewindInfo *ri = new RewindInfoState(time, rewinder, buffer, confirmed); RewindInfo *ri = new RewindInfoState(ticks, rewinder, buffer, confirmed);
assert(ri); assert(ri);
insertRewindInfo(ri); insertRewindInfo(ri);
} // addLocalState } // addLocalState
@ -207,9 +207,9 @@ void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
* \param buffer Pointer to the event data. * \param buffer Pointer to the event data.
*/ */
void RewindQueue::addNetworkEvent(EventRewinder *event_rewinder, void RewindQueue::addNetworkEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, float time) BareNetworkString *buffer, int ticks)
{ {
RewindInfo *ri = new RewindInfoEvent(time, event_rewinder, RewindInfo *ri = new RewindInfoEvent(ticks, event_rewinder,
buffer, /*confirmed*/true); buffer, /*confirmed*/true);
m_network_events.lock(); m_network_events.lock();
@ -226,9 +226,9 @@ void RewindQueue::addNetworkEvent(EventRewinder *event_rewinder,
* \param buffer Pointer to the event data. * \param buffer Pointer to the event data.
*/ */
void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer, void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
float time, float dt) int ticks, float dt)
{ {
RewindInfo *ri = new RewindInfoState(time, rewinder, RewindInfo *ri = new RewindInfoState(ticks, rewinder,
buffer, /*confirmed*/true); buffer, /*confirmed*/true);
m_network_events.lock(); m_network_events.lock();
@ -239,7 +239,7 @@ void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Merges thread-safe all data received from the network with the current /** Merges thread-safe all data received from the network with the current
* local rewind information. * local rewind information.
* \param world_time[in] Current world time up to which network events will be * \param world_ticks[in] Current world time up to which network events will be
* merged in. * merged in.
* \param dt[in] Time step size. The current frame will cover events between * \param dt[in] Time step size. The current frame will cover events between
* world_time and world_time+dt. * world_time and world_time+dt.
@ -250,8 +250,8 @@ void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
* must be performed (at least). Otherwise undefined, but the value * must be performed (at least). Otherwise undefined, but the value
* might be modified in this function. * might be modified in this function.
*/ */
void RewindQueue::mergeNetworkData(float world_time, float dt, void RewindQueue::mergeNetworkData(int world_ticks, float dt,
bool *needs_rewind, float *rewind_time) bool *needs_rewind, int *rewind_ticks)
{ {
*needs_rewind = false; *needs_rewind = false;
m_network_events.lock(); m_network_events.lock();
@ -264,7 +264,7 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
// Merge all newly received network events into the main event list. // Merge all newly received network events into the main event list.
// Only a client ever rewinds. So the rewind time should be the latest // Only a client ever rewinds. So the rewind time should be the latest
// received state before current world time (if any) // received state before current world time (if any)
*rewind_time = -99999.9f; *rewind_ticks = -9999;
bool adjust_next = false; bool adjust_next = false;
// FIXME: making m_network_events sorted would prevent the need to // FIXME: making m_network_events sorted would prevent the need to
@ -277,7 +277,7 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
// time step id world_time, the next will be world_time+dt. So if the // time step id world_time, the next will be world_time+dt. So if the
// event is later than world_time+0.5*dt, it will be closer to a // event is later than world_time+0.5*dt, it will be closer to a
// future time stamp and is ignored now. // future time stamp and is ignored now.
if ((*i)->getTime() > world_time+0.5f*dt) if ((*i)->getTicks() > world_ticks+0.5f*dt)
{ {
i++; i++;
continue; continue;
@ -286,23 +286,23 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
// duplicated states, which in the best case would then have // duplicated states, which in the best case would then have
// a negative effect for every player, when in fact only one // a negative effect for every player, when in fact only one
// player might have a network hickup). // player might have a network hickup).
if (NetworkConfig::get()->isServer() && (*i)->getTime() < world_time) if (NetworkConfig::get()->isServer() && (*i)->getTicks() < world_ticks)
{ {
Log::warn("RewindQueue", "At %f received message from %f", Log::warn("RewindQueue", "At %d received message from %d",
world_time, (*i)->getTime()); world_ticks, (*i)->getTicks());
// Server received an event in the past. Adjust this event // Server received an event in the past. Adjust this event
// to be executed now - at least we get a bit closer to the // to be executed now - at least we get a bit closer to the
// client state. // client state.
(*i)->setTime(world_time); (*i)->setTicks(world_ticks);
} }
// Find closest previous time step. // Find closest previous time step.
AllTimeStepInfo::iterator prev = AllTimeStepInfo::iterator prev =
findPreviousTimeStepInfo((*i)->getTime()); findPreviousTimeStepInfo((*i)->getTicks());
AllTimeStepInfo::iterator next = prev; AllTimeStepInfo::iterator next = prev;
next++; next++;
float event_time = (*i)->getTime(); int event_ticks = (*i)->getTicks();
TimeStepInfo *tsi; TimeStepInfo *tsi;
@ -311,18 +311,18 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
// mean more CPU work in the rewind this will very likely trigger). // mean more CPU work in the rewind this will very likely trigger).
if (next == m_time_step_info.end()) if (next == m_time_step_info.end())
tsi = *prev; tsi = *prev;
else if ( (*next)->getTime()-event_time < event_time-(*prev)->getTime() ) else if ( (*next)->getTicks()-event_ticks < event_ticks-(*prev)->getTicks() )
tsi = *next; tsi = *next;
else else
tsi = *prev; tsi = *prev;
tsi->insert(*i); tsi->insert(*i);
Log::info("Rewind", "Inserting event from time %f type %c to timstepinfo %f prev %f next %f", Log::info("Rewind", "Inserting event from time %d type %c to timstepinfo %d prev %d next %d",
(*i)->getTime(), (*i)->getTicks(),
(*i)->isEvent() ? 'E' : ((*i)->isState() ? 'S' : 'T'), (*i)->isEvent() ? 'E' : ((*i)->isState() ? 'S' : 'T'),
tsi->getTime(), tsi->getTicks(),
(*prev)->getTime(), (*prev)->getTicks(),
next != m_time_step_info.end() ? (*next)->getTime() : 9999 ); next != m_time_step_info.end() ? (*next)->getTicks() : 9999 );
// Check if a rewind is necessary: either an message arrived in the past // Check if a rewind is necessary: either an message arrived in the past
// or if the time is between world_time and world_time+dt (otherwise // or if the time is between world_time and world_time+dt (otherwise
@ -340,11 +340,11 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
// at the time the client is currently simulating (instead of // at the time the client is currently simulating (instead of
// triggering a rollback) it is not ahead enough of the server // triggering a rollback) it is not ahead enough of the server
// which will trigger a time adjustment from the server anyway. // which will trigger a time adjustment from the server anyway.
if (tsi->getTime() < world_time || if (tsi->getTicks() < world_ticks ||
(*i)->isState() && tsi == m_time_step_info.back()) (*i)->isState() && tsi == m_time_step_info.back())
{ {
*needs_rewind = true; *needs_rewind = true;
if (tsi->getTime() > *rewind_time) *rewind_time = tsi->getTime(); if (tsi->getTicks() > *rewind_ticks) *rewind_ticks = tsi->getTicks();
} }
} // if client } // if client
i = m_network_events.getData().erase(i); i = m_network_events.getData().erase(i);
@ -377,18 +377,9 @@ bool RewindQueue::hasMoreRewindInfo() const
* return a dt that would be bigger tham this value. * return a dt that would be bigger tham this value.
* \return The time step size to use in the next simulation step. * \return The time step size to use in the next simulation step.
*/ */
float RewindQueue::determineNextDT(float end_time) float RewindQueue::determineNextDT()
{ {
// If there is a next state (which is known to have a different time) return stk_config->ticks2Time(1);
// use the time difference to determine the time step size.
if(m_current !=m_time_step_info.end())
return (*m_current)->getTime() - World::getWorld()->getTime();
// Otherwise, i.e. we are rewinding the last state/event, take the
// difference between that time and the world time at which the rewind
// was triggered.
return end_time - (*(--m_current))->getTime();
} // determineNextDT } // determineNextDT
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -400,7 +391,7 @@ float RewindQueue::determineNextDT(float end_time)
* m_current is pointing to is ignored. * m_current is pointing to is ignored.
* \param undo_time To what at least events need to be undone. * \param undo_time To what at least events need to be undone.
*/ */
void RewindQueue::undoUntil(float undo_time) void RewindQueue::undoUntil(int undo_ticks)
{ {
while (m_current != m_time_step_info.begin()) while (m_current != m_time_step_info.begin())
{ {
@ -408,7 +399,7 @@ void RewindQueue::undoUntil(float undo_time)
// Undo all events and states from the current time // Undo all events and states from the current time
(*m_current)->undoAll(); (*m_current)->undoAll();
if ((*m_current)->getTime() <= undo_time && if ((*m_current)->getTicks() <= undo_ticks &&
(*m_current)->hasConfirmedState()) (*m_current)->hasConfirmedState())
{ {
return; return;
@ -416,8 +407,8 @@ void RewindQueue::undoUntil(float undo_time)
} // while m_current!=m_time_step_info.begin() } // while m_current!=m_time_step_info.begin()
Log::error("RewindManager", "No state for rewind to %f", Log::error("RewindManager", "No state for rewind to %d",
undo_time); undo_ticks);
} // undoUntil } // undoUntil
@ -456,45 +447,45 @@ void RewindQueue::unitTesting()
assert(q0.isEmpty()); assert(q0.isEmpty());
assert(!q0.hasMoreRewindInfo()); assert(!q0.hasMoreRewindInfo());
q0.addNewTimeStep(0.0f, 0.5f); q0.addNewTimeStep(0, 0.5f);
q0.m_current = q0.m_time_step_info.begin(); q0.m_current = q0.m_time_step_info.begin();
assert(!q0.isEmpty()); assert(!q0.isEmpty());
assert(q0.hasMoreRewindInfo()); assert(q0.hasMoreRewindInfo());
assert(q0.m_time_step_info.size() == 1); assert(q0.m_time_step_info.size() == 1);
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 0); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 0);
q0.addLocalState(NULL, NULL, true, 0.0f); q0.addLocalState(NULL, NULL, true, 0);
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1);
q0.addNewTimeStep(1.0f, 0.5f); q0.addNewTimeStep(1, 0.5f);
assert(q0.m_time_step_info.size() == 2); assert(q0.m_time_step_info.size() == 2);
q0.addNetworkEvent(dummy_rewinder, NULL, 0.0f); q0.addNetworkEvent(dummy_rewinder, NULL, 0);
bool needs_rewind; bool needs_rewind;
float rewind_time; int rewind_ticks;
float world_time = 0.0f; int world_ticks = 0;
float dt = 0.01f; float dt = 0.01f;
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 1);
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time); q0.mergeNetworkData(world_ticks, dt, &needs_rewind, &rewind_ticks);
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 2); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 2);
// This will be added to timestep 0 // This will be added to timestep 0
q0.addNetworkEvent(dummy_rewinder, NULL, 0.2f); q0.addNetworkEvent(dummy_rewinder, NULL, 2);
dt = 0.01f; // to small, event from 0.2 will not be merged dt = 0.01f; // to small, event from 0.2 will not be merged
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time); q0.mergeNetworkData(world_ticks, dt, &needs_rewind, &rewind_ticks);
assert(q0.m_time_step_info.size() == 2); assert(q0.m_time_step_info.size() == 2);
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 2); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 2);
dt = 0.3f; dt = 0.3f;
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time); q0.mergeNetworkData(world_ticks, dt, &needs_rewind, &rewind_ticks);
assert(q0.m_time_step_info.size() == 2); assert(q0.m_time_step_info.size() == 2);
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 3); assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 3);
// This event will get added to the last time step info at 1.0: // This event will get added to the last time step info at 1.0:
q0.addNetworkEvent(dummy_rewinder, NULL, 1.0f); q0.addNetworkEvent(dummy_rewinder, NULL, 1);
world_time = 0.8f; world_ticks = 8;
dt = 0.3f; dt = 0.3f;
q0.mergeNetworkData(world_time, dt, &needs_rewind, &rewind_time); q0.mergeNetworkData(world_ticks, dt, &needs_rewind, &rewind_ticks);
// Note that end() is behind the list, i.e. invalid, but rbegin() // Note that end() is behind the list, i.e. invalid, but rbegin()
// is the last element // is the last element
assert((*q0.m_time_step_info.rbegin())->getNumberOfEvents() == 1); assert((*q0.m_time_step_info.rbegin())->getNumberOfEvents() == 1);
@ -504,10 +495,10 @@ void RewindQueue::unitTesting()
// 1) Current pointer was not reset from end of list when an event // 1) Current pointer was not reset from end of list when an event
// was added and the pointer was already at end of list // was added and the pointer was already at end of list
RewindQueue b1; RewindQueue b1;
b1.addNewTimeStep(1.0f, 0.1f); b1.addNewTimeStep(1, 0.1f);
++b1; // Should now point at end of list ++b1; // Should now point at end of list
b1.hasMoreRewindInfo(); b1.hasMoreRewindInfo();
b1.addNewTimeStep(2.0f, 0.1f); b1.addNewTimeStep(2, 0.1f);
TimeStepInfo *tsi = b1.getCurrent(); TimeStepInfo *tsi = b1.getCurrent();
assert(tsi->getTime() == 2.0f); assert(tsi->getTicks() == 2);
} // unitTesting } // unitTesting

View File

@ -55,7 +55,7 @@ private:
* always be at the same time as World::getTime(). */ * always be at the same time as World::getTime(). */
AllTimeStepInfo::iterator m_current; AllTimeStepInfo::iterator m_current;
AllTimeStepInfo::iterator findPreviousTimeStepInfo(float t); AllTimeStepInfo::iterator findPreviousTimeStepInfo(int ticks);
void insertRewindInfo(RewindInfo *ri); void insertRewindInfo(RewindInfo *ri);
struct _TimeStepInfoCompare struct _TimeStepInfoCompare
@ -73,21 +73,21 @@ public:
RewindQueue(); RewindQueue();
~RewindQueue(); ~RewindQueue();
void reset(); void reset();
void addNewTimeStep(float time, float dt); void addNewTimeStep(int ticks, float dt);
void addLocalEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, void addLocalEvent(EventRewinder *event_rewinder, BareNetworkString *buffer,
bool confirmed, float time); bool confirmed, int ticks);
void addLocalState(Rewinder *rewinder, BareNetworkString *buffer, void addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
bool confirmed, float time); bool confirmed, int ticks);
void addNetworkEvent(EventRewinder *event_rewinder, void addNetworkEvent(EventRewinder *event_rewinder,
BareNetworkString *buffer, float time); BareNetworkString *buffer, int ticks);
void addNetworkState(Rewinder *rewinder, BareNetworkString *buffer, void addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
float time, float dt); int ticks, float dt);
void mergeNetworkData(float world_time, float dt, void mergeNetworkData(int world_ticks, float dt,
bool *needs_rewind, float *rewind_time); bool *needs_rewind, int *rewind_ticks);
bool isEmpty() const; bool isEmpty() const;
bool hasMoreRewindInfo() const; bool hasMoreRewindInfo() const;
void undoUntil(float undo_time); void undoUntil(int undo_ticks);
float determineNextDT(float max_time); float determineNextDT();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the last (i.e. newest) entry in the TimeStepInfo list. This is /** Returns the last (i.e. newest) entry in the TimeStepInfo list. This is
* used for rewinds, since it's the first TimeStep that must not be * used for rewinds, since it's the first TimeStep that must not be

View File

@ -25,9 +25,9 @@
* \param time Time for this TimeStepInfo object. * \param time Time for this TimeStepInfo object.
* \param dt Time step size. * \param dt Time step size.
*/ */
TimeStepInfo::TimeStepInfo(float time, float dt) TimeStepInfo::TimeStepInfo(int ticks, float dt)
{ {
m_time = time; m_ticks = ticks;
m_dt = dt; m_dt = dt;
// In case of unit testing physics does not exist // In case of unit testing physics does not exist
if (Physics::getInstance()) if (Physics::getInstance())

View File

@ -53,7 +53,7 @@ private:
AllRewindInfo m_list_of_events; AllRewindInfo m_list_of_events;
/** Time at which those events should be executed here. */ /** Time at which those events should be executed here. */
float m_time; int m_ticks;
/** Time step to be used. */ /** Time step to be used. */
float m_dt; float m_dt;
@ -62,20 +62,20 @@ private:
* 60 fps. Restoring this value exactly improves accuracy of rewinds. */ * 60 fps. Restoring this value exactly improves accuracy of rewinds. */
float m_local_physics_time; float m_local_physics_time;
public: public:
TimeStepInfo(float time, float dt); TimeStepInfo(int ticks, float dt);
void insert(RewindInfo *ri); void insert(RewindInfo *ri);
void undoAll(); void undoAll();
void replayAllEvents(); void replayAllEvents();
void replayAllStates(); void replayAllStates();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets the tiem of this object. */ /** Sets the tiem of this object. */
void setTime(float time) { m_time = time; } void setTicks(int ticks) { m_ticks = ticks; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets the time step size of this object. */ /** Sets the time step size of this object. */
void setDT(float dt) { m_dt = dt; } void setDT(float dt) { m_dt = dt; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the time for this TimeStepInfo instance. */ /** Returns the time for this TimeStepInfo instance. */
float getTime() const { return m_time; } int getTicks() const { return m_ticks; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the left-over physics time. */ /** Returns the left-over physics time. */
float getLocalPhysicsTime() const { return m_local_physics_time; } float getLocalPhysicsTime() const { return m_local_physics_time; }

View File

@ -154,7 +154,7 @@ void Physics::update(float dt)
// Since the world update (which calls physics update) is called at the // Since the world update (which calls physics update) is called at the
// fixed frequency necessary for the physics update, we need to do exactly // fixed frequency necessary for the physics update, we need to do exactly
// one physic step only. // one physic step only.
m_dynamics_world->stepSimulation(dt, 1, 1.0f / stk_config->m_physics_fps); m_dynamics_world->stepSimulation(dt, 1, stk_config->ticks2Time(1));
// Now handle the actual collision. Note: flyables can not be removed // Now handle the actual collision. Note: flyables can not be removed
// inside of this loop, since the same flyables might hit more than one // inside of this loop, since the same flyables might hit more than one

View File

@ -493,7 +493,8 @@ void RaceGUIBase::drawGlobalMusicDescription()
gui::IGUIFont* font = GUIEngine::getFont(); gui::IGUIFont* font = GUIEngine::getFont();
float race_time = World::getWorld()->getTimeSinceStart(); float race_time =
stk_config->ticks2Time(World::getWorld()->getTicksSinceStart());
// ---- Manage pulsing effect // ---- Manage pulsing effect
// 3.0 is the duration of ready/set (TODO: don't hardcode) // 3.0 is the duration of ready/set (TODO: don't hardcode)

View File

@ -168,7 +168,9 @@ void addAttachment(Attachment::AttachmentType type)
if (type == Attachment::ATTACH_ANVIL) if (type == Attachment::ATTACH_ANVIL)
{ {
kart->getAttachment() kart->getAttachment()
->set(type, kart->getKartProperties()->getAnvilDuration()); ->set(type,
stk_config->time2Ticks(kart->getKartProperties()
->getAnvilDuration()) );
kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor());
kart->updateWeight(); kart->updateWeight();
} }
@ -180,7 +182,7 @@ void addAttachment(Attachment::AttachmentType type)
else if (type == Attachment::ATTACH_BOMB) else if (type == Attachment::ATTACH_BOMB)
{ {
kart->getAttachment() kart->getAttachment()
->set(type, stk_config->m_bomb_time); ->set(type, stk_config->time2Ticks(stk_config->m_bomb_time) );
} }
} }

View File

@ -20,9 +20,11 @@
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "config/stk_config.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/time.hpp" #include "utils/time.hpp"
#include "utils/utf8.h" #include "utils/utf8.h"
#include "coreutil.h" #include "coreutil.h"
#include <algorithm> #include <algorithm>
@ -489,6 +491,12 @@ namespace StringUtils
} }
} }
// ------------------------------------------------------------------------
/** Returns the time (in seconds) as string, based on ticks. */
std::string ticksTimeToString(int ticks)
{
return timeToString(stk_config->ticks2Time(ticks));
} // ticksTimeToString(ticks)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Converts a time in seconds into a string of the form mm:ss:hh (minutes, /** Converts a time in seconds into a string of the form mm:ss:hh (minutes,

View File

@ -45,6 +45,7 @@ namespace StringUtils
std::string getExtension(const std::string& filename); std::string getExtension(const std::string& filename);
bool notEmpty(const irr::core::stringw& input); bool notEmpty(const irr::core::stringw& input);
std::string ticksTimeToString(int time);
std::string timeToString(float time); std::string timeToString(float time);
irr::core::stringw loadingDots(float interval = 0.5f, int max_dots = 3); irr::core::stringw loadingDots(float interval = 0.5f, int max_dots = 3);
irr::core::stringw loadingDots(const wchar_t *s); irr::core::stringw loadingDots(const wchar_t *s);