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:
commit
d3a60356c9
@ -59,9 +59,11 @@ public:
|
||||
* - 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
|
||||
* has the same type as the currently held item. */
|
||||
enum {POWERUP_MODE_NEW,
|
||||
enum {
|
||||
POWERUP_MODE_NEW,
|
||||
POWERUP_MODE_SAME,
|
||||
POWERUP_MODE_ONLY_IF_SAME}
|
||||
POWERUP_MODE_ONLY_IF_SAME
|
||||
}
|
||||
m_same_powerup_mode;
|
||||
|
||||
static float UNDEFINED;
|
||||
@ -105,9 +107,6 @@ public:
|
||||
/** Default friction to be used for any moveable, e.g. karts, balls. */
|
||||
float m_default_moveable_friction;
|
||||
|
||||
/** Default FPS rate for physics. */
|
||||
int m_physics_fps;
|
||||
|
||||
int m_max_skidmarks; /**<Maximum number of skid marks/kart. */
|
||||
float m_skid_fadeout_time; /**<Time till skidmarks fade away. */
|
||||
float m_near_ground; /**<Determines when a kart is not near
|
||||
@ -182,6 +181,10 @@ private:
|
||||
* loaded a user specified config file. */
|
||||
bool m_has_been_loaded;
|
||||
|
||||
/** Default FPS rate for physics. */
|
||||
int m_physics_fps;
|
||||
|
||||
|
||||
public:
|
||||
STKConfig();
|
||||
~STKConfig();
|
||||
@ -190,6 +193,7 @@ public:
|
||||
void load(const std::string &filename);
|
||||
const std::string &getMainMenuPicture(int n);
|
||||
const std::string &getBackgroundPicture(int n);
|
||||
|
||||
void getAllScores(std::vector<int> *all_scores, int num_karts);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the default kart properties for each kart. */
|
||||
@ -205,6 +209,15 @@ public:
|
||||
{
|
||||
return *m_kart_properties.at(type);
|
||||
} // 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
|
||||
|
||||
|
@ -167,8 +167,8 @@ void Camera::setupCamera()
|
||||
m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight()));
|
||||
|
||||
m_scaling = core::vector2df(
|
||||
irr_driver->getActualScreenSize().Width / m_viewport.getWidth() ,
|
||||
irr_driver->getActualScreenSize().Height / m_viewport.getHeight());
|
||||
float(irr_driver->getActualScreenSize().Width) / m_viewport.getWidth() ,
|
||||
float(irr_driver->getActualScreenSize().Height) / m_viewport.getHeight());
|
||||
|
||||
m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov
|
||||
[race_manager->getNumLocalPlayers() > 0 ?
|
||||
|
@ -921,7 +921,7 @@ SColorf GetPlayerColor(int player_id)
|
||||
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);
|
||||
return color_rgb;
|
||||
}
|
||||
@ -1161,9 +1161,9 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget,
|
||||
|
||||
SColorf color_rgb = GetPlayerColor(i);
|
||||
|
||||
parentRibbonWidget->m_skin_r = color_rgb.r * 255.0F;
|
||||
parentRibbonWidget->m_skin_g = color_rgb.g * 255.0F;
|
||||
parentRibbonWidget->m_skin_b = color_rgb.b * 255.0F;
|
||||
parentRibbonWidget->m_skin_r = short(color_rgb.r * 255.0f);
|
||||
parentRibbonWidget->m_skin_g = short(color_rgb.g * 255.0f);
|
||||
parentRibbonWidget->m_skin_b = short(color_rgb.b * 255.0f);
|
||||
|
||||
if (nPlayersOnThisItem > 0)
|
||||
{
|
||||
@ -1270,9 +1270,9 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
|
||||
{
|
||||
params=&SkinConfig::m_render_params["spinner::neutral"];
|
||||
}
|
||||
widget->m_skin_r = color_rgb.r * 255.0f;
|
||||
widget->m_skin_g = color_rgb.g * 255.0f;
|
||||
widget->m_skin_b = color_rgb.b * 255.0f;
|
||||
widget->m_skin_r = short(color_rgb.r * 255.0f);
|
||||
widget->m_skin_g = short(color_rgb.g * 255.0f);
|
||||
widget->m_skin_b = short(color_rgb.b * 255.0f);
|
||||
|
||||
for (int i = 1; i < MAX_PLAYER_COUNT + 1; i++)
|
||||
{
|
||||
|
@ -290,14 +290,14 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
case IRR_KEY_F11:
|
||||
if(value && shift_is_pressed && world && RewindManager::isEnabled())
|
||||
{
|
||||
printf("Enter rewind to time:");
|
||||
printf("Enter rewind to time in ticks:");
|
||||
char s[256];
|
||||
fgets(s, 256, stdin);
|
||||
float t;
|
||||
int t;
|
||||
StringUtils::fromString(s,t);
|
||||
RewindManager::get()->rewindTo(t);
|
||||
Log::info("Rewind", "Rewinding from %f to %f",
|
||||
world->getTime(), t);
|
||||
Log::info("Rewind", "Rewinding from %d to %d",
|
||||
world->getTimeTicks(), t);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -49,7 +49,7 @@ Attachment::Attachment(AbstractKart* kart)
|
||||
: EventRewinder()
|
||||
{
|
||||
m_type = ATTACH_NOTHING;
|
||||
m_time_left = 0.0;
|
||||
m_ticks_left = 0;
|
||||
m_plugin = NULL;
|
||||
m_kart = kart;
|
||||
m_previous_owner = NULL;
|
||||
@ -103,7 +103,7 @@ Attachment::~Attachment()
|
||||
* can be passed back to the previous owner). NULL if a no
|
||||
* previous owner exists.
|
||||
*/
|
||||
void Attachment::set(AttachmentType type, float time,
|
||||
void Attachment::set(AttachmentType type, int ticks,
|
||||
AbstractKart *current_kart)
|
||||
{
|
||||
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_type = type;
|
||||
m_time_left = time;
|
||||
m_ticks_left = ticks;
|
||||
m_previous_owner = current_kart;
|
||||
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));
|
||||
|
||||
m_time_left = m_time_left * speed_mult;
|
||||
m_ticks_left = int(m_ticks_left * speed_mult);
|
||||
|
||||
if (UserConfigParams::m_particles_effects > 1)
|
||||
{
|
||||
@ -230,7 +230,7 @@ void Attachment::clear()
|
||||
|
||||
m_type=ATTACH_NOTHING;
|
||||
|
||||
m_time_left=0.0;
|
||||
m_ticks_left = 0;
|
||||
m_node->setVisible(false);
|
||||
m_node->setPosition(core::vector3df());
|
||||
m_node->setRotation(core::vector3df());
|
||||
@ -254,7 +254,7 @@ void Attachment::saveState(BareNetworkString *buffer) const
|
||||
buffer->addUInt8(type);
|
||||
if(m_type!=ATTACH_NOTHING)
|
||||
{
|
||||
buffer->addFloat(m_time_left);
|
||||
buffer->addUInt32(m_ticks_left);
|
||||
if(m_type==ATTACH_BOMB && m_previous_owner)
|
||||
buffer->addUInt8(m_previous_owner->getWorldKartId());
|
||||
// m_initial_speed is not saved, on restore state it will
|
||||
@ -284,13 +284,13 @@ void Attachment::rewindTo(BareNetworkString *buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
float time_left = buffer->getFloat();
|
||||
int ticks_left = buffer->getUInt32();
|
||||
|
||||
// Attaching an object can be expensive (loading new models, ...)
|
||||
// so avoid doing this if there is no change in attachment type
|
||||
if(new_type == m_type)
|
||||
{
|
||||
setTimeLeft(time_left);
|
||||
setTicksLeft(ticks_left);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ void Attachment::rewindTo(BareNetworkString *buffer)
|
||||
{
|
||||
m_previous_owner = NULL;
|
||||
}
|
||||
set(new_type, time_left, m_previous_owner);
|
||||
set(new_type, ticks_left, m_previous_owner);
|
||||
} // rewindTo
|
||||
// -----------------------------------------------------------------------------
|
||||
/** 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 ||
|
||||
m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD)
|
||||
{
|
||||
m_time_left = 0.0f;
|
||||
m_ticks_left = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
float leftover_time = 0.0f;
|
||||
int leftover_ticks = 0;
|
||||
|
||||
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,
|
||||
// and increase the overall time
|
||||
new_attachment = 1;
|
||||
leftover_time = m_time_left;
|
||||
leftover_ticks = m_ticks_left;
|
||||
break;
|
||||
case ATTACH_PARACHUTE:
|
||||
new_attachment = 0;
|
||||
leftover_time = m_time_left;
|
||||
leftover_ticks = m_ticks_left;
|
||||
break;
|
||||
default:
|
||||
// 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)
|
||||
{
|
||||
case 0:
|
||||
set(ATTACH_PARACHUTE, kp->getParachuteDuration() + leftover_time);
|
||||
set(ATTACH_PARACHUTE, kp->getParachuteDuration() + leftover_ticks);
|
||||
m_initial_speed = m_kart->getSpeed();
|
||||
|
||||
// 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;
|
||||
break ;
|
||||
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] )
|
||||
// sound -> playSfx ( SOUND_SHOOMF ) ;
|
||||
// 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();
|
||||
break ;
|
||||
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 ;
|
||||
} // switch
|
||||
}
|
||||
@ -446,8 +446,8 @@ void Attachment::handleCollisionWithKart(AbstractKart *other)
|
||||
// If both karts have a bomb, explode them immediately:
|
||||
if(attachment_other->getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
setTimeLeft(0.0f);
|
||||
attachment_other->setTimeLeft(0.0f);
|
||||
setTicksLeft(0);
|
||||
attachment_other->setTicksLeft(0);
|
||||
}
|
||||
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)
|
||||
{
|
||||
// Don't move if this bomb was from other kart originally
|
||||
other->getAttachment()->set(ATTACH_BOMB,
|
||||
getTimeLeft()+
|
||||
stk_config->m_bomb_time_increase,
|
||||
other->getAttachment()
|
||||
->set(ATTACH_BOMB,
|
||||
getTicksLeft()+stk_config->time2Ticks(
|
||||
stk_config->m_bomb_time_increase),
|
||||
m_kart);
|
||||
other->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
clear();
|
||||
@ -473,8 +474,10 @@ void Attachment::handleCollisionWithKart(AbstractKart *other)
|
||||
m_kart->decreaseShieldTime();
|
||||
return;
|
||||
}
|
||||
set(ATTACH_BOMB, other->getAttachment()->getTimeLeft()+
|
||||
stk_config->m_bomb_time_increase, other);
|
||||
set(ATTACH_BOMB,
|
||||
other->getAttachment()->getTicksLeft()+
|
||||
stk_config->time2Ticks(stk_config->m_bomb_time_increase),
|
||||
other);
|
||||
other->getAttachment()->clear();
|
||||
m_kart->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
}
|
||||
@ -496,7 +499,7 @@ void Attachment::update(float dt)
|
||||
if (m_type == ATTACH_BOMB && m_kart->getKartAnimation() != NULL)
|
||||
return;
|
||||
|
||||
m_time_left -=dt;
|
||||
m_ticks_left--; // dt always physics time step
|
||||
|
||||
|
||||
bool is_shield = m_type == ATTACH_BUBBLEGUM_SHIELD ||
|
||||
@ -504,20 +507,23 @@ void Attachment::update(float dt)
|
||||
float m_wanted_node_scale = is_shield
|
||||
? std::max(1.0f, m_kart->getHighestPoint()*1.1f)
|
||||
: 1.0f;
|
||||
int slow_flashes = 3;
|
||||
if (is_shield && m_time_left < slow_flashes)
|
||||
int slow_flashes = stk_config->time2Ticks(3.0f);
|
||||
if (is_shield && m_ticks_left < slow_flashes)
|
||||
{
|
||||
int flashes_per_second = 4;
|
||||
int divisor = 2;
|
||||
int ticks_per_flash = stk_config->time2Ticks(0.25f);
|
||||
|
||||
float fast_flashes = 0.5F;
|
||||
if (m_time_left < fast_flashes)
|
||||
int fast_flashes = stk_config->time2Ticks(0.5f);
|
||||
if (m_ticks_left < fast_flashes)
|
||||
{
|
||||
flashes_per_second = 12;
|
||||
ticks_per_flash = stk_config->time2Ticks(1.0f/12);
|
||||
}
|
||||
|
||||
int mod = (int)(m_time_left * flashes_per_second * 2) % divisor;
|
||||
m_node->setVisible(2*mod >= divisor);
|
||||
//int divisor = 2;
|
||||
//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)
|
||||
@ -558,7 +564,7 @@ void Attachment::update(float dt)
|
||||
f * (kp->getParachuteUboundFraction()
|
||||
- kp->getParachuteLboundFraction())))
|
||||
{
|
||||
m_time_left = -1;
|
||||
m_ticks_left = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -576,18 +582,19 @@ void Attachment::update(float dt)
|
||||
assert(false);
|
||||
break;
|
||||
case ATTACH_BOMB:
|
||||
|
||||
{
|
||||
if (m_bomb_sound) m_bomb_sound->setPosition(m_kart->getXYZ());
|
||||
|
||||
// Mesh animation frames are 1 to 61 frames (60 steps)
|
||||
// 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(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->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",
|
||||
"explosion_bomb.xml");
|
||||
@ -603,11 +610,12 @@ void Attachment::update(float dt)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTACH_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();
|
||||
m_bubble_explode_sound =
|
||||
SFXManager::get()->createSoundSource("bubblegum_explode");
|
||||
@ -638,7 +646,7 @@ void Attachment::update(float dt)
|
||||
} // switch
|
||||
|
||||
// Detach attachment if its time is up.
|
||||
if ( m_time_left <= 0.0f)
|
||||
if ( m_ticks_left <= 0)
|
||||
clear();
|
||||
} // update
|
||||
|
||||
|
@ -78,7 +78,7 @@ private:
|
||||
AbstractKart *m_kart;
|
||||
|
||||
/** Time left till attachment expires. */
|
||||
float m_time_left;
|
||||
int m_ticks_left;
|
||||
|
||||
/** For parachutes only. */
|
||||
float m_initial_speed;
|
||||
@ -114,7 +114,7 @@ public:
|
||||
void hitBanana(Item *item, int new_attachment=-1);
|
||||
void update (float dt);
|
||||
void handleCollisionWithKart(AbstractKart *other);
|
||||
void set (AttachmentType type, float time,
|
||||
void set (AttachmentType type, int ticks,
|
||||
AbstractKart *previous_kart=NULL);
|
||||
virtual void rewind(BareNetworkString *buffer);
|
||||
void rewindTo(BareNetworkString *buffer);
|
||||
@ -122,16 +122,17 @@ public:
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** 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. */
|
||||
AttachmentType getType() const { return m_type; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how much time is left before this attachment is removed. */
|
||||
float getTimeLeft() const { return m_time_left; }
|
||||
/** Returns how much time (in ticks) is left before this attachment is
|
||||
* removed. */
|
||||
int getTicksLeft() const { return m_ticks_left; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** 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
|
||||
* are being passed between karts. */
|
||||
|
@ -267,7 +267,8 @@ void Powerup::use()
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_SWATTER, kp->getSwatterDuration());
|
||||
->set(Attachment::ATTACH_SWATTER,
|
||||
stk_config->time2Ticks(kp->getSwatterDuration()));
|
||||
break;
|
||||
|
||||
case PowerupManager::POWERUP_BUBBLEGUM:
|
||||
@ -302,26 +303,35 @@ void Powerup::use()
|
||||
{
|
||||
if (m_kart->getIdent() == "nolok")
|
||||
{
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration());
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
stk_config->
|
||||
time2Ticks(kp->getBubblegumShieldDuration()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration());
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
stk_config->
|
||||
time2Ticks(kp->getBubblegumShieldDuration()));
|
||||
}
|
||||
}
|
||||
else // using a bubble gum while still having a shield
|
||||
{
|
||||
if (m_kart->getIdent() == "nolok")
|
||||
{
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_kart->getShieldTime());
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
stk_config->
|
||||
time2Ticks(kp->getBubblegumShieldDuration()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_kart->getShieldTime());
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
stk_config->
|
||||
time2Ticks(kp->getBubblegumShieldDuration()
|
||||
+ m_kart->getShieldTime() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +360,8 @@ void Powerup::use()
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
kart->getAttachment()->set(Attachment::ATTACH_ANVIL,
|
||||
kp->getAnvilDuration());
|
||||
stk_config->
|
||||
time2Ticks(kp->getAnvilDuration()) );
|
||||
kart->updateWeight();
|
||||
kart->adjustSpeed(kp->getAnvilSpeedFactor() * 0.5f);
|
||||
|
||||
@ -397,14 +408,17 @@ void Powerup::use()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
rank_mult = 1 + (position_factor * (kp->getParachuteDurationRankMult() - 1));
|
||||
rank_mult = 1 + (position_factor *
|
||||
(kp->getParachuteDurationRankMult() - 1));
|
||||
|
||||
kart->getAttachment()->set(Attachment::ATTACH_PARACHUTE,
|
||||
(kp->getParachuteDurationOther() * rank_mult));
|
||||
kart->getAttachment()
|
||||
->set(Attachment::ATTACH_PARACHUTE,
|
||||
int(kp->getParachuteDurationOther()*rank_mult) );
|
||||
|
||||
if(kart->getController()->isLocalPlayerController())
|
||||
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,
|
||||
// reset the bBallCollectTime to 0 before giving new powerup.
|
||||
if(m_type == PowerupManager::POWERUP_RUBBERBALL)
|
||||
powerup_manager->setBallCollectTime(0);
|
||||
powerup_manager->setBallCollectTicks(0);
|
||||
|
||||
// Check if two bouncing balls are collected less than getRubberBallTimer()
|
||||
//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);
|
||||
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
|
||||
( World::getWorld()->getTimeSinceStart() - powerup_manager->getBallCollectTime()) >
|
||||
RubberBall::getTimeBetweenRubberBalls() )
|
||||
( World::getWorld()->getTicksSinceStart() - powerup_manager->getBallCollectTicks()) >
|
||||
RubberBall::getTicksBetweenRubberBalls() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -486,7 +500,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
|
||||
}
|
||||
|
||||
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
|
||||
// doesn't have a powerup atm).
|
||||
|
@ -113,7 +113,7 @@ private:
|
||||
float m_all_max_turn_angle[POWERUP_MAX];
|
||||
|
||||
/** Last time the bouncing ball was collected */
|
||||
float m_rubber_ball_collect_time;
|
||||
int m_rubber_ball_collect_ticks;
|
||||
|
||||
public:
|
||||
/** 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];}
|
||||
const btVector3&
|
||||
getExtend (int type) const {return m_all_extends[type];}
|
||||
float getBallCollectTime() const {return m_rubber_ball_collect_time;}
|
||||
void setBallCollectTime(float time) {m_rubber_ball_collect_time=time;}
|
||||
int getBallCollectTicks() const {return m_rubber_ball_collect_ticks;}
|
||||
void setBallCollectTicks(int ticks) {m_rubber_ball_collect_ticks=ticks;}
|
||||
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,7 @@ float RubberBall::m_st_max_height_difference;
|
||||
float RubberBall::m_st_fast_ping_distance;
|
||||
float RubberBall::m_st_early_target_factor;
|
||||
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.
|
||||
@ -272,7 +272,7 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
|
||||
m_st_max_height_difference = 10.0f;
|
||||
m_st_fast_ping_distance = 50.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))
|
||||
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))
|
||||
Log::warn("powerup",
|
||||
"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",
|
||||
"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);
|
||||
} // init
|
||||
|
||||
|
@ -84,7 +84,7 @@ private:
|
||||
/** 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
|
||||
* 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
|
||||
* 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 hit(AbstractKart* kart, PhysicalObject* obj=NULL);
|
||||
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
|
||||
* karts are handled by this hit() function. */
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/interpolation_array.hpp"
|
||||
|
||||
@ -931,7 +932,7 @@ float AbstractCharacteristic::getParachuteFriction() const
|
||||
} // getParachuteFriction
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getParachuteDuration() const
|
||||
int AbstractCharacteristic::getParachuteDuration() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
@ -939,11 +940,11 @@ float AbstractCharacteristic::getParachuteDuration() const
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(PARACHUTE_DURATION).c_str());
|
||||
return result;
|
||||
return stk_config->time2Ticks(result);
|
||||
} // getParachuteDuration
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getParachuteDurationOther() const
|
||||
int AbstractCharacteristic::getParachuteDurationOther() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
@ -951,7 +952,7 @@ float AbstractCharacteristic::getParachuteDurationOther() const
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(PARACHUTE_DURATION_OTHER).c_str());
|
||||
return result;
|
||||
return stk_config->time2Ticks(result);
|
||||
} // getParachuteDurationOther
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -305,8 +305,8 @@ public:
|
||||
float getAnvilSpeedFactor() const;
|
||||
|
||||
float getParachuteFriction() const;
|
||||
float getParachuteDuration() const;
|
||||
float getParachuteDurationOther() const;
|
||||
int getParachuteDuration() const;
|
||||
int getParachuteDurationOther() const;
|
||||
float getParachuteDurationRankMult() const;
|
||||
float getParachuteDurationSpeedMult() const;
|
||||
float getParachuteLboundFraction() const;
|
||||
|
@ -48,7 +48,7 @@ AIBaseController::AIBaseController(AbstractKart *kart)
|
||||
void AIBaseController::reset()
|
||||
{
|
||||
m_stuck = false;
|
||||
m_collision_times.clear();
|
||||
m_collision_ticks.clear();
|
||||
} // 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
|
||||
// time for the AI to accelerate and hit the terrain again).
|
||||
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();
|
||||
if(m_collision_times.size()==0)
|
||||
int ticks = World::getWorld()->getTicksSinceStart();
|
||||
if(m_collision_ticks.size()==0)
|
||||
{
|
||||
m_collision_times.push_back(time);
|
||||
m_collision_ticks.push_back(ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -252,23 +252,24 @@ void AIBaseController::crashed(const Material *m)
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
// Remove all outdated entries, i.e. entries that are older than the
|
||||
// collision time plus 1 second. Older entries must be deleted,
|
||||
// otherwise a collision that happened (say) 10 seconds ago could
|
||||
// contribute to a stuck condition.
|
||||
while(m_collision_times.size()>0 &&
|
||||
time - m_collision_times[0] > 1.0f+COLLISION_TIME)
|
||||
m_collision_times.erase(m_collision_times.begin());
|
||||
while(m_collision_ticks.size()>0 &&
|
||||
ticks - m_collision_ticks[0] > stk_config->time2Ticks(1.0f)
|
||||
+ 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
|
||||
// specified time interval.
|
||||
if(time - m_collision_times.front() > COLLISION_TIME
|
||||
&& m_collision_times.size()>=NUM_COLLISION)
|
||||
if(ticks - m_collision_ticks.front() > COLLISION_TICKS &&
|
||||
m_collision_ticks.size()>=NUM_COLLISION )
|
||||
{
|
||||
// We can't call m_kart->forceRescue here, since crased() is
|
||||
// called during physics processing, and forceRescue() removes the
|
||||
|
@ -36,7 +36,7 @@ private:
|
||||
/** 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
|
||||
* 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
|
||||
* this kart is stuck and needs to be rescued. */
|
||||
|
@ -357,7 +357,7 @@ void Kart::reset()
|
||||
m_has_started = false;
|
||||
m_bounce_back_time = 0.0f;
|
||||
m_brake_time = 0.0f;
|
||||
m_time_last_crash = 0.0f;
|
||||
m_ticks_last_crash = 0;
|
||||
m_speed = 0.0f;
|
||||
m_smoothed_speed = 0.0f;
|
||||
m_current_lean = 0.0f;
|
||||
@ -1051,7 +1051,7 @@ void Kart::collectedItem(Item *item, int add_info)
|
||||
*/
|
||||
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();
|
||||
for (unsigned int i = 0; i < startup_times.size(); i++)
|
||||
{
|
||||
@ -1110,16 +1110,16 @@ bool Kart::isNearGround() const
|
||||
} // 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)
|
||||
{
|
||||
if(isShielded())
|
||||
{
|
||||
getAttachment()->setTimeLeft(t);
|
||||
}
|
||||
getAttachment()->setTicksLeft(stk_config->time2Ticks(t));
|
||||
}
|
||||
} // setShieldTime
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns true if the kart is protected by a shield.
|
||||
@ -1145,7 +1145,7 @@ bool Kart::isShielded() const
|
||||
float Kart::getShieldTime() const
|
||||
{
|
||||
if (isShielded())
|
||||
return getAttachment()->getTimeLeft();
|
||||
return stk_config->ticks2Time(getAttachment()->getTicksLeft());
|
||||
else
|
||||
return 0.0f;
|
||||
} // getShieldTime
|
||||
@ -1159,7 +1159,7 @@ void Kart::decreaseShieldTime()
|
||||
{
|
||||
if (isShielded())
|
||||
{
|
||||
getAttachment()->setTimeLeft(0.0f);
|
||||
getAttachment()->setTicksLeft(0);
|
||||
}
|
||||
} // decreaseShieldTime
|
||||
|
||||
@ -2193,9 +2193,10 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
|
||||
*/
|
||||
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
|
||||
// can 'bounce back' a bit (without this the engine force will prevent
|
||||
// karts from bouncing back, they will instead stuck towards the obstable).
|
||||
|
@ -223,7 +223,7 @@ protected:
|
||||
SFXBuffer *m_crash_sounds[CRASH_SOUND_COUNT];
|
||||
SFXBuffer *m_goo_sound;
|
||||
SFXBuffer *m_boing_sound;
|
||||
float m_time_last_crash;
|
||||
int m_ticks_last_crash;
|
||||
RaceManager::KartType m_type;
|
||||
|
||||
/** To prevent using nitro in too short bursts */
|
||||
|
@ -773,13 +773,13 @@ float KartProperties::getParachuteFriction() const
|
||||
} // getParachuteFriction
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getParachuteDuration() const
|
||||
int KartProperties::getParachuteDuration() const
|
||||
{
|
||||
return m_cached_characteristic->getParachuteDuration();
|
||||
} // getParachuteDuration
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getParachuteDurationOther() const
|
||||
int KartProperties::getParachuteDurationOther() const
|
||||
{
|
||||
return m_cached_characteristic->getParachuteDurationOther();
|
||||
} // getParachuteDurationOther
|
||||
|
@ -427,8 +427,8 @@ public:
|
||||
float getAnvilSpeedFactor() const;
|
||||
|
||||
float getParachuteFriction() const;
|
||||
float getParachuteDuration() const;
|
||||
float getParachuteDurationOther() const;
|
||||
int getParachuteDuration() const;
|
||||
int getParachuteDurationOther() const;
|
||||
float getParachuteDurationRankMult() const;
|
||||
float getParachuteDurationSpeedMult() const;
|
||||
float getParachuteLboundFraction() const;
|
||||
|
@ -72,10 +72,12 @@ void Moveable::addError(const Vec3& pos_error,
|
||||
const btQuaternion &rot_error)
|
||||
{
|
||||
m_positional_error += pos_error;
|
||||
#ifdef DEBUG_VISUAL_ERROR
|
||||
Log::info("VisualError", "time %f addError %f %f %f size %f",
|
||||
World::getWorld()->getTime(),
|
||||
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
|
||||
m_positional_error.length());
|
||||
#endif
|
||||
m_rotational_error *= rot_error;
|
||||
} // addError
|
||||
|
||||
@ -96,10 +98,12 @@ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
{
|
||||
float error = m_positional_error.length();
|
||||
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",
|
||||
World::getWorld()->getTime(),
|
||||
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
|
||||
m_positional_error.length());
|
||||
#endif
|
||||
}
|
||||
#ifndef SERVER_ONLY
|
||||
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;
|
||||
|
@ -273,8 +273,8 @@ void MainLoop::run()
|
||||
PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7);
|
||||
|
||||
left_over_time += getLimitedDt();
|
||||
int num_steps = int(left_over_time * stk_config->m_physics_fps);
|
||||
float dt = 1.0f / stk_config->m_physics_fps;
|
||||
int num_steps = stk_config->time2Ticks(left_over_time);
|
||||
float dt = stk_config->ticks2Time(1);
|
||||
left_over_time -= num_steps * dt ;
|
||||
|
||||
if (STKHost::existHost() &&
|
||||
@ -309,7 +309,7 @@ void MainLoop::run()
|
||||
if (World::getWorld() && RewindManager::get()->isEnabled())
|
||||
{
|
||||
RewindManager::get()
|
||||
->addNextTimeStep(World::getWorld()->getTime(), dt);
|
||||
->addNextTimeStep(World::getWorld()->getTimeTicks(), dt);
|
||||
}
|
||||
|
||||
if (!m_abort)
|
||||
@ -349,7 +349,7 @@ void MainLoop::run()
|
||||
if (World::getWorld() && RewindManager::get()->isEnabled() && i>0)
|
||||
{
|
||||
RewindManager::get()
|
||||
->addNextTimeStep(World::getWorld()->getTime(), dt);
|
||||
->addNextTimeStep(World::getWorld()->getTimeTicks(), dt);
|
||||
}
|
||||
|
||||
// Enable last substep in last iteration
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -49,7 +50,7 @@ LinearWorld::LinearWorld() : WorldWithRank()
|
||||
m_last_lap_sfx = SFXManager::get()->createSoundSource("last_lap_fanfare");
|
||||
m_last_lap_sfx_played = false;
|
||||
m_last_lap_sfx_playing = false;
|
||||
m_fastest_lap = 9999999.9f;
|
||||
m_fastest_lap_ticks = INT_MAX;
|
||||
} // LinearWorld
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -89,6 +90,7 @@ void LinearWorld::reset()
|
||||
WorldWithRank::reset();
|
||||
m_last_lap_sfx_played = false;
|
||||
m_last_lap_sfx_playing = false;
|
||||
m_fastest_lap_ticks = INT_MAX;
|
||||
|
||||
const unsigned int kart_amount = (unsigned int) m_karts.size();
|
||||
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)
|
||||
{
|
||||
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++;
|
||||
m_kart_info[kart_index].m_overall_distance =
|
||||
m_kart_info[kart_index].m_race_lap
|
||||
@ -345,23 +347,23 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
{
|
||||
kart->finishedRace(getTime());
|
||||
}
|
||||
float time_per_lap;
|
||||
int ticks_per_lap;
|
||||
if (kart_info.m_race_lap == 1) // just completed first lap
|
||||
{
|
||||
time_per_lap=getTime();
|
||||
ticks_per_lap = getTimeTicks();
|
||||
}
|
||||
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(time_per_lap < m_fastest_lap && raceHasLaps() &&
|
||||
if(ticks_per_lap < m_fastest_lap_ticks && raceHasLaps() &&
|
||||
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
|
||||
// (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
|
||||
|
||||
kart_info.m_lap_start_time = getTime();
|
||||
kart_info.m_lap_start_ticks = getTimeTicks();
|
||||
kart->getController()->newLap(kart_info.m_race_lap);
|
||||
} // newLap
|
||||
|
||||
@ -422,18 +424,18 @@ float LinearWorld::getEstimatedFinishTime(const int kart_id) const
|
||||
} // 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());
|
||||
return m_kart_info[kart_id].m_time_at_last_lap;
|
||||
} // getTimeAtLapForKart
|
||||
return m_kart_info[kart_id].m_ticks_at_last_lap;
|
||||
} // getTicksAtLapForKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
|
||||
{
|
||||
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
|
||||
// the time of the kart at position 1, since the kart
|
||||
// might have been overtaken by now
|
||||
@ -448,7 +450,7 @@ void LinearWorld::getKartsDisplayInfo(
|
||||
rank_info.lap = -1;
|
||||
|
||||
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() );
|
||||
rank_info.lap = current_lap;
|
||||
|
||||
@ -457,11 +459,11 @@ void LinearWorld::getKartsDisplayInfo(
|
||||
// more laps than current leader --> new leader and
|
||||
// new time computation
|
||||
laps_of_leader = current_lap;
|
||||
time_of_leader = lap_time;
|
||||
ticks_of_leader = lap_ticks;
|
||||
} else if(current_lap == laps_of_leader)
|
||||
{
|
||||
// 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
|
||||
if(laps_of_leader>0 &&
|
||||
(getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f ||
|
||||
(getTimeTicks() - getTicksAtLapForKart(kart->getWorldKartId())<5||
|
||||
rank_info.lap != laps_of_leader) &&
|
||||
raceHasLaps())
|
||||
{ // Display for 5 seconds
|
||||
std::string str;
|
||||
if(position == 1)
|
||||
{
|
||||
str = " " + StringUtils::timeToString(
|
||||
getTimeAtLapForKart(kart->getWorldKartId()) );
|
||||
str = " " + StringUtils::ticksTimeToString(
|
||||
getTicksAtLapForKart(kart->getWorldKartId()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
float timeBehind;
|
||||
timeBehind = (kart_info.m_race_lap==laps_of_leader
|
||||
? getTimeAtLapForKart(kart->getWorldKartId())
|
||||
: getTime())
|
||||
- time_of_leader;
|
||||
str = "+" + StringUtils::timeToString(timeBehind);
|
||||
int ticks_behind;
|
||||
ticks_behind = (kart_info.m_race_lap==laps_of_leader
|
||||
? getTicksAtLapForKart(kart->getWorldKartId())
|
||||
: getTimeTicks())
|
||||
- ticks_of_leader;
|
||||
str = "+" + StringUtils::ticksTimeToString(ticks_behind);
|
||||
}
|
||||
rank_info.m_text = irr::core::stringw(str.c_str());
|
||||
}
|
||||
|
@ -18,11 +18,12 @@
|
||||
#ifndef HEADER_LINEAR_WORLD_HPP
|
||||
#define HEADER_LINEAR_WORLD_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "modes/world_with_rank.hpp"
|
||||
#include "utils/aligned_array.hpp"
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
|
||||
class SFXBase;
|
||||
|
||||
/*
|
||||
@ -42,8 +43,8 @@ private:
|
||||
|
||||
bool m_last_lap_sfx_playing;
|
||||
|
||||
/** The fastest lap time. */
|
||||
float m_fastest_lap;
|
||||
/** The fastest lap time, in ticks of physics dt. */
|
||||
int m_fastest_lap_ticks;
|
||||
|
||||
/** The track length returned by Track::getLength() only covers the
|
||||
* distance from start line to finish line, i.e. it does not include
|
||||
@ -65,10 +66,10 @@ private:
|
||||
int m_race_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. */
|
||||
float m_lap_start_time;
|
||||
int m_lap_start_ticks;
|
||||
|
||||
/** During last lap only: estimated finishing time! */
|
||||
float m_estimated_finish;
|
||||
@ -84,8 +85,8 @@ private:
|
||||
void reset()
|
||||
{
|
||||
m_race_lap = -1;
|
||||
m_lap_start_time = 0;
|
||||
m_time_at_last_lap = 99999.9f;
|
||||
m_lap_start_ticks = 0;
|
||||
m_ticks_at_last_lap = INT_MAX;
|
||||
m_estimated_finish = -1.0f;
|
||||
m_overall_distance = 0.0f;
|
||||
} // reset
|
||||
@ -117,7 +118,7 @@ public:
|
||||
float getDistanceToCenterForKart(const int kart_id) const;
|
||||
float getEstimatedFinishTime(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(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||
@ -155,11 +156,11 @@ public:
|
||||
{
|
||||
return m_kart_info[kart_index].m_overall_distance;
|
||||
} // getOverallDistance
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns time for the fastest laps */
|
||||
float getFastestLap() const
|
||||
{
|
||||
return m_fastest_lap;
|
||||
return stk_config->ticks2Time(m_fastest_lap_ticks);
|
||||
}
|
||||
}; // LinearWorld
|
||||
|
||||
|
@ -625,26 +625,24 @@ void ThreeStrikesBattle::addKartLife(unsigned int id)
|
||||
void ThreeStrikesBattle::spawnSpareTireKarts()
|
||||
{
|
||||
if (m_spare_tire_karts.empty() ||
|
||||
getTimeSinceStart() < m_next_sta_spawn_time)
|
||||
getTicksSinceStart() < m_next_sta_spawn_time)
|
||||
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
|
||||
// So in easier mode the sta lasts longer than spawn period
|
||||
const float lifespan = inc_factor / period * 1000;
|
||||
m_next_sta_spawn_time = lifespan + (getTimeSinceStart() * inc_factor) +
|
||||
getTimeSinceStart();
|
||||
float inc_factor, lifespan;
|
||||
switch (race_manager->getDifficulty())
|
||||
{
|
||||
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;
|
||||
for (unsigned int i = 0; i < m_kart_info.size(); i++)
|
||||
{
|
||||
|
@ -311,7 +311,7 @@ void World::reset()
|
||||
irr_driver->reset();
|
||||
|
||||
//Reset the Rubber Ball Collect Time to some negative value.
|
||||
powerup_manager->setBallCollectTime(-100);
|
||||
powerup_manager->setBallCollectTicks(-100);
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -63,8 +63,9 @@ void WorldStatus::reset()
|
||||
{
|
||||
m_time = 0.0f;
|
||||
m_adjust_time_by = 0.0f;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_count_up_timer = 0.0f;
|
||||
m_time_ticks = 0;
|
||||
m_auxiliary_ticks = 0;
|
||||
m_count_up_ticks = 0;
|
||||
|
||||
m_engines_started = false;
|
||||
|
||||
@ -138,7 +139,8 @@ void WorldStatus::startEngines()
|
||||
void WorldStatus::setClockMode(const ClockType mode, const float initial_time)
|
||||
{
|
||||
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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -154,7 +156,7 @@ void WorldStatus::enterRaceOverState()
|
||||
return;
|
||||
|
||||
m_phase = DELAY_FINISH_PHASE;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_auxiliary_ticks = 0;
|
||||
} // enterRaceOverState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -190,7 +192,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
// tilt way too much. A separate setup phase for the first frame
|
||||
// simplifies this handling
|
||||
case SETUP_PHASE:
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_auxiliary_ticks= 0;
|
||||
m_phase = TRACK_INTRO_PHASE;
|
||||
|
||||
if (m_play_track_intro_sound)
|
||||
@ -205,7 +207,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
|
||||
return; // Do not increase time
|
||||
case TRACK_INTRO_PHASE:
|
||||
m_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
|
||||
if (UserConfigParams::m_artist_debug_mode &&
|
||||
!NetworkConfig::get()->isNetworking() &&
|
||||
@ -213,7 +215,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
race_manager->getNumSpareTireKarts() == 1 &&
|
||||
race_manager->getTrackName() != "tutorial")
|
||||
{
|
||||
m_auxiliary_timer += dt * 6;
|
||||
m_auxiliary_ticks += 6;
|
||||
}
|
||||
|
||||
// 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
|
||||
// after 3.5 seconds.
|
||||
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
|
||||
|
||||
// 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;
|
||||
|
||||
if (!m_play_track_intro_sound)
|
||||
{
|
||||
startEngines();
|
||||
if (m_auxiliary_timer < 3.0f)
|
||||
if (m_auxiliary_ticks < stk_config->time2Ticks(3.0f))
|
||||
return; // Do not increase time
|
||||
}
|
||||
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_auxiliary_ticks = 0;
|
||||
|
||||
if (m_play_ready_set_go_sounds)
|
||||
m_prestart_sound->play();
|
||||
@ -269,8 +272,8 @@ void WorldStatus::updateTime(const float dt)
|
||||
}
|
||||
case READY_PHASE:
|
||||
startEngines();
|
||||
|
||||
if (m_auxiliary_timer > 1.0)
|
||||
// One second
|
||||
if (m_auxiliary_ticks > stk_config->getPhysicsFPS())
|
||||
{
|
||||
if (m_play_ready_set_go_sounds)
|
||||
{
|
||||
@ -280,7 +283,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
m_phase = SET_PHASE;
|
||||
}
|
||||
|
||||
m_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
|
||||
// In artist debug mode, when without opponents, skip the
|
||||
// ready/set/go counter faster
|
||||
@ -290,12 +293,12 @@ void WorldStatus::updateTime(const float dt)
|
||||
race_manager->getNumSpareTireKarts() == 1 &&
|
||||
race_manager->getTrackName() != "tutorial")
|
||||
{
|
||||
m_auxiliary_timer += dt*6;
|
||||
m_auxiliary_ticks += 6;
|
||||
}
|
||||
|
||||
return; // Do not increase time
|
||||
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
|
||||
m_phase = GO_PHASE;
|
||||
@ -308,7 +311,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
onGo();
|
||||
}
|
||||
|
||||
m_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
|
||||
// In artist debug mode, when without opponents,
|
||||
// skip the ready/set/go counter faster
|
||||
@ -318,24 +321,25 @@ void WorldStatus::updateTime(const float dt)
|
||||
race_manager->getNumSpareTireKarts() == 1 &&
|
||||
race_manager->getTrackName() != "tutorial")
|
||||
{
|
||||
m_auxiliary_timer += dt*6;
|
||||
m_auxiliary_ticks += 6;
|
||||
}
|
||||
|
||||
return; // Do not increase time
|
||||
case GO_PHASE :
|
||||
|
||||
if (m_auxiliary_timer>2.5f && music_manager->getCurrentMusic() &&
|
||||
// 2.5 seconds
|
||||
if (m_auxiliary_ticks>stk_config->time2Ticks(2.5f) &&
|
||||
music_manager->getCurrentMusic() &&
|
||||
!music_manager->getCurrentMusic()->isPlaying())
|
||||
{
|
||||
music_manager->startMusic();
|
||||
}
|
||||
|
||||
if (m_auxiliary_timer > 3.0f) // how long to display the 'go' message
|
||||
// how long to display the 'go' message
|
||||
if (m_auxiliary_ticks > 3 * stk_config->getPhysicsFPS())
|
||||
{
|
||||
m_phase = MUSIC_PHASE;
|
||||
}
|
||||
|
||||
m_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
|
||||
// In artist debug mode, when without opponents,
|
||||
// skip the ready/set/go counter faster
|
||||
@ -344,7 +348,7 @@ void WorldStatus::updateTime(const float dt)
|
||||
race_manager->getNumSpareTireKarts() == 1 &&
|
||||
race_manager->getTrackName() != "tutorial")
|
||||
{
|
||||
m_auxiliary_timer += dt*6;
|
||||
m_auxiliary_ticks += 6;
|
||||
}
|
||||
|
||||
break; // Now the world time starts
|
||||
@ -356,12 +360,13 @@ void WorldStatus::updateTime(const float dt)
|
||||
UserConfigParams::m_race_now = false;
|
||||
}
|
||||
// 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_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
break;
|
||||
case RACE_PHASE:
|
||||
// Nothing to do for race phase, switch to delay finish phase
|
||||
@ -369,10 +374,11 @@ void WorldStatus::updateTime(const float dt)
|
||||
break;
|
||||
case DELAY_FINISH_PHASE:
|
||||
{
|
||||
m_auxiliary_timer += dt;
|
||||
m_auxiliary_ticks++;
|
||||
|
||||
// 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;
|
||||
terminateRace();
|
||||
@ -400,26 +406,29 @@ void WorldStatus::updateTime(const float dt)
|
||||
case CLOCK_CHRONO:
|
||||
if (!device->getTimer()->isStopped())
|
||||
{
|
||||
m_time += dt;
|
||||
m_count_up_timer += dt;
|
||||
m_time_ticks++;
|
||||
m_time = stk_config->ticks2Time(m_time_ticks);
|
||||
m_count_up_ticks++;
|
||||
}
|
||||
break;
|
||||
case CLOCK_COUNTDOWN:
|
||||
// stop countdown when race is over
|
||||
if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE)
|
||||
{
|
||||
m_time_ticks = 0;
|
||||
m_time = 0.0f;
|
||||
m_count_up_timer = 0.0f;
|
||||
m_count_up_ticks = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!device->getTimer()->isStopped())
|
||||
{
|
||||
m_time -= dt;
|
||||
m_count_up_timer += dt;
|
||||
m_time_ticks--;
|
||||
m_time = stk_config->ticks2Time(m_time_ticks);
|
||||
m_count_up_ticks++;
|
||||
}
|
||||
|
||||
if(m_time <= 0.0)
|
||||
if(m_time_ticks <= 0.0)
|
||||
{
|
||||
// event
|
||||
countdownReachedZero();
|
||||
@ -484,10 +493,23 @@ void WorldStatus::startReadySetGo()
|
||||
*/
|
||||
void WorldStatus::setTime(const float time)
|
||||
{
|
||||
m_count_up_timer += (time - m_time);
|
||||
m_time = time;
|
||||
int new_time_ticks = stk_config->time2Ticks(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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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.
|
||||
* \param phase Phase to switch to.
|
||||
|
@ -91,6 +91,9 @@ protected:
|
||||
/** Elasped/remaining time in seconds. */
|
||||
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. */
|
||||
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.
|
||||
* 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;
|
||||
/** In networked game a client must wait for the server to start 'ready
|
||||
@ -155,6 +160,7 @@ public:
|
||||
virtual void enterRaceOverState();
|
||||
virtual void terminateRace();
|
||||
void setTime(const float time);
|
||||
void setTicks(int ticks);
|
||||
float adjustDT(float dt);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -192,6 +198,11 @@ public:
|
||||
/** Returns the current race 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,
|
||||
* which is in COUNTDOWN mode, has reached zero. */
|
||||
@ -202,8 +213,8 @@ public:
|
||||
virtual void onGo() {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get the time since start regardless of which way the clock counts */
|
||||
float getTimeSinceStart() const { return m_count_up_timer; }
|
||||
/** Get the ticks since start regardless of which way the clock counts */
|
||||
int getTicksSinceStart() const { return m_count_up_ticks; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setReadyToRace() { m_server_is_ready = true; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -140,7 +140,7 @@ void GameProtocol::controllerAction(int kart_id, PlayerAction action,
|
||||
s->addUInt8(kart_id).addUInt8(action).addUInt32(value)
|
||||
.addUInt32(val_l).addUInt32(val_r);
|
||||
RewindManager::get()->addEvent(this, s, /*confirmed*/true,
|
||||
World::getWorld()->getTime() );
|
||||
World::getWorld()->getTimeTicks() );
|
||||
|
||||
Log::info("GameProtocol", "Action at %f: %d value %d",
|
||||
World::getWorld()->getTime(), action,
|
||||
@ -158,19 +158,21 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
NetworkString &data = event->data();
|
||||
uint8_t count = data.getUInt8();
|
||||
bool will_trigger_rewind = false;
|
||||
float rewind_delta = 0.0f;
|
||||
int rewind_delta = 0;
|
||||
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
|
||||
// a rewind, i.e. with an incorrect world time. So the event
|
||||
// time needs to be compared with the World time independent
|
||||
// of any rewinding.
|
||||
if (time < RewindManager::get()->getNotRewoundWorldTime() &&
|
||||
if (ticks < RewindManager::get()->getNotRewoundWorldTicks() &&
|
||||
!will_trigger_rewind )
|
||||
{
|
||||
will_trigger_rewind = true;
|
||||
rewind_delta = time - RewindManager::get()->getNotRewoundWorldTime();
|
||||
rewind_delta = ticks
|
||||
- RewindManager::get()->getNotRewoundWorldTicks();
|
||||
}
|
||||
uint8_t kart_id = data.getUInt8();
|
||||
assert(kart_id < World::getWorld()->getNumKarts());
|
||||
@ -179,12 +181,12 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
int value = data.getUInt32();
|
||||
int value_l = data.getUInt32();
|
||||
int value_r = data.getUInt32();
|
||||
Log::info("GameProtocol", "Action at %f: %d %d %d %d %d",
|
||||
time, kart_id, action, value, value_l, value_r);
|
||||
Log::info("GameProtocol", "Action at %d: %d %d %d %d %d",
|
||||
ticks, kart_id, action, value, value_l, value_r);
|
||||
BareNetworkString *s = new BareNetworkString(3);
|
||||
s->addUInt8(kart_id).addUInt8(action).addUInt32(value)
|
||||
.addUInt32(value_l).addUInt32(value_r);
|
||||
RewindManager::get()->addNetworkEvent(this, s, time);
|
||||
RewindManager::get()->addNetworkEvent(this, s, ticks);
|
||||
}
|
||||
|
||||
if (data.size() > 0)
|
||||
@ -200,9 +202,9 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
if (will_trigger_rewind)
|
||||
{
|
||||
Log::info("GameProtocol",
|
||||
"At %f %f %f requesting time adjust of %f for host %d",
|
||||
World::getWorld()->getTime(), StkTime::getRealTime(),
|
||||
RewindManager::get()->getNotRewoundWorldTime(),
|
||||
"At %d %f %d requesting time adjust of %d for host %d",
|
||||
World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
|
||||
RewindManager::get()->getNotRewoundWorldTicks(),
|
||||
rewind_delta, event->getPeer()->getHostId());
|
||||
// This message from a client triggered a rewind in the server.
|
||||
// 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 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());
|
||||
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
|
||||
// get delivered, the server will request again later anyway.
|
||||
peer->sendPacket(ns, /*reliable*/false);
|
||||
@ -282,9 +284,9 @@ void GameProtocol::handleState(Event *event)
|
||||
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
NetworkString &data = event->data();
|
||||
float time = data.getFloat();
|
||||
Log::info("GameProtocol", "Received at %f state from %f",
|
||||
World::getWorld()->getTime(), time);
|
||||
int ticks = data.getUInt32();
|
||||
Log::info("GameProtocol", "Received at %d state from %d",
|
||||
World::getWorld()->getTimeTicks(), ticks);
|
||||
int index = 0;
|
||||
while (data.size() > 0)
|
||||
{
|
||||
@ -292,7 +294,7 @@ void GameProtocol::handleState(Event *event)
|
||||
BareNetworkString *state = new BareNetworkString(data.getCurrentData(),
|
||||
count);
|
||||
data.skip(count);
|
||||
RewindManager::get()->addNetworkState(index, state, time);
|
||||
RewindManager::get()->addNetworkState(index, state, ticks);
|
||||
index++;
|
||||
} // while data.size()>0
|
||||
} // handleState
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
void startNewState();
|
||||
void addState(BareNetworkString *buffer);
|
||||
void sendState();
|
||||
void adjustTimeForClient(STKPeer *peer, float t);
|
||||
void adjustTimeForClient(STKPeer *peer, int ticks);
|
||||
|
||||
virtual void undo(BareNetworkString *buffer) OVERRIDE;
|
||||
virtual void rewind(BareNetworkString *buffer) OVERRIDE;
|
||||
|
@ -1115,7 +1115,7 @@ void ServerLobby::startedRaceOnClient(Event *event)
|
||||
void ServerLobby::playerFinishedResult(Event *event)
|
||||
{
|
||||
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
|
||||
// from the protocol manager thread. So instead we force the timeout
|
||||
|
@ -25,9 +25,9 @@
|
||||
* for all state info.
|
||||
* \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;
|
||||
} // 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
|
||||
* 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(m_time < time);
|
||||
m_time = time;
|
||||
} // setTime
|
||||
assert(m_ticks < ticks);
|
||||
m_ticks = ticks;
|
||||
} // setTicks
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoState::RewindInfoState(float time, Rewinder *rewinder,
|
||||
RewindInfoState::RewindInfoState(int ticks, Rewinder *rewinder,
|
||||
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
|
||||
if(rewinder!=NULL)
|
||||
@ -55,9 +55,9 @@ RewindInfoState::RewindInfoState(float time, Rewinder *rewinder,
|
||||
} // RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoEvent::RewindInfoEvent(float time, EventRewinder *event_rewinder,
|
||||
RewindInfoEvent::RewindInfoEvent(int ticks, EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed)
|
||||
: RewindInfo(time, is_confirmed)
|
||||
: RewindInfo(ticks, is_confirmed)
|
||||
{
|
||||
m_event_rewinder = event_rewinder;
|
||||
m_buffer = buffer;
|
||||
|
@ -46,7 +46,7 @@ private:
|
||||
LEAK_CHECK();
|
||||
|
||||
/** Time when this RewindInfo was taken. */
|
||||
float m_time;
|
||||
int m_ticks;
|
||||
|
||||
/** A confirmed event is one that was sent from the server. When
|
||||
* rewinding we have to start with a confirmed state for each
|
||||
@ -54,7 +54,7 @@ private:
|
||||
bool m_is_confirmed;
|
||||
|
||||
public:
|
||||
RewindInfo(float time, bool is_confirmed);
|
||||
RewindInfo(int ticks, bool is_confirmed);
|
||||
|
||||
/** Called when going back in time to undo any rewind information. */
|
||||
virtual void undo() = 0;
|
||||
@ -62,12 +62,12 @@ public:
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. */
|
||||
virtual void rewind() = 0;
|
||||
void setTime(float time);
|
||||
void setTicks(int ticks);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RewindInfo() { }
|
||||
// ------------------------------------------------------------------------
|
||||
/** 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. */
|
||||
void setConfirmed(bool b) { m_is_confirmed = b; }
|
||||
@ -101,9 +101,9 @@ protected:
|
||||
Rewinder *m_rewinder;
|
||||
|
||||
public:
|
||||
RewindInfoRewinder(float time, Rewinder *rewinder,
|
||||
RewindInfoRewinder(int ticks, Rewinder *rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed)
|
||||
: RewindInfo(time, is_confirmed)
|
||||
: RewindInfo(ticks, is_confirmed)
|
||||
{
|
||||
m_rewinder = rewinder;
|
||||
m_buffer = buffer;
|
||||
@ -126,7 +126,7 @@ private:
|
||||
float m_local_physics_time;
|
||||
|
||||
public:
|
||||
RewindInfoState(float time, Rewinder *rewinder,
|
||||
RewindInfoState(int ticks, Rewinder *rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed);
|
||||
virtual ~RewindInfoState() {};
|
||||
|
||||
@ -169,7 +169,7 @@ private:
|
||||
/** Buffer with the event data. */
|
||||
BareNetworkString *m_buffer;
|
||||
public:
|
||||
RewindInfoEvent(float time, EventRewinder *event_rewinder,
|
||||
RewindInfoEvent(int ticks, EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed);
|
||||
virtual ~RewindInfoEvent()
|
||||
{
|
||||
|
@ -75,10 +75,11 @@ RewindManager::~RewindManager()
|
||||
void RewindManager::reset()
|
||||
{
|
||||
m_is_rewinding = false;
|
||||
m_not_rewound_time = 0;
|
||||
m_not_rewound_ticks = 0;
|
||||
m_overall_state_size = 0;
|
||||
m_state_frequency = 1.0f / stk_config->m_network_state_frequeny;
|
||||
m_last_saved_state = -9999.9f; // forces initial state save
|
||||
m_last_saved_state = -1; // forces initial state save
|
||||
m_state_frequency =
|
||||
stk_config->getPhysicsFPS() / stk_config->m_network_state_frequeny;
|
||||
|
||||
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
|
||||
* 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'
|
||||
// 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,
|
||||
BareNetworkString *buffer, bool confirmed,
|
||||
float time )
|
||||
int ticks )
|
||||
{
|
||||
if(m_is_rewinding)
|
||||
{
|
||||
@ -131,9 +132,9 @@ void RewindManager::addEvent(EventRewinder *event_rewinder,
|
||||
return;
|
||||
}
|
||||
|
||||
if (time < 0)
|
||||
time = World::getWorld()->getTime();
|
||||
m_rewind_queue.addLocalEvent(event_rewinder, buffer, confirmed, time);
|
||||
if (ticks < 0)
|
||||
ticks = World::getWorld()->getTimeTicks();
|
||||
m_rewind_queue.addLocalEvent(event_rewinder, buffer, confirmed, ticks);
|
||||
} // addEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -145,9 +146,9 @@ void RewindManager::addEvent(EventRewinder *event_rewinder,
|
||||
* \param buffer Pointer to the event data.
|
||||
*/
|
||||
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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -159,13 +160,13 @@ void RewindManager::addNetworkEvent(EventRewinder *event_rewinder,
|
||||
* \param buffer Pointer to the event data.
|
||||
*/
|
||||
void RewindManager::addNetworkState(int rewinder_index, BareNetworkString *buffer,
|
||||
float time)
|
||||
int ticks)
|
||||
{
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
// On a client dt from a state is never used, it maintains
|
||||
// its own dt information (using TimeEvents).
|
||||
m_rewind_queue.addNetworkState(m_all_rewinder[rewinder_index], buffer,
|
||||
time, -99);
|
||||
ticks, -99);
|
||||
} // addNetworkState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -180,11 +181,13 @@ void RewindManager::update(float dt)
|
||||
m_is_rewinding ) return;
|
||||
|
||||
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.
|
||||
if ( NetworkConfig::get()->isClient() ||
|
||||
time - m_last_saved_state < m_state_frequency )
|
||||
ticks - m_last_saved_state < m_state_frequency )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -201,7 +204,7 @@ void RewindManager::update(float dt)
|
||||
m_overall_state_size += buffer->size();
|
||||
// Add to the previously created container
|
||||
m_rewind_queue.addLocalState(*rewinder, buffer, /*confirmed*/true,
|
||||
World::getWorld()->getTime());
|
||||
World::getWorld()->getTimeTicks());
|
||||
GameProtocol::lock()->addState(buffer);
|
||||
} // size >= 0
|
||||
else
|
||||
@ -211,7 +214,7 @@ void RewindManager::update(float dt)
|
||||
PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40);
|
||||
GameProtocol::lock()->sendState();
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
m_last_saved_state = time;
|
||||
m_last_saved_state = ticks;
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -223,23 +226,23 @@ void RewindManager::update(float dt)
|
||||
void RewindManager::playEventsTill(float time, float *dt)
|
||||
{
|
||||
bool needs_rewind;
|
||||
float rewind_time;
|
||||
int rewind_ticks;
|
||||
|
||||
// Merge in all network events that have happened since the last
|
||||
// merge and that have happened before the current time (which will
|
||||
// be getTime()+dt - world time has not been updated yet).
|
||||
m_rewind_queue.mergeNetworkData(World::getWorld()->getTime(), *dt,
|
||||
&needs_rewind, &rewind_time);
|
||||
m_rewind_queue.mergeNetworkData(World::getWorld()->getTimeTicks(), *dt,
|
||||
&needs_rewind, &rewind_ticks);
|
||||
|
||||
if (needs_rewind)
|
||||
{
|
||||
Log::setPrefix("Rewind");
|
||||
PROFILER_PUSH_CPU_MARKER("Rewind", 128, 128, 128);
|
||||
rewindTo(rewind_time);
|
||||
rewindTo(rewind_ticks);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
Log::setPrefix("");
|
||||
TimeStepInfo *tsi = m_rewind_queue.getCurrent();
|
||||
World::getWorld()->setTime(tsi->getTime());
|
||||
World::getWorld()->setTicks(tsi->getTicks());
|
||||
Physics::getInstance()->getPhysicsWorld()->resetLocalTime();
|
||||
}
|
||||
|
||||
@ -262,8 +265,8 @@ void RewindManager::playEventsTill(float time, float *dt)
|
||||
if (tsi->hasConfirmedState() && NetworkConfig::get()->isClient())
|
||||
{
|
||||
Log::warn("RewindManager",
|
||||
"Client has received state in the future: at %f state %f",
|
||||
World::getWorld()->getTime(), tsi->getTime());
|
||||
"Client has received state in the future: at %d state %d",
|
||||
World::getWorld()->getTimeTicks(), tsi->getTicks());
|
||||
}
|
||||
m_is_rewinding = false;
|
||||
} // playEventsTill
|
||||
@ -272,9 +275,9 @@ void RewindManager::playEventsTill(float time, float *dt)
|
||||
/** Rewinds to the specified time, then goes forward till the current
|
||||
* World::getTime() is reached again: it will replay everything before
|
||||
* 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);
|
||||
bool is_history = history->replayHistory();
|
||||
@ -293,7 +296,7 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
// Then undo the rewind infos going backwards in time
|
||||
// --------------------------------------------------
|
||||
m_is_rewinding = true;
|
||||
m_rewind_queue.undoUntil(rewind_time);
|
||||
m_rewind_queue.undoUntil(rewind_ticks);
|
||||
|
||||
// Rewind the required state(s)
|
||||
// ----------------------------
|
||||
@ -304,11 +307,11 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
TimeStepInfo *current = m_rewind_queue.getCurrent();
|
||||
|
||||
// Store the time to which we have to replay to,
|
||||
// which can be earlier than rewind_time
|
||||
float exact_rewind_time = current->getTime();
|
||||
// which can be earlier than rewind_ticks
|
||||
int exact_rewind_ticks = current->getTicks();
|
||||
|
||||
// Now start the rewind with the full state:
|
||||
world->setTime(exact_rewind_time);
|
||||
world->setTicks(exact_rewind_ticks);
|
||||
float local_physics_time = current->getLocalPhysicsTime();
|
||||
Physics::getInstance()->getPhysicsWorld()->setLocalTime(local_physics_time);
|
||||
|
||||
@ -346,8 +349,8 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
|
||||
++m_rewind_queue;
|
||||
current = m_rewind_queue.getCurrent();
|
||||
world->setTime(current->getTime());
|
||||
} // while (world->getTime() < current_time)
|
||||
world->setTicks(current->getTicks());
|
||||
} // while (world->getTicks() < current_ticks)
|
||||
|
||||
// Now compute the errors which need to be visually smoothed
|
||||
for (rewinder = m_all_rewinder.begin();
|
||||
|
@ -101,14 +101,15 @@ private:
|
||||
bool m_is_rewinding;
|
||||
|
||||
/** How much time between consecutive state saves. */
|
||||
float m_state_frequency;
|
||||
int m_state_frequency;
|
||||
|
||||
/** Time at which the last state was saved. */
|
||||
float m_last_saved_state;
|
||||
/** Ticks at which the last state was saved. */
|
||||
int m_last_saved_state;
|
||||
|
||||
/** This stores the original World time during a rewind. It is used to
|
||||
* detect if a client's local time need adjustment to reduce rewinds. */
|
||||
float m_not_rewound_time;
|
||||
/** This stores the original World time in ticks during a rewind. It is
|
||||
* used to detect if a client's local time need adjustment to reduce
|
||||
* rewinds. */
|
||||
int m_not_rewound_ticks;
|
||||
|
||||
RewindManager();
|
||||
~RewindManager();
|
||||
@ -137,15 +138,15 @@ public:
|
||||
|
||||
void reset();
|
||||
void update(float dt);
|
||||
void rewindTo(float target_time);
|
||||
void rewindTo(int target_ticks);
|
||||
void playEventsTill(float time, float *dt);
|
||||
void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer,
|
||||
bool confirmed, float time = -1.0f);
|
||||
bool confirmed, int ticks = -1);
|
||||
void addNetworkEvent(EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, float time);
|
||||
BareNetworkString *buffer, int ticks);
|
||||
void addNetworkState(int rewinder_index, BareNetworkString *buffer,
|
||||
float time);
|
||||
void addNextTimeStep(float time, float dt);
|
||||
int ticks);
|
||||
void addNextTimeStep(int ticks, float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds a Rewinder to the list of all rewinders.
|
||||
* \return true If rewinding is enabled, false otherwise.
|
||||
@ -160,7 +161,7 @@ public:
|
||||
/** Returns true if currently a rewind is happening. */
|
||||
bool isRewinding() const { return m_is_rewinding; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getNotRewoundWorldTime() const { return m_not_rewound_time; }
|
||||
int getNotRewoundWorldTicks() const { return m_not_rewound_ticks; }
|
||||
}; // RewindManager
|
||||
|
||||
|
||||
|
@ -99,11 +99,11 @@ void RewindQueue::reset()
|
||||
* \param time New time to add.
|
||||
* \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() ||
|
||||
time > m_time_step_info.back()->getTime() );
|
||||
ticks > m_time_step_info.back()->getTicks() );
|
||||
m_time_step_info.push_back(tsi);
|
||||
|
||||
// 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.
|
||||
*/
|
||||
RewindQueue::AllTimeStepInfo::iterator
|
||||
RewindQueue::findPreviousTimeStepInfo(float t)
|
||||
RewindQueue::findPreviousTimeStepInfo(int ticks)
|
||||
{
|
||||
AllTimeStepInfo::iterator i = m_time_step_info.end();
|
||||
while(i!=m_time_step_info.begin())
|
||||
{
|
||||
i--;
|
||||
if ((*i)->getTime() <= t) return i;
|
||||
if ((*i)->getTicks() <= ticks) return i;
|
||||
}
|
||||
return i;
|
||||
} // findPreviousTimeStepInfo
|
||||
@ -140,7 +140,7 @@ RewindQueue::AllTimeStepInfo::iterator
|
||||
bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri1,
|
||||
const TimeStepInfo * const ri2) const
|
||||
{
|
||||
return ri1->getTime() < ri2->getTime();
|
||||
return ri1->getTicks() < ri2->getTicks();
|
||||
} // RewindQueue::operator()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -153,7 +153,7 @@ bool RewindQueue::_TimeStepInfoCompare::operator()(const TimeStepInfo * const ri
|
||||
void RewindQueue::insertRewindInfo(RewindInfo *ri)
|
||||
{
|
||||
// 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
|
||||
// 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,
|
||||
BareNetworkString *buffer, bool confirmed,
|
||||
float time )
|
||||
int ticks )
|
||||
{
|
||||
RewindInfo *ri = new RewindInfoEvent(time, event_rewinder,
|
||||
RewindInfo *ri = new RewindInfoEvent(ticks, event_rewinder,
|
||||
buffer, confirmed);
|
||||
insertRewindInfo(ri);
|
||||
} // addLocalEvent
|
||||
@ -191,9 +191,9 @@ void RewindQueue::addLocalEvent(EventRewinder *event_rewinder,
|
||||
* \param time Time at which the state was captured.
|
||||
*/
|
||||
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);
|
||||
insertRewindInfo(ri);
|
||||
} // addLocalState
|
||||
@ -207,9 +207,9 @@ void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
* \param buffer Pointer to the event data.
|
||||
*/
|
||||
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);
|
||||
|
||||
m_network_events.lock();
|
||||
@ -226,9 +226,9 @@ void RewindQueue::addNetworkEvent(EventRewinder *event_rewinder,
|
||||
* \param buffer Pointer to the event data.
|
||||
*/
|
||||
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);
|
||||
|
||||
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
|
||||
* 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.
|
||||
* \param dt[in] Time step size. The current frame will cover events between
|
||||
* 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
|
||||
* might be modified in this function.
|
||||
*/
|
||||
void RewindQueue::mergeNetworkData(float world_time, float dt,
|
||||
bool *needs_rewind, float *rewind_time)
|
||||
void RewindQueue::mergeNetworkData(int world_ticks, float dt,
|
||||
bool *needs_rewind, int *rewind_ticks)
|
||||
{
|
||||
*needs_rewind = false;
|
||||
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.
|
||||
// Only a client ever rewinds. So the rewind time should be the latest
|
||||
// received state before current world time (if any)
|
||||
*rewind_time = -99999.9f;
|
||||
*rewind_ticks = -9999;
|
||||
bool adjust_next = false;
|
||||
|
||||
// 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
|
||||
// event is later than world_time+0.5*dt, it will be closer to a
|
||||
// future time stamp and is ignored now.
|
||||
if ((*i)->getTime() > world_time+0.5f*dt)
|
||||
if ((*i)->getTicks() > world_ticks+0.5f*dt)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
@ -286,23 +286,23 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
|
||||
// duplicated states, which in the best case would then have
|
||||
// a negative effect for every player, when in fact only one
|
||||
// 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",
|
||||
world_time, (*i)->getTime());
|
||||
Log::warn("RewindQueue", "At %d received message from %d",
|
||||
world_ticks, (*i)->getTicks());
|
||||
// Server received an event in the past. Adjust this event
|
||||
// to be executed now - at least we get a bit closer to the
|
||||
// client state.
|
||||
(*i)->setTime(world_time);
|
||||
(*i)->setTicks(world_ticks);
|
||||
}
|
||||
|
||||
// Find closest previous time step.
|
||||
AllTimeStepInfo::iterator prev =
|
||||
findPreviousTimeStepInfo((*i)->getTime());
|
||||
findPreviousTimeStepInfo((*i)->getTicks());
|
||||
AllTimeStepInfo::iterator next = prev;
|
||||
next++;
|
||||
|
||||
float event_time = (*i)->getTime();
|
||||
int event_ticks = (*i)->getTicks();
|
||||
|
||||
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).
|
||||
if (next == m_time_step_info.end())
|
||||
tsi = *prev;
|
||||
else if ( (*next)->getTime()-event_time < event_time-(*prev)->getTime() )
|
||||
else if ( (*next)->getTicks()-event_ticks < event_ticks-(*prev)->getTicks() )
|
||||
tsi = *next;
|
||||
else
|
||||
tsi = *prev;
|
||||
|
||||
tsi->insert(*i);
|
||||
Log::info("Rewind", "Inserting event from time %f type %c to timstepinfo %f prev %f next %f",
|
||||
(*i)->getTime(),
|
||||
Log::info("Rewind", "Inserting event from time %d type %c to timstepinfo %d prev %d next %d",
|
||||
(*i)->getTicks(),
|
||||
(*i)->isEvent() ? 'E' : ((*i)->isState() ? 'S' : 'T'),
|
||||
tsi->getTime(),
|
||||
(*prev)->getTime(),
|
||||
next != m_time_step_info.end() ? (*next)->getTime() : 9999 );
|
||||
tsi->getTicks(),
|
||||
(*prev)->getTicks(),
|
||||
next != m_time_step_info.end() ? (*next)->getTicks() : 9999 );
|
||||
|
||||
// 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
|
||||
@ -340,11 +340,11 @@ void RewindQueue::mergeNetworkData(float world_time, float dt,
|
||||
// at the time the client is currently simulating (instead of
|
||||
// triggering a rollback) it is not ahead enough of the server
|
||||
// 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())
|
||||
{
|
||||
*needs_rewind = true;
|
||||
if (tsi->getTime() > *rewind_time) *rewind_time = tsi->getTime();
|
||||
if (tsi->getTicks() > *rewind_ticks) *rewind_ticks = tsi->getTicks();
|
||||
}
|
||||
} // if client
|
||||
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 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)
|
||||
// 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();
|
||||
|
||||
return stk_config->ticks2Time(1);
|
||||
} // determineNextDT
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -400,7 +391,7 @@ float RewindQueue::determineNextDT(float end_time)
|
||||
* m_current is pointing to is ignored.
|
||||
* \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())
|
||||
{
|
||||
@ -408,7 +399,7 @@ void RewindQueue::undoUntil(float undo_time)
|
||||
// Undo all events and states from the current time
|
||||
(*m_current)->undoAll();
|
||||
|
||||
if ((*m_current)->getTime() <= undo_time &&
|
||||
if ((*m_current)->getTicks() <= undo_ticks &&
|
||||
(*m_current)->hasConfirmedState())
|
||||
{
|
||||
return;
|
||||
@ -416,8 +407,8 @@ void RewindQueue::undoUntil(float undo_time)
|
||||
|
||||
} // while m_current!=m_time_step_info.begin()
|
||||
|
||||
Log::error("RewindManager", "No state for rewind to %f",
|
||||
undo_time);
|
||||
Log::error("RewindManager", "No state for rewind to %d",
|
||||
undo_ticks);
|
||||
|
||||
} // undoUntil
|
||||
|
||||
@ -456,45 +447,45 @@ void RewindQueue::unitTesting()
|
||||
assert(q0.isEmpty());
|
||||
assert(!q0.hasMoreRewindInfo());
|
||||
|
||||
q0.addNewTimeStep(0.0f, 0.5f);
|
||||
q0.addNewTimeStep(0, 0.5f);
|
||||
q0.m_current = q0.m_time_step_info.begin();
|
||||
assert(!q0.isEmpty());
|
||||
assert(q0.hasMoreRewindInfo());
|
||||
assert(q0.m_time_step_info.size() == 1);
|
||||
|
||||
assert((*q0.m_time_step_info.begin())->getNumberOfEvents() == 0);
|
||||
q0.addLocalState(NULL, NULL, true, 0.0f);
|
||||
q0.addLocalState(NULL, NULL, true, 0);
|
||||
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);
|
||||
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0.0f);
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0);
|
||||
|
||||
bool needs_rewind;
|
||||
float rewind_time;
|
||||
float world_time = 0.0f;
|
||||
int rewind_ticks;
|
||||
int world_ticks = 0;
|
||||
float dt = 0.01f;
|
||||
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);
|
||||
|
||||
// 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
|
||||
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.begin())->getNumberOfEvents() == 2);
|
||||
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.begin())->getNumberOfEvents() == 3);
|
||||
|
||||
// This event will get added to the last time step info at 1.0:
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 1.0f);
|
||||
world_time = 0.8f;
|
||||
q0.addNetworkEvent(dummy_rewinder, NULL, 1);
|
||||
world_ticks = 8;
|
||||
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()
|
||||
// is the last element
|
||||
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
|
||||
// was added and the pointer was already at end of list
|
||||
RewindQueue b1;
|
||||
b1.addNewTimeStep(1.0f, 0.1f);
|
||||
b1.addNewTimeStep(1, 0.1f);
|
||||
++b1; // Should now point at end of list
|
||||
b1.hasMoreRewindInfo();
|
||||
b1.addNewTimeStep(2.0f, 0.1f);
|
||||
b1.addNewTimeStep(2, 0.1f);
|
||||
TimeStepInfo *tsi = b1.getCurrent();
|
||||
assert(tsi->getTime() == 2.0f);
|
||||
assert(tsi->getTicks() == 2);
|
||||
} // unitTesting
|
||||
|
@ -55,7 +55,7 @@ private:
|
||||
* always be at the same time as World::getTime(). */
|
||||
AllTimeStepInfo::iterator m_current;
|
||||
|
||||
AllTimeStepInfo::iterator findPreviousTimeStepInfo(float t);
|
||||
AllTimeStepInfo::iterator findPreviousTimeStepInfo(int ticks);
|
||||
void insertRewindInfo(RewindInfo *ri);
|
||||
|
||||
struct _TimeStepInfoCompare
|
||||
@ -73,21 +73,21 @@ public:
|
||||
RewindQueue();
|
||||
~RewindQueue();
|
||||
void reset();
|
||||
void addNewTimeStep(float time, float dt);
|
||||
void addNewTimeStep(int ticks, float dt);
|
||||
void addLocalEvent(EventRewinder *event_rewinder, BareNetworkString *buffer,
|
||||
bool confirmed, float time);
|
||||
bool confirmed, int ticks);
|
||||
void addLocalState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
bool confirmed, float time);
|
||||
bool confirmed, int ticks);
|
||||
void addNetworkEvent(EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, float time);
|
||||
BareNetworkString *buffer, int ticks);
|
||||
void addNetworkState(Rewinder *rewinder, BareNetworkString *buffer,
|
||||
float time, float dt);
|
||||
void mergeNetworkData(float world_time, float dt,
|
||||
bool *needs_rewind, float *rewind_time);
|
||||
int ticks, float dt);
|
||||
void mergeNetworkData(int world_ticks, float dt,
|
||||
bool *needs_rewind, int *rewind_ticks);
|
||||
bool isEmpty() const;
|
||||
bool hasMoreRewindInfo() const;
|
||||
void undoUntil(float undo_time);
|
||||
float determineNextDT(float max_time);
|
||||
void undoUntil(int undo_ticks);
|
||||
float determineNextDT();
|
||||
// ------------------------------------------------------------------------
|
||||
/** 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
|
||||
|
@ -25,9 +25,9 @@
|
||||
* \param time Time for this TimeStepInfo object.
|
||||
* \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;
|
||||
// In case of unit testing physics does not exist
|
||||
if (Physics::getInstance())
|
||||
|
@ -53,7 +53,7 @@ private:
|
||||
AllRewindInfo m_list_of_events;
|
||||
|
||||
/** Time at which those events should be executed here. */
|
||||
float m_time;
|
||||
int m_ticks;
|
||||
|
||||
/** Time step to be used. */
|
||||
float m_dt;
|
||||
@ -62,20 +62,20 @@ private:
|
||||
* 60 fps. Restoring this value exactly improves accuracy of rewinds. */
|
||||
float m_local_physics_time;
|
||||
public:
|
||||
TimeStepInfo(float time, float dt);
|
||||
TimeStepInfo(int ticks, float dt);
|
||||
void insert(RewindInfo *ri);
|
||||
void undoAll();
|
||||
void replayAllEvents();
|
||||
void replayAllStates();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the tiem of this object. */
|
||||
void setTime(float time) { m_time = time; }
|
||||
void setTicks(int ticks) { m_ticks = ticks; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the time step size of this object. */
|
||||
void setDT(float dt) { m_dt = dt; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time for this TimeStepInfo instance. */
|
||||
float getTime() const { return m_time; }
|
||||
int getTicks() const { return m_ticks; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the left-over physics time. */
|
||||
float getLocalPhysicsTime() const { return m_local_physics_time; }
|
||||
|
@ -154,7 +154,7 @@ void Physics::update(float dt)
|
||||
// Since the world update (which calls physics update) is called at the
|
||||
// fixed frequency necessary for the physics update, we need to do exactly
|
||||
// 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
|
||||
// inside of this loop, since the same flyables might hit more than one
|
||||
|
@ -493,7 +493,8 @@ void RaceGUIBase::drawGlobalMusicDescription()
|
||||
|
||||
gui::IGUIFont* font = GUIEngine::getFont();
|
||||
|
||||
float race_time = World::getWorld()->getTimeSinceStart();
|
||||
float race_time =
|
||||
stk_config->ticks2Time(World::getWorld()->getTicksSinceStart());
|
||||
|
||||
// ---- Manage pulsing effect
|
||||
// 3.0 is the duration of ready/set (TODO: don't hardcode)
|
||||
|
@ -168,7 +168,9 @@ void addAttachment(Attachment::AttachmentType type)
|
||||
if (type == Attachment::ATTACH_ANVIL)
|
||||
{
|
||||
kart->getAttachment()
|
||||
->set(type, kart->getKartProperties()->getAnvilDuration());
|
||||
->set(type,
|
||||
stk_config->time2Ticks(kart->getKartProperties()
|
||||
->getAnvilDuration()) );
|
||||
kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor());
|
||||
kart->updateWeight();
|
||||
}
|
||||
@ -180,7 +182,7 @@ void addAttachment(Attachment::AttachmentType type)
|
||||
else if (type == Attachment::ATTACH_BOMB)
|
||||
{
|
||||
kart->getAttachment()
|
||||
->set(type, stk_config->m_bomb_time);
|
||||
->set(type, stk_config->time2Ticks(stk_config->m_bomb_time) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,11 @@
|
||||
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/utf8.h"
|
||||
|
||||
#include "coreutil.h"
|
||||
|
||||
#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,
|
||||
|
@ -45,6 +45,7 @@ namespace StringUtils
|
||||
std::string getExtension(const std::string& filename);
|
||||
|
||||
bool notEmpty(const irr::core::stringw& input);
|
||||
std::string ticksTimeToString(int time);
|
||||
std::string timeToString(float time);
|
||||
irr::core::stringw loadingDots(float interval = 0.5f, int max_dots = 3);
|
||||
irr::core::stringw loadingDots(const wchar_t *s);
|
||||
|
Loading…
Reference in New Issue
Block a user