Clean up the firing of flyables in network

This commit is contained in:
Benau
2019-02-26 15:55:24 +08:00
parent 1ac4a5b93d
commit cfbbc7c6dd
17 changed files with 458 additions and 500 deletions

View File

@@ -37,50 +37,9 @@ Bowling::Bowling(AbstractKart *kart)
: Flyable(kart, PowerupManager::POWERUP_BOWLING, 50.0f /* mass */)
{
m_has_hit_kart = false;
float y_offset = 0.5f*kart->getKartLength() + m_extend.getZ()*0.5f;
// if the kart is looking backwards, release from the back
if( kart->getControls().getLookBack())
{
y_offset = -y_offset;
m_speed = -m_speed*2;
}
else
{
float min_speed = m_speed*4.0f;
/* make it go faster when throwing forward
so the player doesn't catch up with the ball
and explode by touching it */
m_speed = kart->getSpeed() + m_speed;
if(m_speed < min_speed) m_speed = min_speed;
}
const Vec3& normal = kart->getNormal();
createPhysics(y_offset, btVector3(0.0f, 0.0f, m_speed*2),
new btSphereShape(0.5f*m_extend.getY()),
0.4f /*restitution*/,
-70.0f*normal /*gravity*/,
true /*rotates*/);
// Even if the ball is fired backwards, m_speed must be positive,
// otherwise the ball can start to vibrate when energy is added.
m_speed = fabsf(m_speed);
// Do not adjust the up velociy depending on height above terrain, since
// this would disable gravity.
setAdjustUpVelocity(false);
// unset no_contact_response flags, so that the ball
// will bounce off the track
int flag = getBody()->getCollisionFlags();
flag = flag & (~ btCollisionObject::CF_NO_CONTACT_RESPONSE);
getBody()->setCollisionFlags(flag);
// should not live forever, auto-destruct after 20 seconds
m_max_lifespan = stk_config->time2Ticks(20);
m_roll_sfx = SFXManager::get()->createSoundSource("bowling_roll");
m_roll_sfx->play();
m_roll_sfx->setLoop(true);
} // Bowling
// ----------------------------------------------------------------------------
@@ -89,9 +48,7 @@ Bowling::Bowling(AbstractKart *kart)
Bowling::~Bowling()
{
// This will stop the sfx and delete the object.
if (m_roll_sfx)
m_roll_sfx->deleteSFX();
removeRollSfx();
} // ~RubberBall
// -----------------------------------------------------------------------------
@@ -121,8 +78,11 @@ void Bowling::init(const XMLNode &node, scene::IMesh *bowling)
bool Bowling::updateAndDelete(int ticks)
{
bool can_be_deleted = Flyable::updateAndDelete(ticks);
if(can_be_deleted)
if (can_be_deleted)
{
removeRollSfx();
return true;
}
const AbstractKart *kart=0;
Vec3 direction;
@@ -153,6 +113,7 @@ bool Bowling::updateAndDelete(int ticks)
if(!material || material->isDriveReset())
{
hit(NULL);
removeRollSfx();
return true;
}
}
@@ -172,6 +133,7 @@ bool Bowling::updateAndDelete(int ticks)
if(vlen<0.1)
{
hit(NULL);
removeRollSfx();
return true;
}
@@ -180,6 +142,7 @@ bool Bowling::updateAndDelete(int ticks)
return false;
} // updateAndDelete
// -----------------------------------------------------------------------------
/** Callback from the physics in case that a kart or physical object is hit.
* The bowling ball triggers an explosion when hit.
@@ -208,15 +171,14 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj)
} // hit
// ----------------------------------------------------------------------------
void Bowling::hideNodeWhenUndoDestruction()
void Bowling::removeRollSfx()
{
Flyable::hideNodeWhenUndoDestruction();
if (m_roll_sfx)
{
m_roll_sfx->deleteSFX();
m_roll_sfx = NULL;
}
} // hideNodeWhenUndoDestruction
} // removeRollSfx
// ----------------------------------------------------------------------------
/** Returns the hit effect object to use when this objects hits something.
@@ -224,8 +186,57 @@ void Bowling::hideNodeWhenUndoDestruction()
*/
HitEffect* Bowling::getHitEffect() const
{
if (m_deleted_once)
return NULL;
if(m_has_hit_kart)
return new HitSFX(getXYZ(), "strike");
else
return new HitSFX(getXYZ(), "crash");
} // getHitEffect
// ----------------------------------------------------------------------------
void Bowling::onFireFlyable()
{
Flyable::onFireFlyable();
m_has_hit_kart = false;
float y_offset = 0.5f*m_owner->getKartLength() + m_extend.getZ()*0.5f;
// if the kart is looking backwards, release from the back
if( m_owner->getControls().getLookBack())
{
y_offset = -y_offset;
m_speed = -m_speed*2;
}
else
{
float min_speed = m_speed*4.0f;
/* make it go faster when throwing forward
so the player doesn't catch up with the ball
and explode by touching it */
m_speed = m_owner->getSpeed() + m_speed;
if(m_speed < min_speed) m_speed = min_speed;
}
const Vec3& normal = m_owner->getNormal();
createPhysics(y_offset, btVector3(0.0f, 0.0f, m_speed*2),
new btSphereShape(0.5f*m_extend.getY()),
0.4f /*restitution*/,
-70.0f*normal /*gravity*/,
true /*rotates*/);
// Even if the ball is fired backwards, m_speed must be positive,
// otherwise the ball can start to vibrate when energy is added.
m_speed = fabsf(m_speed);
// Do not adjust the up velociy depending on height above terrain, since
// this would disable gravity.
setAdjustUpVelocity(false);
// unset no_contact_response flags, so that the ball
// will bounce off the track
int flag = getBody()->getCollisionFlags();
flag = flag & (~ btCollisionObject::CF_NO_CONTACT_RESPONSE);
getBody()->setCollisionFlags(flag);
// should not live forever, auto-destruct after 20 seconds
m_max_lifespan = stk_config->time2Ticks(20);
} // onFireFlyable

View File

@@ -48,7 +48,7 @@ private:
/** A sound effect for rolling ball. */
SFXBase *m_roll_sfx;
virtual void hideNodeWhenUndoDestruction() OVERRIDE;
void removeRollSfx();
public:
Bowling(AbstractKart* kart);
@@ -57,7 +57,8 @@ public:
virtual bool updateAndDelete(int ticks) OVERRIDE;
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
virtual HitEffect *getHitEffect() const OVERRIDE;
// ------------------------------------------------------------------------
virtual void onFireFlyable() OVERRIDE;
}; // Bowling

View File

@@ -34,92 +34,6 @@ float Cake::m_gravity;
Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
{
m_target = NULL;
setDoTerrainInfo(false);
btVector3 gravity_vector;
btQuaternion q = kart->getTrans().getRotation();
gravity_vector = Vec3(0, -1, 0).rotate(q.getAxis(), q.getAngle());
gravity_vector = gravity_vector.normalize() * m_gravity;
// A bit of a hack: the mass of this kinematic object is still 1.0
// (see flyable), which enables collisions. I tried setting
// collisionFilterGroup/mask, but still couldn't get this object to
// collide with the track. By setting the mass to 1, collisions happen.
// (if bullet is compiled with _DEBUG, a warning will be printed the first
// time a homing-track collision happens).
float forward_offset=kart->getKartLength()/2.0f + m_extend.getZ()/2.0f;
float up_velocity = m_speed/7.0f;
// give a speed proportional to kart speed. m_speed is defined in flyable
m_speed *= kart->getSpeed() / 23.0f;
//when going backwards, decrease speed of cake by less
if (kart->getSpeed() < 0) m_speed /= 3.6f;
m_speed += 16.0f;
if (m_speed < 1.0f) m_speed = 1.0f;
btTransform trans = kart->getTrans();
float heading=kart->getHeading();
float pitch = kart->getTerrainPitch(heading);
// Find closest kart in front of the current one
const bool backwards = kart->getControls().getLookBack();
const AbstractKart *closest_kart=NULL;
Vec3 direction;
float kart_dist_squared;
getClosestKart(&closest_kart, &kart_dist_squared, &direction,
kart /* search in front of this kart */, backwards);
// aim at this kart if 1) it's not too far, 2) if the aimed kart's speed
// allows the projectile to catch up with it
//
// this code finds the correct angle and upwards velocity to hit an opponents'
// vehicle if they were to continue travelling in the same direction and same speed
// (barring any obstacles in the way of course)
if(closest_kart != NULL && kart_dist_squared < m_st_max_distance_squared &&
m_speed>closest_kart->getSpeed())
{
m_target = (AbstractKart*)closest_kart;
float fire_angle = 0.0f;
getLinearKartItemIntersection (kart->getXYZ(), closest_kart,
m_speed, m_gravity, forward_offset,
&fire_angle, &up_velocity);
// apply transformation to the bullet object (without pitch)
btQuaternion q;
q = trans.getRotation() * btQuaternion(btVector3(0, 1, 0), fire_angle);
trans.setRotation(q);
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
createPhysics(forward_offset, m_initial_velocity,
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */, gravity_vector,
true /* rotation */, false /* backwards */, &trans);
}
else
{
m_target = NULL;
// kart is too far to be hit. so throw the projectile in a generic way,
// straight ahead, without trying to hit anything in particular
trans = kart->getAlignedTransform(pitch);
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
createPhysics(forward_offset, m_initial_velocity,
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */, gravity_vector,
true /* rotation */, backwards, &trans);
}
//do not adjust height according to terrain
setAdjustUpVelocity(false);
additionalPhysicsProperties();
} // Cake
// -----------------------------------------------------------------------------
@@ -162,3 +76,95 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj)
return was_real_hit;
} // hit
// ----------------------------------------------------------------------------
void Cake::onFireFlyable()
{
Flyable::onFireFlyable();
setDoTerrainInfo(false);
btVector3 gravity_vector;
btQuaternion q = m_owner->getTrans().getRotation();
gravity_vector = Vec3(0, -1, 0).rotate(q.getAxis(), q.getAngle());
gravity_vector = gravity_vector.normalize() * m_gravity;
// A bit of a hack: the mass of this kinematic object is still 1.0
// (see flyable), which enables collisions. I tried setting
// collisionFilterGroup/mask, but still couldn't get this object to
// collide with the track. By setting the mass to 1, collisions happen.
// (if bullet is compiled with _DEBUG, a warning will be printed the first
// time a homing-track collision happens).
float forward_offset=m_owner->getKartLength()/2.0f + m_extend.getZ()/2.0f;
float up_velocity = m_speed/7.0f;
// give a speed proportional to kart speed. m_speed is defined in flyable
m_speed *= m_owner->getSpeed() / 23.0f;
//when going backwards, decrease speed of cake by less
if (m_owner->getSpeed() < 0) m_speed /= 3.6f;
m_speed += 16.0f;
if (m_speed < 1.0f) m_speed = 1.0f;
btTransform trans = m_owner->getTrans();
float heading=m_owner->getHeading();
float pitch = m_owner->getTerrainPitch(heading);
// Find closest kart in front of the current one
const bool backwards = m_owner->getControls().getLookBack();
const AbstractKart *closest_kart=NULL;
Vec3 direction;
float kart_dist_squared;
getClosestKart(&closest_kart, &kart_dist_squared, &direction,
m_owner /* search in front of this kart */, backwards);
// aim at this kart if 1) it's not too far, 2) if the aimed kart's speed
// allows the projectile to catch up with it
//
// this code finds the correct angle and upwards velocity to hit an opponents'
// vehicle if they were to continue travelling in the same direction and same speed
// (barring any obstacles in the way of course)
if(closest_kart != NULL && kart_dist_squared < m_st_max_distance_squared &&
m_speed>closest_kart->getSpeed())
{
m_target = (AbstractKart*)closest_kart;
float fire_angle = 0.0f;
getLinearKartItemIntersection (m_owner->getXYZ(), closest_kart,
m_speed, m_gravity, forward_offset,
&fire_angle, &up_velocity);
// apply transformation to the bullet object (without pitch)
btQuaternion q;
q = trans.getRotation() * btQuaternion(btVector3(0, 1, 0), fire_angle);
trans.setRotation(q);
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
createPhysics(forward_offset, m_initial_velocity,
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */, gravity_vector,
true /* rotation */, false /* backwards */, &trans);
}
else
{
m_target = NULL;
// kart is too far to be hit. so throw the projectile in a generic way,
// straight ahead, without trying to hit anything in particular
trans = m_owner->getAlignedTransform(pitch);
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
createPhysics(forward_offset, m_initial_velocity,
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */, gravity_vector,
true /* rotation */, backwards, &trans);
}
//do not adjust height according to terrain
setAdjustUpVelocity(false);
m_body->setActivationState(DISABLE_DEACTIVATION);
m_body->clearForces();
m_body->applyTorque(btVector3(5.0f, -3.0f, 7.0f));
} // onFireFlyable

View File

@@ -47,20 +47,17 @@ private:
/** Which kart is targeted by this projectile (NULL if none). */
Moveable* m_target;
// ------------------------------------------------------------------------
virtual void additionalPhysicsProperties() OVERRIDE
{
m_body->setActivationState(DISABLE_DEACTIVATION);
m_body->clearForces();
m_body->applyTorque(btVector3(5.0f, -3.0f, 7.0f));
}
public:
Cake (AbstractKart *kart);
static void init (const XMLNode &node, scene::IMesh *cake_model);
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
// ------------------------------------------------------------------------
virtual void hitTrack () OVERRIDE { hit(NULL); }
virtual void hitTrack () OVERRIDE
{
if (!m_has_server_state)
return;
hit(NULL);
}
// ------------------------------------------------------------------------
/** Kinematic objects are not allowed to have a velocity (assertion in
* bullet), so we have to do our own velocity handling here. This
@@ -75,7 +72,8 @@ public:
*/
virtual void setVelocity(const btVector3& v) OVERRIDE
{ m_initial_velocity = v; }
// ------------------------------------------------------------------------
virtual void onFireFlyable() OVERRIDE;
}; // Cake
#endif

View File

@@ -40,9 +40,7 @@
#include "karts/explosion_animation.hpp"
#include "modes/linear_world.hpp"
#include "network/compress_network_body.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/rewind_info.hpp"
#include "network/rewind_manager.hpp"
#include "physics/physics.hpp"
#include "tracks/track.hpp"
@@ -61,7 +59,7 @@ Vec3 Flyable::m_st_extend [PowerupManager::POWERUP_MAX];
Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
float mass)
: Moveable(), TerrainInfo()
: Moveable(), TerrainInfo(), m_mass(mass)
{
// get the appropriate data from the static fields
m_speed = m_st_speed[type];
@@ -75,17 +73,16 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
m_has_hit_something = false;
m_shape = NULL;
m_animation = NULL;
m_mass = mass;
m_adjust_up_velocity = true;
m_ticks_since_thrown = 0;
m_position_offset = Vec3(0,0,0);
m_owner_has_temporary_immunity = true;
m_do_terrain_info = true;
m_deleted_once = false;
m_max_lifespan = -1;
m_undo_creation = false;
m_has_undone_destruction = false;
m_has_server_state = false;
m_check_created_ticks = -1;
// It will be reset for each state restore
m_has_server_state = true;
m_last_deleted_ticks = -1;
// Add the graphical model
#ifndef SERVER_ONLY
@@ -96,6 +93,9 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
getNode()->setName(debug_name.c_str());
#endif
#endif
// Smooth network body for flyable doesn't seem to be needed, most of the
// time it rewinds almost the same
SmoothNetworkBody::setEnable(false);
} // Flyable
// ----------------------------------------------------------------------------
@@ -118,6 +118,8 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
const bool rotates, const bool turn_around,
const btTransform* custom_direction)
{
// Remove previously physics data if any
removePhysics();
// Get Kart heading direction
btTransform trans = ( !custom_direction ? m_owner->getAlignedTransform()
: *custom_direction );
@@ -170,11 +172,6 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
}
m_body->setCollisionFlags(m_body->getCollisionFlags() |
btCollisionObject::CF_NO_CONTACT_RESPONSE);
m_saved_transform = getTrans();
m_saved_lv = m_body->getLinearVelocity();
m_saved_av = m_body->getAngularVelocity();
m_saved_gravity = gravity;
} // createPhysics
// -----------------------------------------------------------------------------
@@ -206,10 +203,25 @@ void Flyable::init(const XMLNode &node, scene::IMesh *model,
//-----------------------------------------------------------------------------
Flyable::~Flyable()
{
if(m_shape) delete m_shape;
Physics::getInstance()->removeBody(getBody());
removePhysics();
} // ~Flyable
//-----------------------------------------------------------------------------
/* Called when delete this flyable or re-firing during rewind. */
void Flyable::removePhysics()
{
if (m_shape)
{
delete m_shape;
m_shape = NULL;
}
if (m_body.get())
{
Physics::getInstance()->removeBody(m_body.get());
m_body.reset();
}
} // removePhysics
//-----------------------------------------------------------------------------
/** Returns information on what is the closest kart and at what distance it is.
* All 3 parameters first are of type 'out'. 'inFrontOf' can be set if you
@@ -395,16 +407,13 @@ void Flyable::updateGraphics(float dt)
*/
bool Flyable::updateAndDelete(int ticks)
{
if (m_undo_creation)
if (!m_has_server_state)
return false;
if (hasAnimation())
{
if (!RewindManager::get()->isRewinding())
{
m_animation->update(ticks);
Moveable::update(ticks);
}
m_animation->update(ticks);
Moveable::update(ticks);
return false;
} // if animation
@@ -513,7 +522,7 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
*/
bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
{
if (m_undo_creation)
if (!m_has_server_state)
return false;
// the owner of this flyable should not be hit by his own flyable
if(isOwnerImmunity(kart_hit)) return false;
@@ -586,7 +595,8 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
*/
HitEffect* Flyable::getHitEffect() const
{
return new Explosion(getXYZ(), "explosion", "explosion_cake.xml");
return m_deleted_once ? NULL :
new Explosion(getXYZ(), "explosion", "explosion_cake.xml");
} // getHitEffect
// ----------------------------------------------------------------------------
@@ -596,15 +606,24 @@ unsigned int Flyable::getOwnerId()
} // getOwnerId
// ----------------------------------------------------------------------------
void Flyable::moveToInfinity()
/** It's called when undoing the creation or destruction of flyables, so that
* it will not affected the current game, and it will be deleted in
* computeError.
* \param set_moveable_trans If true, set m_transform in moveable, so the
* graphical node will have the same transform, otherwise only the physical
* body will be moved to infinity
*/
void Flyable::moveToInfinity(bool set_moveable_trans)
{
const Vec3 *min, *max;
Track::getCurrentTrack()->getAABB(&min, &max);
btTransform t = m_body->getWorldTransform();
t.setOrigin(*max * 2.0f);
m_body->setWorldTransform(t);
m_motion_state->setWorldTransform(t);
m_body->setInterpolationWorldTransform(t);
m_body->proceedToTransform(t);
if (set_moveable_trans)
setTrans(t);
else
m_motion_state->setWorldTransform(t);
} // moveToInfinity
// ----------------------------------------------------------------------------
@@ -622,20 +641,6 @@ BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
return buffer;
} // saveState
// ----------------------------------------------------------------------------
std::function<void()> Flyable::getLocalStateRestoreFunction()
{
// Avoid circular reference
std::weak_ptr<Flyable> fw = getShared<Flyable>();
return [fw]()
{
std::shared_ptr<Flyable> f = fw.lock();
if (!f || f->m_has_undone_destruction)
return;
f->m_has_server_state = false;
};
} // getLocalStateRestoreFunction
// ----------------------------------------------------------------------------
void Flyable::restoreState(BareNetworkString *buffer, int count)
{
@@ -643,120 +648,78 @@ void Flyable::restoreState(BareNetworkString *buffer, int count)
Vec3 lv, av;
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
if (!hasAnimation())
{
m_body->setWorldTransform(t);
m_motion_state->setWorldTransform(t);
m_body->setInterpolationWorldTransform(t);
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->setInterpolationLinearVelocity(lv);
m_body->setInterpolationAngularVelocity(av);
setTrans(t);
}
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->proceedToTransform(t);
setTrans(t);
m_ticks_since_thrown = buffer->getUInt16();
m_has_server_state = true;
m_has_hit_something = false;
} // restoreState
// ----------------------------------------------------------------------------
void Flyable::addForRewind(const std::string& uid)
{
SmoothNetworkBody::setEnable(true);
SmoothNetworkBody::setSmoothRotation(false);
SmoothNetworkBody::setAdjustVerticalOffset(false);
Rewinder::setUniqueIdentity(uid);
Rewinder::rewinderAdd();
} // addForRewind
// ----------------------------------------------------------------------------
void Flyable::addRewindInfoEventFunctionAfterFiring()
void Flyable::saveTransform()
{
if (!NetworkConfig::get()->isNetworking() ||
NetworkConfig::get()->isServer())
return;
std::shared_ptr<Flyable> f = getShared<Flyable>();
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
/*undo_function*/[f]()
{
f->m_undo_creation = true;
// Move it to infinity, avoiding affecting current rewinding
f->moveToInfinity();
f->m_body->setGravity(Vec3(0.0f));
},
/*replay_function*/[f]()
{
f->m_undo_creation = false;
f->m_body->setWorldTransform(f->m_saved_transform);
f->m_motion_state->setWorldTransform(f->m_saved_transform);
f->m_body->setInterpolationWorldTransform(f->m_saved_transform);
f->m_body->setLinearVelocity(f->m_saved_lv);
f->m_body->setAngularVelocity(f->m_saved_av);
f->m_body->setInterpolationLinearVelocity(f->m_saved_lv);
f->m_body->setInterpolationAngularVelocity(f->m_saved_av);
f->m_body->setGravity(f->m_saved_gravity);
f->m_ticks_since_thrown = 0;
f->m_has_hit_something = false;
f->additionalPhysicsProperties();
},
/*delete_function*/[f]()
{
f->m_check_created_ticks = World::getWorld()->getTicksSinceStart();
}));
} // addRewindInfoEventFunctionAfterFiring
// ----------------------------------------------------------------------------
void Flyable::hideNodeWhenUndoDestruction()
{
#ifndef SERVER_ONLY
m_node->setVisible(false);
#endif
// It will be overwritten in restoreState (so it's confirmed by server) or
// onFireFlyable (before the game state all flyables are assumed to be
// sucessfully created)
moveToInfinity();
} // hideNodeWhenUndoDestruction
// ----------------------------------------------------------------------------
void Flyable::handleUndoDestruction()
{
if (!NetworkConfig::get()->isNetworking() ||
NetworkConfig::get()->isServer() ||
m_has_undone_destruction)
return;
m_has_undone_destruction = true;
// We don't bother seeing the mesh during rewinding
hideNodeWhenUndoDestruction();
std::shared_ptr<Flyable> f = getShared<Flyable>();
std::string uid = f->getUniqueIdentity();
projectile_manager->addDeletedUID(uid);
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
/*undo_function*/[f, uid]()
{
f->m_has_hit_something = false;
projectile_manager->addByUID(uid, f);
},
/*replay_function*/[f, uid]()
{
f->m_has_hit_something = true;
projectile_manager->removeByUID(uid);
f->moveToInfinity();
}));
} // handleUndoDestruction
m_has_server_state = false;
m_last_deleted_ticks = -1;
} // saveTransform
// ----------------------------------------------------------------------------
void Flyable::computeError()
{
Moveable::checkSmoothing();
if (!m_has_server_state && m_check_created_ticks != -1 &&
World::getWorld()->getTicksSinceStart() > m_check_created_ticks)
// Remove the flyable if it doesn't exist or failed to create on server
// For each saveTransform it will call moveToInfinity so the invalid
// flyables won't affect the current game
const int state_ticks = RewindManager::get()->getLatestConfirmedState();
if (!m_has_server_state && (m_last_deleted_ticks == -1 ||
state_ticks > m_last_deleted_ticks))
{
const std::string& uid = getUniqueIdentity();
Log::warn("Flyable", "Item %s doesn't exist on server, "
"remove it locally.", uid.c_str());
Log::debug("Flyable", "Item %s doesn't exist on server, "
"remove it.", uid.c_str());
projectile_manager->removeByUID(uid);
}
} // computeError
// ----------------------------------------------------------------------------
/** Call when the item is (re-)fired (during rewind if needed) by
* projectile_manager. */
void Flyable::onFireFlyable()
{
m_ticks_since_thrown = 0;
m_has_hit_something = false;
m_has_server_state = true;
m_deleted_once = false;
m_last_deleted_ticks = -1;
// Reset the speed each time for (re-)firing, so subclass access with same
// initial value
m_speed = m_st_speed[m_type];
m_extend = m_st_extend[m_type];
m_max_height = m_st_max_height[m_type];
m_min_height = m_st_min_height[m_type];
m_average_height = (m_min_height + m_max_height) / 2.0f;
m_force_updown = m_st_force_updown[m_type];
} // onFireFlyable
// ----------------------------------------------------------------------------
/* Call when deleting the flyable locally and save the deleted world ticks. */
void Flyable::onDeleteFlyable()
{
m_deleted_once = true;
m_last_deleted_ticks = World::getWorld()->getTicksSinceStart();
m_has_server_state = false;
moveToInfinity();
} // onDeleteFlyable
/* EOF */

View File

@@ -47,7 +47,6 @@ class XMLNode;
class Flyable : public Moveable, public TerrainInfo,
public Rewinder
{
public:
private:
bool m_has_hit_something;
@@ -100,15 +99,32 @@ protected:
float m_speed;
/** Mass of this Flyable. */
float m_mass;
const float m_mass;
/** Size of this flyable. */
Vec3 m_extend;
bool m_undo_creation;
bool m_has_undone_destruction;
/** Time since thrown. used so a kart can't hit himself when trying
* something, and also to put some time limit to some collectibles */
int16_t m_ticks_since_thrown;
/* True if this flyable exists in server, and will trigger a rewind.
* For each local state it will reset it to false and call moveToInfinity,
* and for each restoreState it will set it to true. Also when re-fire the
* flyable during rewind it will set to true too. */
bool m_has_server_state;
int m_check_created_ticks;
/** If set to true, the kart that throwns this flyable can't collide
* with it for a short time. */
bool m_owner_has_temporary_immunity;
/* Set to true once when onDeleteFlyable, this is used to create HitEffect
* only once. */
bool m_deleted_once;
/* Save the locally detected deleted ticks, if the confirmed state world
* ticks in computeError > this, the flyable can be deleted in client. */
int m_last_deleted_ticks;
// The flyable class stores the values for each flyable type, e.g.
// speed, min_height, max_height. These variables must be static,
@@ -133,17 +149,10 @@ protected:
/** Size of the model. */
static Vec3 m_st_extend[PowerupManager::POWERUP_MAX];
/** Time since thrown. used so a kart can't hit himself when trying
* something, and also to put some time limit to some collectibles */
int16_t m_ticks_since_thrown;
/** Set to something > -1 if this flyable should auto-destrcut after
* that may ticks. */
int m_max_lifespan;
/** If set to true, the kart that throwns this flyable can't collide
* with it for a short time. */
bool m_owner_has_temporary_immunity;
void getClosestKart(const AbstractKart **minKart,
float *minDistSquared,
@@ -168,14 +177,8 @@ protected:
const bool turn_around=false,
const btTransform* customDirection=NULL);
void moveToInfinity();
/** Used when undoing creation or destruction. */
btTransform m_saved_transform;
Vec3 m_saved_lv, m_saved_av, m_saved_gravity;
virtual void additionalPhysicsProperties() {}
virtual void hideNodeWhenUndoDestruction();
void moveToInfinity(bool set_moveable_trans = true);
void removePhysics();
public:
Flyable (AbstractKart* kart,
@@ -245,7 +248,7 @@ public:
// ------------------------------------------------------------------------
virtual void undoState(BareNetworkString *buffer) OVERRIDE {}
// ------------------------------------------------------------------------
virtual void saveTransform() OVERRIDE { Moveable::prepareSmoothing(); }
virtual void saveTransform() OVERRIDE;
// ------------------------------------------------------------------------
virtual void computeError() OVERRIDE;
// ------------------------------------------------------------------------
@@ -254,15 +257,14 @@ public:
// ------------------------------------------------------------------------
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
// ------------------------------------------------------------------------
virtual void addRewindInfoEventFunctionAfterFiring();
/* Return true if still in game state, or otherwise can be deleted. */
bool hasServerState() const { return m_has_server_state; }
// ------------------------------------------------------------------------
virtual std::function<void()> getLocalStateRestoreFunction() OVERRIDE;
/** Call when the item is (re-)fired (during rewind if needed) by
* projectile_manager. */
virtual void onFireFlyable();
// ------------------------------------------------------------------------
bool isUndoCreation() const { return m_undo_creation; }
// ------------------------------------------------------------------------
bool hasUndoneDestruction() const { return m_has_undone_destruction; }
// ------------------------------------------------------------------------
void handleUndoDestruction();
virtual void onDeleteFlyable();
}; // Flyable

View File

@@ -40,40 +40,57 @@
Plunger::Plunger(AbstractKart *kart)
: Flyable(kart, PowerupManager::POWERUP_PLUNGER)
{
m_has_locally_played_sound = false;
m_moved_to_infinity = false;
m_reverse_mode = false;
m_rubber_band = NULL;
} // Plunger
// ----------------------------------------------------------------------------
Plunger::~Plunger()
{
if(m_rubber_band)
delete m_rubber_band;
} // ~Plunger
// ----------------------------------------------------------------------------
void Plunger::onFireFlyable()
{
Flyable::onFireFlyable();
m_has_locally_played_sound = false;
m_moved_to_infinity = false;
const float gravity = 0.0f;
setDoTerrainInfo(false);
float forward_offset = 0.5f*kart->getKartLength()+0.5f*m_extend.getZ();
float forward_offset = 0.5f*m_owner->getKartLength()+0.5f*m_extend.getZ();
float up_velocity = 0.0f;
float plunger_speed = 2 * m_speed;
// if the kart is looking backwards, release from the back
m_reverse_mode = kart->getControls().getLookBack();
m_reverse_mode = m_owner->getControls().getLookBack();
// find closest kart in front of the current one
const AbstractKart *closest_kart=0;
Vec3 direction;
float kart_dist_2;
getClosestKart(&closest_kart, &kart_dist_2, &direction,
kart /* search in front of this kart */, m_reverse_mode);
m_owner /* search in front of this kart */, m_reverse_mode);
btTransform kart_transform = kart->getAlignedTransform();
btTransform kart_transform = m_owner->getAlignedTransform();
float heading =kart->getHeading();
float pitch = kart->getTerrainPitch(heading);
float heading =m_owner->getHeading();
float pitch = m_owner->getTerrainPitch(heading);
// aim at this kart if it's not too far
if(closest_kart != NULL && kart_dist_2 < 30*30)
{
float fire_angle = 0.0f;
getLinearKartItemIntersection (kart->getXYZ(), closest_kart,
getLinearKartItemIntersection (m_owner->getXYZ(), closest_kart,
plunger_speed, gravity, forward_offset,
&fire_angle, &up_velocity);
btTransform trans = kart->getTrans();
btTransform trans = m_owner->getTrans();
btQuaternion q;
q = trans.getRotation()*(btQuaternion(btVector3(0, 1, 0), fire_angle));
trans.setRotation(q);
@@ -96,22 +113,22 @@ Plunger::Plunger(AbstractKart *kart)
//adjust height according to terrain
setAdjustUpVelocity(false);
m_rubber_band = NULL;
// pulling back makes no sense in battle mode, since this mode is not a race.
// so in battle mode, always hide view
if (!(m_reverse_mode || race_manager->isBattleMode()))
const bool create_rubber_band =
!(m_reverse_mode || race_manager->isBattleMode());
if (create_rubber_band && !m_rubber_band)
m_rubber_band = new RubberBand(this, m_owner);
else if (!create_rubber_band && m_rubber_band)
{
m_rubber_band = new RubberBand(this, kart);
}
additionalPhysicsProperties();
} // Plunger
// ----------------------------------------------------------------------------
Plunger::~Plunger()
{
if(m_rubber_band)
delete m_rubber_band;
} // ~Plunger
m_rubber_band = NULL;
}
if (m_rubber_band)
m_rubber_band->reset();
m_keep_alive = -1;
m_moved_to_infinity = false;
} // onFireFlyable
// ----------------------------------------------------------------------------
void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
@@ -123,6 +140,13 @@ void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
void Plunger::updateGraphics(float dt)
{
Flyable::updateGraphics(dt);
#ifndef SERVER_ONLY
scene::ISceneNode *node = getNode();
if (node && m_moved_to_infinity)
node->setVisible(false);
else if (node && !m_moved_to_infinity)
node->setVisible(true);
#endif
if (m_rubber_band)
m_rubber_band->updateGraphics(dt);
} // updateGraphics
@@ -155,7 +179,6 @@ bool Plunger::updateAndDelete(int ticks)
return ret;
} // updateAndDelete
// -----------------------------------------------------------------------------
/** Virtual function called when the plunger hits something.
* The plunger is special in that it is not deleted when hitting an object.
@@ -168,7 +191,7 @@ bool Plunger::updateAndDelete(int ticks)
*/
bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
{
if (isOwnerImmunity(kart) || m_moved_to_infinity || m_undo_creation)
if (isOwnerImmunity(kart) || m_moved_to_infinity || !m_has_server_state)
return false;
// pulling back makes no sense in battle mode, since this mode is not a race.
@@ -187,37 +210,17 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
}
m_keep_alive = 0;
// Make this object invisible.
#ifndef SERVER_ONLY
getNode()->setVisible(false);
#endif
// Previously removeBody will break rewind
moveToInfinity();
moveToInfinity(false/*set_moveable_trans*/);
m_moved_to_infinity = true;
}
else
{
m_keep_alive = stk_config->time2Ticks(m_owner->getKartProperties()
->getPlungerBandDuration() );
#ifndef SERVER_ONLY
// Make this object invisible by placing it faaar down. Not that if
// this objects is simply removed from the scene graph, it might be
// auto-deleted because the ref count reaches zero.
scene::ISceneNode *node = getNode();
if(node)
{
node->setVisible(false);
}
#endif
// Previously removeBody will break rewind
moveToInfinity();
m_moved_to_infinity = true;
m_keep_alive = (int16_t)stk_config->time2Ticks(m_owner->getKartProperties()
->getPlungerBandDuration());
if(kart)
{
m_rubber_band->hit(kart);
return false;
}
else if(obj)
{
@@ -228,6 +231,9 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
{
m_rubber_band->hit(NULL, &(getXYZ()));
}
// Previously removeBody will break rewind
moveToInfinity(false/*set_moveable_trans*/);
m_moved_to_infinity = true;
}
// Rubber band attached.
@@ -240,17 +246,11 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
*/
void Plunger::hitTrack()
{
if (m_moved_to_infinity || !m_has_server_state)
return;
hit(NULL, NULL);
} // hitTrack
// ----------------------------------------------------------------------------
void Plunger::hideNodeWhenUndoDestruction()
{
Flyable::hideNodeWhenUndoDestruction();
if (m_rubber_band)
m_rubber_band->remove();
} // hideNodeWhenUndoDestruction
// ----------------------------------------------------------------------------
BareNetworkString* Plunger::saveState(std::vector<std::string>* ru)
{
@@ -271,7 +271,15 @@ void Plunger::restoreState(BareNetworkString *buffer, int count)
{
Flyable::restoreState(buffer, count);
m_keep_alive = buffer->getUInt16();
m_moved_to_infinity = false;
// Restore position base on m_keep_alive in Plunger::hit
if (m_keep_alive == -1)
m_moved_to_infinity = false;
else
{
moveToInfinity(false/*set_moveable_trans*/);
m_moved_to_infinity = true;
}
uint8_t bit_state = buffer->getUInt8();
if (bit_state == 255 && m_rubber_band)
{
@@ -289,3 +297,11 @@ void Plunger::restoreState(BareNetworkString *buffer, int count)
if (bit_state != 255)
m_rubber_band->set8BitState(bit_state);
} // restoreState
// ----------------------------------------------------------------------------
void Plunger::onDeleteFlyable()
{
Flyable::onDeleteFlyable();
if (m_rubber_band)
m_rubber_band->remove();
} // onDeleteFlyable

View File

@@ -48,12 +48,6 @@ private:
bool m_reverse_mode, m_has_locally_played_sound, m_moved_to_infinity;
virtual void additionalPhysicsProperties() OVERRIDE
{
m_keep_alive = -1;
m_moved_to_infinity = false;
}
virtual void hideNodeWhenUndoDestruction() OVERRIDE;
public:
Plunger(AbstractKart *kart);
~Plunger();
@@ -77,6 +71,10 @@ public:
OVERRIDE;
// ------------------------------------------------------------------------
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
// ------------------------------------------------------------------------
virtual void onFireFlyable() OVERRIDE;
// ------------------------------------------------------------------------
virtual void onDeleteFlyable() OVERRIDE;
}; // Plunger

View File

@@ -28,7 +28,7 @@
#include "items/rubber_ball.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "network/dummy_rewinder.hpp"
#include "network/network_config.hpp"
#include "network/rewind_manager.hpp"
ProjectileManager *projectile_manager=0;
@@ -49,7 +49,6 @@ void ProjectileManager::removeTextures()
void ProjectileManager::cleanup()
{
m_active_projectiles.clear();
m_deleted_projectiles.clear();
for(HitEffects::iterator i = m_active_hit_effects.begin();
i != m_active_hit_effects.end(); ++i)
{
@@ -106,7 +105,7 @@ void ProjectileManager::updateServer(int ticks)
auto p = m_active_projectiles.begin();
while (p != m_active_projectiles.end())
{
if (p->second->isUndoCreation())
if (!p->second->hasServerState())
{
p++;
continue;
@@ -114,14 +113,15 @@ void ProjectileManager::updateServer(int ticks)
bool can_be_deleted = p->second->updateAndDelete(ticks);
if (can_be_deleted)
{
if (!p->second->hasUndoneDestruction())
{
HitEffect *he = p->second->getHitEffect();
if (he)
addHitEffect(he);
}
p->second->handleUndoDestruction();
p = m_active_projectiles.erase(p);
HitEffect* he = p->second->getHitEffect();
if (he)
addHitEffect(he);
p->second->onDeleteFlyable();
// Flyables will be deleted by computeError in client
if (!NetworkConfig::get()->isNetworking() ||
NetworkConfig::get()->isServer())
p = m_active_projectiles.erase(p);
}
else
p++;
@@ -140,9 +140,12 @@ std::shared_ptr<Flyable>
{
const std::string& uid = getUniqueIdentity(kart, type);
auto it = m_active_projectiles.find(uid);
// Flyable already created during rewind
// Flyable has already created before and now rewinding, re-fire it
if (it != m_active_projectiles.end())
{
it->second->onFireFlyable();
return it->second;
}
std::shared_ptr<Flyable> f;
switch(type)
@@ -162,12 +165,12 @@ std::shared_ptr<Flyable>
default:
return nullptr;
}
// This cannot be done in constructor because of virtual function
f->onFireFlyable();
m_active_projectiles[uid] = f;
if (RewindManager::get()->isEnabled())
{
f->addForRewind(uid);
f->addRewindInfoEventFunctionAfterFiring();
}
return f;
} // newProjectile
@@ -184,7 +187,7 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
i++)
{
if (i->second->isUndoCreation())
if (!i->second->hasServerState())
continue;
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
if (dist2 < r2)
@@ -209,7 +212,7 @@ int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
i++)
{
if (i->second->isUndoCreation())
if (!i->second->hasServerState())
continue;
if (i->second->getType() == type)
{
@@ -255,6 +258,8 @@ std::string ProjectileManager::getUniqueIdentity(AbstractKart* kart,
} // getUniqueIdentity
// -----------------------------------------------------------------------------
/* If any flyable is not found in current game state, create it with respect to
* its uid as below. */
std::shared_ptr<Rewinder>
ProjectileManager::addRewinderFromNetworkState(const std::string& uid)
{
@@ -269,49 +274,40 @@ std::shared_ptr<Rewinder>
AbstractKart* kart = World::getWorld()->getKart(world_id);
char first_id = id[0][0];
auto it = m_deleted_projectiles.find(uid);
if (it != m_deleted_projectiles.end())
{
Log::debug("ProjectileManager", "Flyable %s locally (early) deleted,"
" use a dummy rewinder to skip.", uid.c_str());
return std::make_shared<DummyRewinder>();
}
Log::debug("ProjectileManager",
"Missed a firing event, add the flyable %s manually.", uid.c_str());
std::shared_ptr<Flyable> f;
switch (first_id)
{
case 'B':
{
auto f = std::make_shared<Bowling>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
f = std::make_shared<Bowling>(kart);
break;
}
case 'P':
{
auto f = std::make_shared<Plunger>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
f = std::make_shared<Plunger>(kart);
break;
}
case 'C':
{
auto f = std::make_shared<Cake>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
f = std::make_shared<Cake>(kart);
break;
}
case 'R':
{
auto f = std::make_shared<RubberBall>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
f = std::make_shared<RubberBall>(kart);
break;
}
default:
assert(false);
return nullptr;
{
break;
}
}
assert(f);
f->onFireFlyable();
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
} // addProjectileFromNetworkState

View File

@@ -51,8 +51,6 @@ private:
* currently moving on the track. */
std::map<std::string, std::shared_ptr<Flyable> > m_active_projectiles;
std::unordered_set<std::string> m_deleted_projectiles;
/** All active hit effects, i.e. hit effects which are currently
* being shown or have a sfx playing. */
HitEffects m_active_hit_effects;
@@ -91,9 +89,6 @@ public:
// ------------------------------------------------------------------------
void removeByUID(const std::string& uid)
{ m_active_projectiles.erase(uid); }
// ------------------------------------------------------------------------
void addDeletedUID(const std::string& uid)
{ m_deleted_projectiles.insert(uid); }
};
extern ProjectileManager *projectile_manager;

View File

@@ -70,10 +70,20 @@ RubberBall::RubberBall(AbstractKart *kart)
m_next_id++;
m_id = m_next_id;
m_target = NULL;
m_ping_sfx = SFXManager::get()->createSoundSource("ball_bounce");
CheckManager::get()->addFlyableToCannons(this);
} // RubberBall
// ----------------------------------------------------------------------------
void RubberBall::onFireFlyable()
{
Flyable::onFireFlyable();
// Don't let Flyable update the terrain information, since this object
// has to do it earlier than that.
setDoTerrainInfo(false);
float forw_offset = 0.5f*kart->getKartLength() + m_extend.getZ()*0.5f+5.0f;
float forw_offset =
0.5f * m_owner->getKartLength() + m_extend.getZ() * 0.5f + 5.0f;
createPhysics(forw_offset, btVector3(0.0f, 0.0f, m_speed*2),
new btSphereShape(0.5f*m_extend.getY()), -70.0f,
@@ -84,17 +94,6 @@ RubberBall::RubberBall(AbstractKart *kart)
setAdjustUpVelocity(false);
m_max_lifespan = stk_config->time2Ticks(9999);
m_target = NULL;
m_ping_sfx = SFXManager::get()->createSoundSource("ball_bounce");
m_owner_init_pos = m_owner->getXYZ();
m_init_pos = getXYZ();
additionalPhysicsProperties();
CheckManager::get()->addFlyableToCannons(this);
} // RubberBall
// ----------------------------------------------------------------------------
void RubberBall::additionalPhysicsProperties()
{
setXYZ(m_init_pos);
m_aiming_at_target = false;
m_fast_ping = false;
// At the start the ball aims at quads till it gets close enough to the
@@ -102,8 +101,8 @@ void RubberBall::additionalPhysicsProperties()
m_height_timer = 0.0f;
m_interval = m_st_interval;
m_current_max_height = m_max_height;
// Just init the previoux coordinates with some value that's not getXYZ()
m_previous_xyz = m_owner_init_pos;
// Just init the previous coordinates with some value that's not getXYZ()
m_previous_xyz = m_owner->getXYZ();
m_previous_height = 2.0f; //
// A negative value indicates that the timer is not active
m_delete_ticks = -1;
@@ -121,17 +120,15 @@ void RubberBall::additionalPhysicsProperties()
const Vec3& normal =
DriveGraph::get()->getNode(getCurrentGraphNode())->getNormal();
TerrainInfo::update(getXYZ(), -normal);
initializeControlPoints(m_owner_init_pos);
} // additionalPhysicsProperties
initializeControlPoints(m_owner->getXYZ());
} // onFireFlyable
// ----------------------------------------------------------------------------
/** Destructor, removes any playing sfx.
*/
RubberBall::~RubberBall()
{
if(m_ping_sfx->getStatus()==SFXBase::SFX_PLAYING)
m_ping_sfx->stop();
m_ping_sfx->deleteSFX();
removePingSFX();
CheckManager::get()->removeFlyableFromCannons(this);
} // ~RubberBall
@@ -171,29 +168,6 @@ void RubberBall::setAnimation(AbstractKartAnimation *animation)
{
initializeControlPoints(getXYZ());
m_height_timer = 0;
if (RewindManager::get()->useLocalEvent())
{
std::shared_ptr<RubberBall> rb = getShared<RubberBall>();
btTransform cur_trans = getTrans();
Vec3 cur_previous_xyz = m_previous_xyz;
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
/*undo_function*/[rb]()
{
rb->m_undo_creation = true;
rb->moveToInfinity();
},
/*replay_function*/[rb, cur_trans, cur_previous_xyz]()
{
rb->m_undo_creation = false;
rb->m_body->setWorldTransform(cur_trans);
rb->m_motion_state->setWorldTransform(cur_trans);
rb->m_body->setInterpolationWorldTransform(cur_trans);
rb->m_previous_xyz = cur_previous_xyz;
rb->initializeControlPoints(cur_trans.getOrigin());
rb->m_height_timer = 0;
}));
}
}
Flyable::setAnimation(animation);
} // setAnimation
@@ -405,6 +379,7 @@ bool RubberBall::updateAndDelete(int ticks)
#ifdef PRINT_BALL_REMOVE_INFO
Log::debug("[RubberBall]", "ball %d deleted.", m_id);
#endif
removePingSFX();
return true;
}
}
@@ -414,7 +389,10 @@ bool RubberBall::updateAndDelete(int ticks)
// Flyable will call update() of the animation to
// update the ball's position.
m_previous_xyz = getXYZ();
return Flyable::updateAndDelete(ticks);
bool can_be_deleted = Flyable::updateAndDelete(ticks);
if (can_be_deleted)
removePingSFX();
return can_be_deleted;
}
// Update normal from rewind first
@@ -499,13 +477,19 @@ bool RubberBall::updateAndDelete(int ticks)
m_previous_height = (getXYZ() - getHitPoint()).length();
setXYZ(next_xyz);
if(checkTunneling())
if (checkTunneling())
{
removePingSFX();
return true;
}
// Determine new distance along track
TrackSector::update(next_xyz);
return Flyable::updateAndDelete(ticks);
bool can_be_deleted = Flyable::updateAndDelete(ticks);
if (can_be_deleted)
removePingSFX();
return can_be_deleted;
} // updateAndDelete
// ----------------------------------------------------------------------------
@@ -705,7 +689,7 @@ float RubberBall::updateHeight()
if(m_height_timer>m_interval)
{
m_height_timer -= m_interval;
if (m_ping_sfx->getStatus()!=SFXBase::SFX_PLAYING &&
if (m_ping_sfx && m_ping_sfx->getStatus()!=SFXBase::SFX_PLAYING &&
!RewindManager::get()->isRewinding())
{
m_ping_sfx->setPosition(getXYZ());
@@ -938,3 +922,14 @@ void RubberBall::restoreState(BareNetworkString *buffer, int count)
m_aiming_at_target = ((tunnel_and_aiming >> 7) & 1) == 1;
TrackSector::rewindTo(buffer);
} // restoreState
// ----------------------------------------------------------------------------
void RubberBall::removePingSFX()
{
if (!m_ping_sfx)
return;
if (m_ping_sfx->getStatus() == SFXBase::SFX_PLAYING)
m_ping_sfx->stop();
m_ping_sfx->deleteSFX();
m_ping_sfx = NULL;
} // removePingSFX

View File

@@ -196,9 +196,6 @@ private:
/** A 'ping' sound effect to be played when the ball hits the ground. */
SFXBase *m_ping_sfx;
/* Used by undo and redo the firing when rewind */
Vec3 m_owner_init_pos, m_init_pos;
bool m_restoring_state;
void computeTarget();
@@ -214,7 +211,7 @@ private:
float getTunnelHeight(const Vec3 &next_xyz,
const float vertical_offset) const;
bool checkTunneling();
virtual void additionalPhysicsProperties() OVERRIDE;
void removePingSFX();
public:
RubberBall (AbstractKart* kart);
@@ -233,6 +230,7 @@ public:
// ------------------------------------------------------------------------
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
// ------------------------------------------------------------------------
virtual void onFireFlyable() OVERRIDE;
}; // RubberBall

View File

@@ -47,8 +47,6 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart)
{
m_hit_kart = NULL;
m_attached_state = RB_TO_PLUNGER;
updatePosition();
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics() || !CVS->isGLSL())
{
@@ -81,6 +79,14 @@ RubberBand::~RubberBand()
remove();
} // RubberBand
// ----------------------------------------------------------------------------
void RubberBand::reset()
{
m_hit_kart = NULL;
m_attached_state = RB_TO_PLUNGER;
updatePosition();
} // reset
// ----------------------------------------------------------------------------
/** Updates the position of the rubber band. It especially sets the
* end position of the rubber band, i.e. the side attached to the plunger,

View File

@@ -71,6 +71,7 @@ private:
public:
RubberBand(Plunger *plunger, AbstractKart *kart);
~RubberBand();
void reset();
void updateGraphics(float dt);
void update(int ticks);
void hit(AbstractKart *kart_hit, const Vec3 *track_xyz=NULL);

View File

@@ -33,8 +33,6 @@
Moveable::Moveable()
{
m_body = 0;
m_motion_state = 0;
m_node = NULL;
m_heading = 0;
} // Moveable

View File

@@ -27,8 +27,6 @@
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/rewind_info.hpp"
#include "network/rewind_manager.hpp"
#include "network/server_config.hpp"
#include "network/stk_host.hpp"
#include "physics/triangle_mesh.hpp"
@@ -488,30 +486,6 @@ void CaptureTheFlag::loseFlagForKart(int kart_id)
else
m_blue_flag->resetToBase();
}
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient())
{
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
[](){},
/*replay_function*/[dropped_trans, drop_red_flag, succeed, this]()
{
if (drop_red_flag)
{
if (succeed)
m_red_flag->dropFlagAt(dropped_trans);
else
m_red_flag->resetToBase();
}
else
{
if (succeed)
m_blue_flag->dropFlagAt(dropped_trans);
else
m_blue_flag->resetToBase();
}
}));
}
} // loseFlagForKart
// ----------------------------------------------------------------------------

View File

@@ -32,7 +32,6 @@
#include "karts/skidding.hpp"
#include "modes/profile_world.hpp"
#include "modes/world.hpp"
#include "network/rewind_manager.hpp"
/** Constructor for a check cannon.
* \param node XML node containing the parameters for this checkline.
@@ -158,8 +157,8 @@ void CheckCannon::update(float dt)
CheckLine::update(dt);
for (unsigned int i = 0; i < m_all_flyables.size(); i++)
{
if (m_all_flyables[i]->hasUndoneDestruction() ||
RewindManager::get()->isRewinding())
if (!m_all_flyables[i]->hasServerState() ||
m_all_flyables[i]->hasAnimation())
continue;
setIgnoreHeight(true);
bool triggered = isTriggered(m_flyable_previous_position[i],
@@ -176,6 +175,7 @@ void CheckCannon::update(float dt)
//m_all_flyables[i]->setAnimation(animation);
} // for i in all flyables
} // update
// ----------------------------------------------------------------------------
/** Called when the check line is triggered. This function creates a cannon
* animation object and attaches it to the kart.