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

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

View File

@ -59,9 +59,11 @@ public:
* - SAME: give it one more item of the type it currently has.
* - 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

View File

@ -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 ?

View File

@ -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++)
{

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -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).

View File

@ -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;}
};

View File

@ -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

View File

@ -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. */

View File

@ -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
// ----------------------------------------------------------------------------

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -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).

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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++)
{

View File

@ -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
//-----------------------------------------------------------------------------

View File

@ -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.

View File

@ -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; }
// ------------------------------------------------------------------------

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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()
{

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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())

View File

@ -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; }

View File

@ -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

View File

@ -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)

View File

@ -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) );
}
}

View File

@ -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,

View File

@ -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);