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