Merge branch 'master' of github.com:supertuxkart/stk-code

This commit is contained in:
hiker 2018-07-26 10:18:30 +10:00
commit 7ff7e049ea
52 changed files with 833 additions and 415 deletions

View File

@ -53,9 +53,9 @@ public:
Bowling(AbstractKart* kart);
virtual ~Bowling();
static void init(const XMLNode &node, scene::IMesh *bowling);
virtual bool updateAndDelete(int ticks);
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
virtual HitEffect *getHitEffect() const;
virtual bool updateAndDelete(int ticks) OVERRIDE;
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
virtual HitEffect *getHitEffect() const OVERRIDE;
}; // Bowling

View File

@ -119,11 +119,7 @@ Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
//do not adjust height according to terrain
setAdjustUpVelocity(false);
m_body->setActivationState(DISABLE_DEACTIVATION);
m_body->applyTorque( btVector3(5,-3,7) );
additionalPhysicsProperties();
} // Cake
// -----------------------------------------------------------------------------

View File

@ -46,24 +46,36 @@ 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);
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
// ------------------------------------------------------------------------
virtual void hitTrack () { hit(NULL); }
virtual void hitTrack () OVERRIDE { 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
* function returns the velocity of this object. */
virtual const btVector3 &getVelocity() const {return m_initial_velocity;}
virtual const btVector3 &getVelocity() const OVERRIDE
{ return m_initial_velocity; }
// ------------------------------------------------------------------------
/** Kinematic objects are not allowed to have a velocity (assertion in
* bullet), so we have to do our own velocity handling here. This
* function sets the velocity of this object.
* \param v Linear velocity of this object.
*/
virtual void setVelocity(const btVector3& v) {m_initial_velocity=v; }
virtual void setVelocity(const btVector3& v) OVERRIDE
{ m_initial_velocity = v; }
}; // Cake
#endif

View File

@ -37,6 +37,11 @@
#include "karts/explosion_animation.hpp"
#include "modes/linear_world.hpp"
#include "modes/soccer_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"
#include "utils/constants.hpp"
@ -75,6 +80,10 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
m_owner_has_temporary_immunity = true;
m_do_terrain_info = true;
m_max_lifespan = -1;
m_undo_creation = false;
m_has_undone_destruction = false;
m_has_server_state = false;
m_check_created_ticks = -1;
// Add the graphical model
#ifndef SERVER_ONLY
@ -160,6 +169,10 @@ 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
// -----------------------------------------------------------------------------
@ -378,7 +391,7 @@ void Flyable::setAnimation(AbstractKartAnimation *animation)
*/
void Flyable::updateGraphics(float dt)
{
updateSmoothedGraphics(dt);
Moveable::updateSmoothedGraphics(dt);
Moveable::updateGraphics();
} // updateGraphics
@ -390,6 +403,9 @@ void Flyable::updateGraphics(float dt)
*/
bool Flyable::updateAndDelete(int ticks)
{
if (m_undo_creation)
return false;
if (hasAnimation())
{
m_animation->update(stk_config->ticks2Time(ticks));
@ -502,6 +518,8 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
*/
bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
{
if (m_undo_creation)
return false;
// the owner of this flyable should not be hit by his own flyable
if(isOwnerImmunity(kart_hit)) return false;
m_has_hit_something=true;
@ -573,5 +591,140 @@ HitEffect* Flyable::getHitEffect() const
unsigned int Flyable::getOwnerId()
{
return m_owner->getWorldKartId();
}
} // getOwnerId
// ----------------------------------------------------------------------------
BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
{
ru->push_back(getUniqueIdentity());
BareNetworkString *buffer = new BareNetworkString();
CompressNetworkBody::compress(m_body->getWorldTransform(),
m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer);
uint16_t hit_and_ticks = (m_has_hit_something ? 1 << 15 : 0) |
m_ticks_since_thrown;
buffer->addUInt16(hit_and_ticks);
return buffer;
} // saveState
// ----------------------------------------------------------------------------
void Flyable::restoreState(BareNetworkString *buffer, int count)
{
btTransform t;
Vec3 lv, av;
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
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);
uint16_t hit_and_ticks = buffer->getUInt16();
m_has_hit_something = (hit_and_ticks >> 15) == 1;
m_ticks_since_thrown = hit_and_ticks & ~(1 << 15);
if (!m_has_server_state)
m_has_server_state = true;
} // 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()
{
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;
const Vec3 *min, *max;
Track::getCurrentTrack()->getAABB(&min, &max);
btTransform t = f->m_body->getWorldTransform();
// Move it to (almost infinity), avoiding affecting current
// rewinding
t.setOrigin(*max * 2.0f);
f->m_body->setWorldTransform(t);
f->m_motion_state->setWorldTransform(t);
f->m_body->setInterpolationWorldTransform(t);
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::handleUndoDestruction()
{
if (!NetworkConfig::get()->isNetworking() ||
NetworkConfig::get()->isServer() ||
m_has_undone_destruction)
return;
m_has_undone_destruction = true;
// If destroyed during rewind, than in theroy it should be safe to delete
// without undo
if (RewindManager::get()->isRewinding())
return;
// We don't bother seeing the mesh during rewinding
m_node->setVisible(false);
std::shared_ptr<Flyable> f = getShared<Flyable>();
std::string uid = f->getUniqueIdentity();
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
/*undo_function*/[f, uid]()
{
projectile_manager->addByUID(uid, f);
},
/*replay_function*/[uid]()
{
projectile_manager->removeByUID(uid);
}));
} // handleUndoDestruction
// ----------------------------------------------------------------------------
void Flyable::computeError()
{
Moveable::checkSmoothing();
if (!m_has_server_state && m_check_created_ticks != -1 &&
World::getWorld()->getTicksSinceStart() > m_check_created_ticks)
{
const std::string& uid = getUniqueIdentity();
Log::warn("Flyable", "Item %s failed to be created on server, "
"remove it locally", uid.c_str());
projectile_manager->removeByUID(uid);
}
} // computeError
/* EOF */

View File

@ -24,6 +24,7 @@
#include "items/powerup_manager.hpp"
#include "karts/moveable.hpp"
#include "network/rewinder.hpp"
#include "tracks/terrain_info.hpp"
#include "utils/cpp2011.hpp"
@ -43,7 +44,8 @@ class XMLNode;
/**
* \ingroup items
*/
class Flyable : public Moveable, public TerrainInfo
class Flyable : public Moveable, public TerrainInfo,
public Rewinder
{
public:
private:
@ -103,6 +105,11 @@ protected:
/** Size of this flyable. */
Vec3 m_extend;
bool m_undo_creation;
bool m_has_undone_destruction;
bool m_has_server_state;
int m_check_created_ticks;
// The flyable class stores the values for each flyable type, e.g.
// speed, min_height, max_height. These variables must be static,
// so we need arrays of these variables to have different values
@ -128,11 +135,11 @@ protected:
/** Time since thrown. used so a kart can't hit himself when trying
* something, and also to put some time limit to some collectibles */
int m_ticks_since_thrown;
int16_t m_ticks_since_thrown;
/** Set to something > -1 if this flyable should auto-destrcut after
* that may ticks. */
int m_max_lifespan;
int m_max_lifespan;
/** If set to true, the kart that throwns this flyable can't collide
* with it for a short time. */
@ -160,6 +167,13 @@ protected:
const bool rotates=false,
const bool turn_around=false,
const btTransform* customDirection=NULL);
/** Used when undoing creation or destruction. */
btTransform m_saved_transform;
Vec3 m_saved_lv, m_saved_av, m_saved_gravity;
virtual void additionalPhysicsProperties() {}
public:
Flyable (AbstractKart* kart,
@ -217,6 +231,31 @@ public:
/** Returns the size (extend) of the mesh. */
const Vec3 &getExtend() const { return m_extend; }
// ------------------------------------------------------------------------
void addForRewind(const std::string& uid);
// ------------------------------------------------------------------------
virtual void undoEvent(BareNetworkString *buffer) OVERRIDE {}
// ------------------------------------------------------------------------
virtual void rewindToEvent(BareNetworkString *buffer) OVERRIDE {}
// ------------------------------------------------------------------------
virtual void undoState(BareNetworkString *buffer) OVERRIDE {}
// ------------------------------------------------------------------------
virtual void saveTransform() OVERRIDE { Moveable::prepareSmoothing(); }
// ------------------------------------------------------------------------
virtual void computeError() OVERRIDE;
// ------------------------------------------------------------------------
virtual BareNetworkString* saveState(std::vector<std::string>* ru)
OVERRIDE;
// ------------------------------------------------------------------------
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
// ------------------------------------------------------------------------
virtual void addRewindInfoEventFunctionAfterFiring();
// ------------------------------------------------------------------------
bool isUndoCreation() const { return m_undo_creation; }
// ------------------------------------------------------------------------
bool hasUndoneDestruction() const { return m_has_undone_destruction; }
// ------------------------------------------------------------------------
void handleUndoDestruction();
}; // Flyable
#endif

View File

@ -43,19 +43,20 @@
#include <string>
std::vector<scene::IMesh *> ItemManager::m_item_mesh;
std::vector<scene::IMesh *> ItemManager::m_item_lowres_mesh;
std::vector<video::SColorf> ItemManager::m_glow_color;
bool ItemManager::m_disable_item_collection = false;
ItemManager * ItemManager::m_item_manager = NULL;
std::mt19937 ItemManager::m_random_engine;
std::vector<scene::IMesh *> ItemManager::m_item_mesh;
std::vector<scene::IMesh *> ItemManager::m_item_lowres_mesh;
std::vector<video::SColorf> ItemManager::m_glow_color;
bool ItemManager::m_disable_item_collection = false;
std::shared_ptr<ItemManager> ItemManager::m_item_manager;
std::mt19937 ItemManager::m_random_engine;
//-----------------------------------------------------------------------------
/** Creates one instance of the item manager. */
void ItemManager::create()
{
assert(!m_item_manager);
m_item_manager = new ItemManager();
// Due to protected constructor use new instead of make_shared
m_item_manager = std::shared_ptr<ItemManager>(new ItemManager());
} // create
//-----------------------------------------------------------------------------
@ -63,8 +64,7 @@ void ItemManager::create()
void ItemManager::destroy()
{
assert(m_item_manager);
delete m_item_manager;
m_item_manager = NULL;
m_item_manager = nullptr;
} // destroy
//-----------------------------------------------------------------------------

View File

@ -60,7 +60,7 @@ private:
static std::mt19937 m_random_engine;
protected:
/** The instance of ItemManager while a race is on. */
static ItemManager *m_item_manager;
static std::shared_ptr<ItemManager> m_item_manager;
public:
static void loadDefaultItemMeshes();
static void removeTextures();
@ -90,9 +90,10 @@ public:
// ------------------------------------------------------------------------
/** Return an instance of the item manager (it does not automatically
* create one, call create for that). */
static ItemManager *get() {
static ItemManager *get()
{
assert(m_item_manager);
return m_item_manager;
return m_item_manager.get();
} // get
// ========================================================================
@ -119,9 +120,9 @@ protected:
virtual unsigned int insertItem(Item *item);
void setSwitchItems(const std::vector<int> &switch_items);
ItemManager();
public:
virtual ~ItemManager();
public:
virtual Item* placeItem (ItemState::ItemType type, const Vec3& xyz,
const Vec3 &normal);
virtual Item* dropNewItem (ItemState::ItemType type,

View File

@ -31,16 +31,16 @@
void NetworkItemManager::create()
{
assert(!m_item_manager);
m_item_manager = new NetworkItemManager();
auto nim = std::shared_ptr<NetworkItemManager>(new NetworkItemManager());
nim->rewinderAdd();
m_item_manager = nim;
} // create
// ============================================================================
/** Creates a new instance of the item manager. This is done at startup
* of each race. */
NetworkItemManager::NetworkItemManager()
: Rewinder("N", /*can be deleted*/false),
ItemManager()
: Rewinder("N"), ItemManager()
{
m_last_confirmed_item_ticks.clear();

View File

@ -61,10 +61,10 @@ private:
void forwardTime(int ticks);
NetworkItemManager();
virtual ~NetworkItemManager();
public:
static void create();
virtual ~NetworkItemManager();
void setSwitchItems(const std::vector<int> &switch_items);
void sendItemUpdate();

View File

@ -100,7 +100,7 @@ Plunger::Plunger(AbstractKart *kart)
{
m_rubber_band = new RubberBand(this, kart);
}
m_keep_alive = -1;
additionalPhysicsProperties();
} // Plunger
// ----------------------------------------------------------------------------

View File

@ -47,13 +47,17 @@ private:
btVector3 m_initial_velocity;
bool m_reverse_mode;
virtual void additionalPhysicsProperties() OVERRIDE { m_keep_alive = -1; }
public:
Plunger(AbstractKart *kart);
~Plunger();
static void init(const XMLNode &node, scene::IMesh* missile);
virtual bool updateAndDelete(int ticks);
virtual void hitTrack ();
virtual bool hit (AbstractKart *kart, PhysicalObject *obj=NULL);
virtual bool updateAndDelete(int ticks) OVERRIDE;
virtual void hitTrack () OVERRIDE;
virtual bool hit (AbstractKart *kart, PhysicalObject *obj=NULL)
OVERRIDE;
// ------------------------------------------------------------------------
/** Sets the keep-alive value. Setting it to 0 will remove the plunger
@ -62,7 +66,7 @@ public:
void setKeepAlive(int ticks) {m_keep_alive = ticks;}
// ------------------------------------------------------------------------
/** No hit effect when it ends. */
virtual HitEffect *getHitEffect() const {return NULL; }
virtual HitEffect *getHitEffect() const OVERRIDE { return NULL; }
// ------------------------------------------------------------------------
}; // Plunger

View File

@ -32,6 +32,7 @@
#include "karts/controller/controller.hpp"
#include "karts/kart_properties.hpp"
#include "modes/world.hpp"
#include "network/rewind_manager.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@ -211,6 +212,13 @@ void Powerup::adjustSound()
}
} // adjustSound
//-----------------------------------------------------------------------------
void Powerup::playSound()
{
if (!RewindManager::get()->isRewinding())
m_sound_use->play();
} // playSound
//-----------------------------------------------------------------------------
/** Use (fire) this powerup.
*/
@ -248,7 +256,7 @@ void Powerup::use()
{
ItemManager::get()->switchItems();
m_sound_use->setPosition(m_kart->getXYZ());
m_sound_use->play();
playSound();
break;
}
case PowerupManager::POWERUP_CAKE:
@ -258,7 +266,7 @@ void Powerup::use()
if(stk_config->m_shield_restrict_weapons)
m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield
Powerup::adjustSound();
m_sound_use->play();
playSound();
projectile_manager->newProjectile(m_kart, m_type);
break ;
@ -280,7 +288,7 @@ void Powerup::use()
if(!new_item) return;
Powerup::adjustSound();
m_sound_use->play();
playSound();
}
else // if the kart is looking forward, use the bubblegum as a shield
{
@ -330,7 +338,7 @@ void Powerup::use()
//In this case this is a workaround, since the bubblegum item has two different sounds.
Powerup::adjustSound();
m_sound_use->play();
playSound();
} // end of PowerupManager::POWERUP_BUBBLEGUM
break;
@ -359,7 +367,7 @@ void Powerup::use()
else
m_sound_use->setPosition(m_kart->getXYZ());
m_sound_use->play();
playSound();
break;
}
}
@ -418,7 +426,7 @@ void Powerup::use()
m_sound_use->setPosition(m_kart->getXYZ());
else if(player_kart)
m_sound_use->setPosition(player_kart->getXYZ());
m_sound_use->play();
playSound();
}
break;

View File

@ -36,9 +36,6 @@ class SFXBase;
class Powerup : public NoCopy
{
private:
/** A synchronised random number generator for network games. */
RandomGenerator m_random;
/** Sound effect that is being played. */
SFXBase *m_sound_use;
@ -51,6 +48,7 @@ private:
/** The owner (kart) of this powerup. */
AbstractKart* m_kart;
void playSound();
public:
Powerup (AbstractKart* kart_);
~Powerup ();

View File

@ -298,7 +298,7 @@ void PowerupManager::WeightsData::convertRankToSection(int rank, int *prev,
}
// The last kart always uses the data for the last section
if (rank == m_num_karts)
if (rank == (int)m_num_karts)
{
*prev = *next = m_weights_for_section.size() - 1;
*weight = 1.0f;
@ -600,9 +600,11 @@ void PowerupManager::unitTesting()
int num_weights = wd.m_summed_weights_for_rank[0].back();
for(int i=0; i<num_weights; i++)
{
#ifdef DEBUG
unsigned int n;
assert( powerup_manager->getRandomPowerup(1, &n, i)==POWERUP_BOWLING );
assert(n==3);
#endif
}
// Test 2: Test all possible random numbers for 5 karts and rank 5

View File

@ -139,7 +139,6 @@ public:
};
private:
const int RAND_CLASS_RANGE = 1000;
/** The icon for each powerup. */
Material* m_all_icons [POWERUP_MAX];

View File

@ -27,6 +27,8 @@
#include "items/powerup.hpp"
#include "items/rubber_ball.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "network/rewind_manager.hpp"
ProjectileManager *projectile_manager=0;
@ -45,12 +47,6 @@ void ProjectileManager::removeTextures()
//-----------------------------------------------------------------------------
void ProjectileManager::cleanup()
{
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i)
{
delete *i;
}
m_active_projectiles.clear();
for(HitEffects::iterator i = m_active_hit_effects.begin();
i != m_active_hit_effects.end(); ++i)
@ -68,12 +64,8 @@ void ProjectileManager::cleanup()
*/
void ProjectileManager::updateGraphics(float dt)
{
for (auto p = m_active_projectiles.begin();
p != m_active_projectiles.end(); ++p)
{
(*p)->updateGraphics(dt);
}
for (auto& p : m_active_projectiles)
p.second->updateGraphics(dt);
} // updateGraphics
// -----------------------------------------------------------------------------
@ -82,6 +74,8 @@ void ProjectileManager::update(int ticks)
{
updateServer(ticks);
if (RewindManager::get()->isRewinding())
return;
HitEffects::iterator he = m_active_hit_effects.begin();
while(he!=m_active_hit_effects.end())
{
@ -107,24 +101,30 @@ void ProjectileManager::update(int ticks)
/** Updates all rockets on the server (or no networking). */
void ProjectileManager::updateServer(int ticks)
{
Projectiles::iterator p = m_active_projectiles.begin();
while(p!=m_active_projectiles.end())
auto p = m_active_projectiles.begin();
while (p != m_active_projectiles.end())
{
bool can_be_deleted = (*p)->updateAndDelete(ticks);
if(can_be_deleted)
if (p->second->isUndoCreation())
{
HitEffect *he = (*p)->getHitEffect();
if(he)
addHitEffect(he);
Flyable *f=*p;
Projectiles::iterator p_next=m_active_projectiles.erase(p);
delete f;
p=p_next;
p++;
continue;
}
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);
}
else
p++;
} // while p!=m_active_projectiles.end()
} // updateServer
// -----------------------------------------------------------------------------
@ -132,20 +132,40 @@ void ProjectileManager::updateServer(int ticks)
* \param kart The kart which shoots the projectile.
* \param type Type of projectile.
*/
Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
PowerupManager::PowerupType type)
std::shared_ptr<Flyable>
ProjectileManager::newProjectile(AbstractKart *kart,
PowerupManager::PowerupType type)
{
Flyable *f;
const std::string& uid = getUniqueIdentity(kart, type);
auto it = m_active_projectiles.find(uid);
// Flyable already created during rewind
if (it != m_active_projectiles.end())
return it->second;
std::shared_ptr<Flyable> f;
switch(type)
{
case PowerupManager::POWERUP_BOWLING: f = new Bowling(kart); break;
case PowerupManager::POWERUP_PLUNGER: f = new Plunger(kart); break;
case PowerupManager::POWERUP_CAKE: f = new Cake(kart); break;
case PowerupManager::POWERUP_RUBBERBALL: f = new RubberBall(kart);
break;
default: return NULL;
case PowerupManager::POWERUP_BOWLING:
f = std::make_shared<Bowling>(kart);
break;
case PowerupManager::POWERUP_PLUNGER:
f = std::make_shared<Plunger>(kart);
break;
case PowerupManager::POWERUP_CAKE:
f = std::make_shared<Cake>(kart);
break;
case PowerupManager::POWERUP_RUBBERBALL:
f = std::make_shared<RubberBall>(kart);
break;
default:
return nullptr;
}
m_active_projectiles[uid] = f;
if (RewindManager::get()->isEnabled())
{
f->addForRewind(uid);
f->addRewindInfoEventFunctionAfterFiring();
}
m_active_projectiles.push_back(f);
return f;
} // newProjectile
@ -158,13 +178,15 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
float radius)
{
float r2 = radius*radius;
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); i++)
float r2 = radius * radius;
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
i++)
{
float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
if(dist2<r2) return true;
if (i->second->isUndoCreation())
continue;
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
if (dist2 < r2)
return true;
}
return false;
} // projectileIsClose
@ -179,21 +201,101 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
float radius, PowerupManager::PowerupType type)
{
float r2 = radius*radius;
int projectileCount = 0;
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); i++)
float r2 = radius * radius;
int projectile_count = 0;
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
i++)
{
if ((*i)->getType() == type)
if (i->second->isUndoCreation())
continue;
if (i->second->getType() == type)
{
float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
if(dist2<r2)
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
if (dist2 < r2)
{
projectileCount++;
projectile_count++;
}
}
}
return projectileCount;
return projectile_count;
} // getNearbyProjectileCount
// -----------------------------------------------------------------------------
std::string ProjectileManager::getUniqueIdentity(AbstractKart* kart,
PowerupManager::PowerupType t)
{
switch (t)
{
case PowerupManager::POWERUP_BOWLING:
return std::string("B_") +
StringUtils::toString(kart->getWorldKartId()) + "_" +
StringUtils::toString(World::getWorld()->getTicksSinceStart());
case PowerupManager::POWERUP_PLUNGER:
return std::string("P_") +
StringUtils::toString(kart->getWorldKartId()) + "_" +
StringUtils::toString(World::getWorld()->getTicksSinceStart());
case PowerupManager::POWERUP_CAKE:
return std::string("C_") +
StringUtils::toString(kart->getWorldKartId()) + "_" +
StringUtils::toString(World::getWorld()->getTicksSinceStart());
case PowerupManager::POWERUP_RUBBERBALL:
return std::string("R_") +
StringUtils::toString(kart->getWorldKartId()) + "_" +
StringUtils::toString(World::getWorld()->getTicksSinceStart());
default:
assert(false);
return "";
}
} // getUniqueIdentity
// -----------------------------------------------------------------------------
std::shared_ptr<Rewinder>
ProjectileManager::addRewinderFromNetworkState(const std::string& uid)
{
std::vector<std::string> id = StringUtils::split(uid, '_');
if (id.size() != 3)
return nullptr;
if (!(id[0] == "B" || id[0] == "P" || id[0] == "C" || id[0] == "R"))
return nullptr;
int world_id = -1;
if (!StringUtils::fromString(id[1], world_id))
return nullptr;
AbstractKart* kart = World::getWorld()->getKart(world_id);
char first_id = id[0][0];
Log::debug("ProjectileManager", "Missed a firing event or locally deleted,"
" add the flyable %s manually", uid.c_str());
switch (first_id)
{
case 'B':
{
auto f = std::make_shared<Bowling>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
}
case 'P':
{
auto f = std::make_shared<Plunger>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
}
case 'C':
{
auto f = std::make_shared<Cake>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
}
case 'R':
{
auto f = std::make_shared<RubberBall>(kart);
f->addForRewind(uid);
m_active_projectiles[uid] = f;
return f;
}
default:
assert(false);
return nullptr;
}
} // addProjectileFromNetworkState

View File

@ -19,6 +19,8 @@
#ifndef HEADER_PROJECTILEMANAGER_HPP
#define HEADER_PROJECTILEMANAGER_HPP
#include <map>
#include <memory>
#include <vector>
namespace irr
@ -32,6 +34,7 @@ namespace irr
class AbstractKart;
class Flyable;
class HitEffect;
class Rewinder;
class Track;
class Vec3;
@ -41,17 +44,18 @@ class Vec3;
class ProjectileManager : public NoCopy
{
private:
typedef std::vector<Flyable*> Projectiles;
typedef std::vector<HitEffect*> HitEffects;
/** The list of all active projectiles, i.e. projectiles which are
* currently moving on the track. */
Projectiles m_active_projectiles;
std::map<std::string, std::shared_ptr<Flyable> > m_active_projectiles;
/** All active hit effects, i.e. hit effects which are currently
* being shown or have a sfx playing. */
HitEffects m_active_hit_effects;
std::string getUniqueIdentity(AbstractKart* kart,
PowerupManager::PowerupType type);
void updateServer(int ticks);
public:
ProjectileManager() {}
@ -60,9 +64,6 @@ public:
void cleanup ();
void update (int ticks);
void updateGraphics (float dt);
Flyable* newProjectile (AbstractKart *kart,
PowerupManager::PowerupType type);
void Deactivate (Flyable *p) {}
void removeTextures ();
bool projectileIsClose(const AbstractKart * const kart,
float radius);
@ -74,6 +75,19 @@ public:
* \param hit_effect The hit effect to be added. */
void addHitEffect(HitEffect *hit_effect)
{ m_active_hit_effects.push_back(hit_effect); }
// ------------------------------------------------------------------------
std::shared_ptr<Rewinder>
addRewinderFromNetworkState(const std::string& uid);
// ------------------------------------------------------------------------
std::shared_ptr<Flyable> newProjectile(AbstractKart *kart,
PowerupManager::PowerupType type);
// ------------------------------------------------------------------------
void addByUID(const std::string& uid, std::shared_ptr<Flyable> f)
{ m_active_projectiles[uid] = f; }
// ------------------------------------------------------------------------
void removeByUID(const std::string& uid)
{ m_active_projectiles.erase(uid); }
};
extern ProjectileManager *projectile_manager;

View File

@ -89,7 +89,7 @@ AbstractKartAnimation::~AbstractKartAnimation()
Vec3 linear_velocity = kart->getBody()->getLinearVelocity();
Vec3 angular_velocity = kart->getBody()->getAngularVelocity();
btTransform transform = kart->getBody()->getWorldTransform();
RewindManager::get()->getRewindQueue().insertRewindInfo(new
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(
World::getWorld()->getTicksSinceStart(),
[kart]()

View File

@ -91,6 +91,7 @@
#include <algorithm> // for min and max
#include <iostream>
#include <limits>
#include <cmath>
@ -129,7 +130,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
m_bubblegum_ticks = 0;
m_bubblegum_torque = 0.0f;
m_invulnerable_ticks = 0;
m_squash_ticks = 0;
m_squash_time = std::numeric_limits<float>::max();
m_shadow = NULL;
m_wheel_box = NULL;
@ -366,7 +367,7 @@ void Kart::reset()
m_bubblegum_ticks = 0;
m_bubblegum_torque = 0.0f;
m_invulnerable_ticks = 0;
m_squash_ticks = 0;
m_squash_time = std::numeric_limits<float>::max();
m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
m_collected_energy = 0;
m_has_started = false;
@ -1275,34 +1276,12 @@ void Kart::update(int ticks)
// Reset any instand speed increase in the bullet kart
m_vehicle->setMinSpeed(0);
if(m_squash_ticks>=0)
{
m_squash_ticks-=ticks;
// If squasing time ends, reset the model
if(m_squash_ticks<=0)
{
m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
scene::ISceneNode* node =
m_kart_model->getAnimatedNode() ?
m_kart_model->getAnimatedNode() : m_node;
if (m_vehicle->getNumWheels() > 0)
{
scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
{
if (wheels[i])
wheels[i]->setParent(node);
}
}
}
} // if squashed
if (m_bubblegum_ticks > 0.0f)
if (m_bubblegum_ticks > 0)
{
m_bubblegum_ticks -= ticks;
if (m_bubblegum_ticks <= 0.0f)
if (m_bubblegum_ticks <= 0)
{
m_bubblegum_torque = 0.0f;
m_bubblegum_torque = 0;
}
}
@ -1752,23 +1731,42 @@ void Kart::setSquash(float time, float slowdown)
ExplosionAnimation::create(this);
return;
}
m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown,
stk_config->time2Ticks(0.1f),
stk_config->time2Ticks(time));
if (m_vehicle->getNumWheels() > 0)
#ifndef SERVER_ONLY
if (m_squash_time == std::numeric_limits<float>::max())
{
if (!m_wheel_box)
m_wheel_box = irr_driver->getSceneManager()->addDummyTransformationSceneNode(m_node);
scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
if (m_vehicle->getNumWheels() > 0)
{
if (wheels[i])
wheels[i]->setParent(m_wheel_box);
if (!m_wheel_box)
{
m_wheel_box = irr_driver->getSceneManager()
->addDummyTransformationSceneNode(m_node);
}
scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); i++)
{
if (wheels[i])
wheels[i]->setParent(m_wheel_box);
}
m_wheel_box->getRelativeTransformationMatrix()
.setScale(core::vector3df(1.0f, 2.0f, 1.0f));
}
m_wheel_box->getRelativeTransformationMatrix().setScale(core::vector3df(1.0f, 2.0f, 1.0f));
m_squash_time = time;
}
m_squash_ticks = stk_config->time2Ticks(time);
#endif
} // setSquash
//-----------------------------------------------------------------------------
/** Returns if the kart is currently being squashed
*/
bool Kart::isSquashed() const
{
return m_max_speed->isSpeedDecreaseActive(MaxSpeed::MS_DECREASE_SQUASH);
} // setSquash
//-----------------------------------------------------------------------------
@ -2941,6 +2939,30 @@ void Kart::updateGraphics(float dt)
if (m_custom_sounds[n] != NULL) m_custom_sounds[n]->position(getXYZ());
}
*/
if (m_squash_time != std::numeric_limits<float>::max())
{
m_squash_time -= dt;
// If squasing time ends, reset the model
if (m_squash_time <= 0.0f)
{
m_squash_time = std::numeric_limits<float>::max();
m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
scene::ISceneNode* node =
m_kart_model->getAnimatedNode() ?
m_kart_model->getAnimatedNode() : m_node;
if (m_vehicle->getNumWheels() > 0)
{
scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
{
if (wheels[i])
wheels[i]->setParent(node);
}
}
}
} // if squashed
for (int i = 0; i < EMITTER_COUNT; i++)
m_emitters[i]->setPosition(getXYZ());
m_skid_sound->setPosition(getXYZ());

View File

@ -160,17 +160,17 @@ protected:
int m_bounce_back_ticks;
/** Time a kart is invulnerable. */
int m_invulnerable_ticks;
int16_t m_invulnerable_ticks;
/** How long a kart is being squashed. If this is >0
* the kart is squashed. */
int m_squash_ticks;
float m_squash_time;
/** Current leaning of the kart. */
float m_current_lean;
/** If > 0 then bubble gum effect is on. This is the sliding when hitting a gum on the floor, not the shield. */
int m_bubblegum_ticks;
int16_t m_bubblegum_ticks;
/** The torque to apply after hitting a bubble gum. */
float m_bubblegum_torque;
@ -218,13 +218,10 @@ protected:
/** When a kart has its view blocked by the plunger, this variable will be
* > 0 the number it contains is the time left before removing plunger. */
int m_view_blocked_by_plunger;
int16_t m_view_blocked_by_plunger;
/** The current speed (i.e. length of velocity vector) of this kart. */
float m_speed;
/** For camera handling an exponentially smoothened value is used, which
* reduces stuttering of the camera. */
float m_smoothed_speed;
/** For smoothing engine sound**/
float m_last_factor_engine_sound;
@ -499,7 +496,7 @@ public:
virtual bool isOnMinNitroTime() const OVERRIDE { return m_min_nitro_ticks > 0; }
// ------------------------------------------------------------------------
/** Returns if the kart is currently being squashed. */
virtual bool isSquashed() const OVERRIDE { return m_squash_ticks >0; }
virtual bool isSquashed() const OVERRIDE;
// ------------------------------------------------------------------------
/** Shows the star effect for a certain time. */
virtual void showStarEffect(float t) OVERRIDE;

View File

@ -38,8 +38,7 @@ KartRewinder::KartRewinder(const std::string& ident,
const btTransform& init_transform,
PerPlayerDifficulty difficulty,
std::shared_ptr<RenderInfo> ri)
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id),
/*can_be_destroyed*/ false)
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id))
, Kart(ident, world_kart_id, position, init_transform, difficulty,
ri)
{
@ -144,6 +143,15 @@ BareNetworkString* KartRewinder::saveState(std::vector<std::string>* ru)
// -----------
m_skidding->saveState(buffer);
// 6) Firing and related handling
// -----------
buffer->addUInt16(m_bubblegum_ticks);
buffer->addUInt16(m_view_blocked_by_plunger);
// m_invulnerable_ticks will not be negative
uint16_t fire_and_invulnerable = (m_fire_clicked ? 1 << 15 : 0) |
m_invulnerable_ticks;
buffer->addUInt16(fire_and_invulnerable);
return buffer;
} // saveState
@ -203,15 +211,21 @@ void KartRewinder::restoreState(BareNetworkString *buffer, int count)
float nitro = buffer->getFloat();
setEnergy(nitro);
// 5) Max speed info
// 4) Max speed info
// ------------------
m_max_speed->rewindTo(buffer);
// 6) Skidding
// 5) Skidding
// -----------
m_skidding->rewindTo(buffer);
return;
// 6) Firing and related handling
// -----------
m_bubblegum_ticks = buffer->getUInt16();
m_view_blocked_by_plunger = buffer->getUInt16();
uint16_t fire_and_invulnerable = buffer->getUInt16();
m_fire_clicked = (fire_and_invulnerable >> 15) == 1;
m_invulnerable_ticks = fire_and_invulnerable & ~(1 << 15);
} // restoreState
// ----------------------------------------------------------------------------
@ -223,25 +237,16 @@ void KartRewinder::update(int ticks)
Kart::update(ticks);
} // update
// ----------------------------------------------------------------------------
void KartRewinder::rewindToEvent(BareNetworkString *buffer)
{
} // rewindToEvent
// ----------------------------------------------------------------------------
std::function<void()> KartRewinder::getLocalStateRestoreFunction()
{
if (m_eliminated)
return nullptr;
// In theory all ticks / boolean related stuff can be saved locally
// Variable can be saved locally if its adjustment only depends on the kart
// itself
bool has_started = m_has_started;
int bubblegum_ticks = m_bubblegum_ticks;
int bounce_back_ticks = m_bounce_back_ticks;
int invulnerable_ticks = m_invulnerable_ticks;
int squash_ticks = m_squash_ticks;
bool fire_clicked = m_fire_clicked;
int view_blocked_by_plunger = m_view_blocked_by_plunger;
int brake_ticks = m_brake_ticks;
int8_t min_nitro_ticks = m_min_nitro_ticks;
@ -259,18 +264,11 @@ std::function<void()> KartRewinder::getLocalStateRestoreFunction()
steer_val_r = pc->m_steer_val_r;
}
return [has_started, bubblegum_ticks, bounce_back_ticks,
invulnerable_ticks, squash_ticks, fire_clicked,
view_blocked_by_plunger, brake_ticks, min_nitro_ticks, initial_speed,
node_scale, steer_val_l, steer_val_r, this]()
return [has_started, bounce_back_ticks, brake_ticks, min_nitro_ticks,
initial_speed, node_scale, steer_val_l, steer_val_r, this]()
{
m_has_started = has_started;
m_bubblegum_ticks = bubblegum_ticks;
m_bounce_back_ticks = bounce_back_ticks;
m_invulnerable_ticks = invulnerable_ticks;
m_squash_ticks = squash_ticks;
m_fire_clicked = fire_clicked;
m_view_blocked_by_plunger = view_blocked_by_plunger;
m_brake_ticks = brake_ticks;
m_min_nitro_ticks = min_nitro_ticks;
getAttachment()->setInitialSpeed(initial_speed);

View File

@ -48,7 +48,7 @@ public:
OVERRIDE;
void reset() OVERRIDE;
virtual void restoreState(BareNetworkString *p, int count) OVERRIDE;
virtual void rewindToEvent(BareNetworkString *p) OVERRIDE;
virtual void rewindToEvent(BareNetworkString *p) OVERRIDE {}
virtual void update(int ticks) OVERRIDE;
// -------------------------------------------------------------------------
virtual float getSteerPercent() const OVERRIDE

View File

@ -280,6 +280,15 @@ int MaxSpeed::getSpeedIncreaseTicksLeft(unsigned int category)
return m_speed_increase[category].getTimeLeft();
} // getSpeedIncreaseTimeLeft
// ----------------------------------------------------------------------------
/** Returns if decreased speed is active in the given category.
* \param category Which category to report on.
*/
int MaxSpeed::isSpeedDecreaseActive(unsigned int category)
{
return m_speed_decrease[category].isActive();
} // isSpeedDecreaseActive
// ----------------------------------------------------------------------------
/** Updates all speed increase and decrease objects, and determines the
* current maximum speed. Note that the function can be called with

View File

@ -158,11 +158,13 @@ private:
// --------------------------------------------------------------------
/** Returns the current slowdown fracftion, taking a 'fade in'
* into account. */
float getSlowdownFraction() const {return m_current_fraction;}
float getSlowdownFraction() const { return m_current_fraction; }
// --------------------------------------------------------------------
int getTimeLeft() const { return m_duration; }
// --------------------------------------------------------------------
/** Returns if this speed decrease is active atm. A duration of
* -1 indicates an ongoing effect. */
bool isActive() const { return m_duration > 0 || m_duration <= -1.0f; }
bool isActive() const { return m_duration > 0 || m_duration <= -1; }
}; // SpeedDecrease
// ------------------------------------------------------------------------
@ -188,6 +190,7 @@ public:
void setSlowdown(unsigned int category, float max_speed_fraction,
int fade_in_time, int duration=-1);
int getSpeedIncreaseTicksLeft(unsigned int category);
int isSpeedDecreaseActive(unsigned int category);
void update(int ticks);
void reset();
void saveState(BareNetworkString *buffer) const;

View File

@ -176,7 +176,7 @@ void LinearWorld::update(int ticks)
for(unsigned int n=0; n<kart_amount; n++)
{
KartInfo& kart_info = m_kart_info[n];
AbstractKart* kart = m_karts[n];
AbstractKart* kart = m_karts[n].get();
// Nothing to do for karts that are currently being
// rescued or eliminated
@ -218,7 +218,7 @@ void LinearWorld::update(int ticks)
// Update the estimated finish time.
// This is used by the AI
m_kart_info[i].m_estimated_finish =
estimateFinishTimeForKart(m_karts[i]);
estimateFinishTimeForKart(m_karts[i].get());
}
// If one player and a ghost, or two compared ghosts,
// compute the live time difference
@ -328,7 +328,7 @@ void LinearWorld::updateLiveDifference()
void LinearWorld::newLap(unsigned int kart_index)
{
KartInfo &kart_info = m_kart_info[kart_index];
AbstractKart *kart = m_karts[kart_index];
AbstractKart *kart = m_karts[kart_index].get();
// Reset reset-after-lap achievements
PlayerProfile *p = PlayerManager::getCurrentPlayer();
@ -556,7 +556,7 @@ void LinearWorld::getKartsDisplayInfo(
for(unsigned int i = 0; i < kart_amount ; i++)
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
AbstractKart* kart = m_karts[i];
AbstractKart* kart = m_karts[i].get();
// reset color
rank_info.m_color = video::SColor(255, 255, 255, 255);
@ -585,7 +585,7 @@ void LinearWorld::getKartsDisplayInfo(
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
KartInfo& kart_info = m_kart_info[i];
AbstractKart* kart = m_karts[i];
AbstractKart* kart = m_karts[i].get();
const int position = kart->getPosition();
@ -799,7 +799,7 @@ void LinearWorld::updateRacePosition()
// so that debug output is still correct!!!!!!!!!!!
for (unsigned int i=0; i<kart_amount; i++)
{
AbstractKart* kart = m_karts[i];
AbstractKart* kart = m_karts[i].get();
// Karts that are either eliminated or have finished the
// race already have their (final) position assigned. If
// these karts would get their rank updated, it could happen
@ -898,7 +898,7 @@ void LinearWorld::updateRacePosition()
Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime());
for (unsigned int i=0; i<kart_amount; i++)
{
AbstractKart* kart = m_karts[i];
AbstractKart* kart = m_karts[i].get();
Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u,"
" progress %u, finished %d, eliminated %d, initial position %u.",
kart->getIdent().c_str(),
@ -973,7 +973,7 @@ void LinearWorld::checkForWrongDirection(unsigned int i, float dt)
KartInfo &ki = m_kart_info[i];
const AbstractKart *kart=m_karts[i];
const AbstractKart *kart=m_karts[i].get();
// If the kart can go in more than one directions from the current track
// don't do any reverse message handling, since it is likely that there
// will be one direction in which it isn't going backwards anyway.

View File

@ -103,19 +103,18 @@ void ProfileWorld::setProfileModeLaps(int laps)
* this player globally (i.e. including network players).
* \param init_pos The start XYZ coordinates.
*/
AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType type,
PerPlayerDifficulty difficulty)
std::shared_ptr<AbstractKart> ProfileWorld::createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
{
btTransform init_pos = getStartTransform(index);
Kart *new_kart = new KartWithStats(kart_ident,
/*world kart id*/ index,
/*position*/ index+1,
init_pos, difficulty);
std::shared_ptr<KartWithStats> new_kart =
std::make_shared<KartWithStats>(kart_ident, /*world kart id*/ index,
/*position*/ index + 1, init_pos, difficulty);
new_kart->init(RaceManager::KT_AI);
Controller *controller = loadAIController(new_kart);
Controller *controller = loadAIController(new_kart.get());
new_kart->setController(controller);
// Create a camera for the last kart (since this way more of the
@ -123,7 +122,7 @@ AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
if (index == (int)race_manager->getNumberOfKarts()-1)
{
// The camera keeps track of all cameras and will free them
Camera::createCamera(new_kart, local_player_id);
Camera::createCamera(new_kart.get(), local_player_id);
}
return new_kart;
} // createKart
@ -197,7 +196,7 @@ void ProfileWorld::enterRaceOverState()
// ---------- update rank ------
if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
continue;
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i].get()));
}
// Print framerate statistics
@ -229,9 +228,9 @@ void ProfileWorld::enterRaceOverState()
std::set<std::string> all_groups;
for ( KartList::size_type i = 0; i < m_karts.size(); ++i)
for (KartList::size_type i = 0; i < m_karts.size(); ++i)
{
KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);
auto kart = std::dynamic_pointer_cast<KartWithStats>(m_karts[i]);
max_t = std::max(max_t, kart->getFinishTime());
min_t = std::min(min_t, kart->getFinishTime());
@ -285,7 +284,7 @@ void ProfileWorld::enterRaceOverState()
float av_time = 0.0f, energy = 0;
for ( unsigned int i = 0; i < (unsigned int)m_karts.size(); ++i)
{
KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);
auto kart = std::dynamic_pointer_cast<KartWithStats>(m_karts[i]);
const std::string &name=kart->getController()->getControllerName();
if(name!=*it)
continue;

View File

@ -72,10 +72,10 @@ protected:
* used by DemoWorld. */
static int m_num_laps;
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType type,
PerPlayerDifficulty difficulty);
virtual std::shared_ptr<AbstractKart> createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType type,
PerPlayerDifficulty difficulty);
public:
ProfileWorld();

View File

@ -228,7 +228,7 @@ void SoccerWorld::update(int ticks)
{
for (unsigned int i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
auto& kart = m_karts[i];
if (kart->isEliminated())
continue;
kart->getBody()->setLinearVelocity(Vec3(0.0f));
@ -335,7 +335,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
}
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
auto& kart = m_karts[i];
if (kart->isEliminated())
continue;
kart->getBody()->setLinearVelocity(Vec3(0.0f));
@ -356,7 +356,7 @@ void SoccerWorld::handleResetBallFromServer(const NetworkString& ns)
"%d when reset player", ticks_back_to_own_goal, ticks_now);
return;
}
RewindManager::get()->getRewindQueue().insertRewindInfo(new
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(ticks_back_to_own_goal,
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
@ -406,7 +406,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
m_ball->setEnabled(false);
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
auto& kart = m_karts[i];
if (kart->isEliminated())
continue;
btTransform transform_now = kart->getBody()->getWorldTransform();
@ -416,7 +416,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
kart->setTrans(transform_now);
m_goal_transforms[i] = transform_now;
}
RewindManager::get()->getRewindQueue().insertRewindInfo(new
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(ticks_back_to_own_goal,
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
@ -431,7 +431,7 @@ void SoccerWorld::resetKartsToSelfGoals()
setPhase(WorldStatus::RACE_PHASE);
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
auto& kart = m_karts[i];
if (kart->isEliminated())
continue;
@ -439,7 +439,7 @@ void SoccerWorld::resetKartsToSelfGoals()
kart->getBody()->setAngularVelocity(Vec3(0.0f));
unsigned index = m_kart_position_map.at(kart->getWorldKartId());
btTransform t = Track::getCurrentTrack()->getStartTransform(index);
moveKartTo(kart, t);
moveKartTo(kart.get(), t);
}
} // resetKartsToSelfGoals
@ -532,10 +532,10 @@ bool SoccerWorld::getKartSoccerResult(unsigned int kart_id) const
} // getKartSoccerResult
//-----------------------------------------------------------------------------
AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
std::shared_ptr<AbstractKart> SoccerWorld::createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
{
int cur_red = getTeamNum(SOCCER_TEAM_RED);
int cur_blue = getTeamNum(SOCCER_TEAM_BLUE);
@ -590,16 +590,19 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
ri = (team == SOCCER_TEAM_BLUE ? std::make_shared<RenderInfo>(0.66f) :
std::make_shared<RenderInfo>(1.0f));
AbstractKart* new_kart;
std::shared_ptr<AbstractKart> new_kart;
if (RewindManager::get()->isEnabled())
{
new_kart = new KartRewinder(kart_ident, index, position, init_pos,
difficulty, ri);
auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
init_pos, difficulty, ri);
kr->rewinderAdd();
new_kart = kr;
}
else
{
new_kart = new Kart(kart_ident, index, position, init_pos, difficulty,
ri);
new_kart = std::make_shared<Kart>(kart_ident, index, position,
init_pos, difficulty, ri);
}
new_kart->init(race_manager->getKartType(index));
@ -608,18 +611,18 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
switch(kart_type)
{
case RaceManager::KT_PLAYER:
controller = new LocalPlayerController(new_kart, local_player_id,
controller = new LocalPlayerController(new_kart.get(), local_player_id,
difficulty);
m_num_players ++;
break;
case RaceManager::KT_NETWORK_PLAYER:
controller = new NetworkPlayerController(new_kart);
controller = new NetworkPlayerController(new_kart.get());
if (!online_name.empty())
new_kart->setOnScreenText(online_name.c_str());
m_num_players++;
break;
case RaceManager::KT_AI:
controller = loadAIController(new_kart);
controller = loadAIController(new_kart.get());
break;
case RaceManager::KT_GHOST:
break;

View File

@ -51,10 +51,10 @@ public:
}; // ScorerData
protected:
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType type,
PerPlayerDifficulty difficulty) OVERRIDE;
virtual std::shared_ptr<AbstractKart> createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType type,
PerPlayerDifficulty difficulty) OVERRIDE;
private:
class KartDistanceMap

View File

@ -103,7 +103,7 @@ void StandardRace::endRaceEarly()
for (unsigned int i = 1; i <= kart_amount; i++)
{
int kartid = m_position_index[i-1];
AbstractKart* kart = m_karts[kartid];
AbstractKart* kart = m_karts[kartid].get();
if (kart->hasFinishedRace())
{
@ -140,7 +140,7 @@ void StandardRace::endRaceEarly()
int kartid = active_players[i];
int position = getNumKarts() - (int) active_players.size() + 1 + i;
setKartPosition(kartid, position);
float punished_time = estimateFinishTimeForKart(m_karts[kartid])
float punished_time = estimateFinishTimeForKart(m_karts[kartid].get())
+ worse_finish_time - WorldStatus::getTime();
m_karts[kartid]->finishedRace(punished_time);

View File

@ -722,18 +722,18 @@ void ThreeStrikesBattle::loadCustomModels()
// Now add them
for (unsigned int i = 0; i < pos.size(); i++)
{
AbstractKart* sta = new Kart(sta_list[i], (int)m_karts.size(),
auto sta = std::make_shared<Kart>(sta_list[i], (int)m_karts.size(),
(int)m_karts.size() + 1, pos[i], PLAYER_DIFFICULTY_NORMAL,
std::make_shared<RenderInfo>(1.0f));
sta->init(RaceManager::KartType::KT_SPARE_TIRE);
sta->setController(new SpareTireAI(sta));
sta->setController(new SpareTireAI(sta.get()));
m_karts.push_back(sta);
race_manager->addSpareTireKart(sta_list[i]);
// Copy STA pointer to m_spare_tire_karts array, allowing them
// to respawn easily
m_spare_tire_karts.push_back(sta);
m_spare_tire_karts.push_back(sta.get());
}
unsigned int sta_num = race_manager->getNumSpareTireKarts();
assert(m_spare_tire_karts.size() == sta_num);

View File

@ -212,10 +212,9 @@ void World::init()
: race_manager->getKartIdent(i);
int local_player_id = race_manager->getKartLocalPlayerId(i);
int global_player_id = race_manager->getKartGlobalPlayerId(i);
AbstractKart* newkart = createKart(kart_ident, i, local_player_id,
global_player_id,
race_manager->getKartType(i),
race_manager->getPlayerDifficulty(i));
auto newkart = createKart(kart_ident, i, local_player_id,
global_player_id, race_manager->getKartType(i),
race_manager->getPlayerDifficulty(i));
m_karts.push_back(newkart);
} // for i
@ -301,6 +300,7 @@ void World::reset()
SFXManager::get()->resumeAll();
projectile_manager->cleanup();
RewindManager::get()->reset();
race_manager->reset();
// Make sure to overwrite the data from the previous race.
if(!history->replayHistory()) history->initRecording();
@ -334,10 +334,10 @@ void World::createRaceGUI()
* \param global_player_id If the kart is a player kart this is the index of
* this player globally (i.e. including network players).
*/
AbstractKart *World::createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
std::shared_ptr<AbstractKart> World::createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
{
unsigned int gk = 0;
if (race_manager->hasGhostKarts())
@ -355,13 +355,19 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
int position = index+1;
btTransform init_pos = getStartTransform(index - gk);
AbstractKart *new_kart;
std::shared_ptr<AbstractKart> new_kart;
if (RewindManager::get()->isEnabled())
new_kart = new KartRewinder(kart_ident, index, position, init_pos,
difficulty, ri);
{
auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
init_pos, difficulty, ri);
kr->rewinderAdd();
new_kart = kr;
}
else
new_kart = new Kart(kart_ident, index, position, init_pos, difficulty,
ri);
{
new_kart = std::make_shared<Kart>(kart_ident, index, position,
init_pos, difficulty, ri);
}
new_kart->init(race_manager->getKartType(index));
Controller *controller = NULL;
@ -369,7 +375,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
{
case RaceManager::KT_PLAYER:
{
controller = new LocalPlayerController(new_kart, local_player_id,
controller = new LocalPlayerController(new_kart.get(), local_player_id,
difficulty);
const PlayerProfile* p = StateManager::get()
->getActivePlayer(local_player_id)->getConstProfile();
@ -383,7 +389,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
}
case RaceManager::KT_NETWORK_PLAYER:
{
controller = new NetworkPlayerController(new_kart);
controller = new NetworkPlayerController(new_kart.get());
if (!online_name.empty())
new_kart->setOnScreenText(online_name.c_str());
m_num_players++;
@ -391,7 +397,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
}
case RaceManager::KT_AI:
{
controller = loadAIController(new_kart);
controller = loadAIController(new_kart.get());
break;
}
case RaceManager::KT_GHOST:
@ -417,7 +423,7 @@ const btTransform &World::getStartTransform(int index)
/** Creates an AI controller for the kart.
* \param kart The kart to be controlled by an AI.
*/
Controller* World::loadAIController(AbstractKart *kart)
Controller* World::loadAIController(AbstractKart* kart)
{
Controller *controller;
int turn=0;
@ -485,13 +491,7 @@ World::~World()
Weather::kill();
for ( unsigned int i = 0 ; i < m_karts.size() ; i++ )
{
// Let ReplayPlay destroy the ghost karts
if (m_karts[i]->isGhostKart()) continue;
delete m_karts[i];
}
m_karts.clear();
if(race_manager->hasGhostKarts() || race_manager->isRecordingRace())
{
// Destroy the old replay object, which also stored the ghost
@ -502,7 +502,6 @@ World::~World()
ReplayPlay::destroy();
ReplayPlay::create();
}
m_karts.clear();
if(race_manager->isRecordingRace())
ReplayRecorder::get()->reset();
race_manager->setRaceGhostKarts(false);
@ -567,7 +566,8 @@ void World::terminateRace()
{
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
{
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
m_karts[i]->finishedRace(
estimateFinishTimeForKart(m_karts[i].get()));
}
} // i<kart_amount
@ -699,7 +699,7 @@ void World::resetAllKarts()
btTransform t = getRescueTransform(rescue_pos);
// This will print out warnings if there is no terrain under
// the kart, or the kart is being dropped on a reset texture
moveKartTo(m_karts[kart_id], t);
moveKartTo(m_karts[kart_id].get(), t);
} // rescue_pos<getNumberOfRescuePositions
@ -725,7 +725,7 @@ void World::resetAllKarts()
Vec3 up_offset = (*i)->getNormal() * (0.5f * ((*i)->getKartHeight()));
(*i)->setXYZ(xyz+up_offset);
bool kart_over_ground = Track::getCurrentTrack()->findGround(*i);
bool kart_over_ground = Track::getCurrentTrack()->findGround(i->get());
if (!kart_over_ground)
{
@ -1055,14 +1055,16 @@ void World::update(int ticks)
m_karts[i]->update(ticks);
}
PROFILER_POP_CPU_MARKER();
if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(ticks);
Physics::getInstance()->update(ticks);
PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
projectile_manager->update(ticks);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("World::update (physics)", 0xa0, 0x7F, 0x00);
Physics::getInstance()->update(ticks);
PROFILER_POP_CPU_MARKER();
PROFILER_POP_CPU_MARKER();
#ifdef DEBUG
@ -1165,7 +1167,7 @@ void World::updateHighscores(int* best_highscore_rank)
if (!m_karts[index[pos]]->hasFinishedRace()) continue;
assert(index[pos] < m_karts.size());
Kart *k = (Kart*)m_karts[index[pos]];
Kart *k = (Kart*)m_karts[index[pos]].get();
Highscores* highscores = getHighscores();
@ -1197,14 +1199,17 @@ void World::updateHighscores(int* best_highscore_rank)
*/
AbstractKart *World::getPlayerKart(unsigned int n) const
{
unsigned int count=-1;
unsigned int count = -1;
for(unsigned int i=0; i<m_karts.size(); i++)
if(m_karts[i]->getController()->isPlayerController())
for(unsigned int i = 0; i < m_karts.size(); i++)
{
if (m_karts[i]->getController()->isPlayerController())
{
count++;
if(count==n) return m_karts[i];
if (count == n)
return m_karts[i].get();
}
}
return NULL;
} // getPlayerKart
@ -1225,7 +1230,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
void World::eliminateKart(int kart_id, bool notify_of_elimination)
{
assert(kart_id < (int)m_karts.size());
AbstractKart *kart = m_karts[kart_id];
AbstractKart *kart = m_karts[kart_id].get();
if (kart->isGhostKart()) return;
// Display a message about the eliminated kart in the race guia

View File

@ -25,6 +25,7 @@
* battle, etc.)
*/
#include <memory>
#include <vector>
#include <stdexcept>
@ -80,7 +81,7 @@ public:
class World : public WorldStatus
{
public:
typedef std::vector<AbstractKart*> KartList;
typedef std::vector<std::shared_ptr<AbstractKart> > KartList;
private:
/** A pointer to the global world object for a race. */
static World *m_world;
@ -117,10 +118,10 @@ protected:
Controller*
loadAIController (AbstractKart *kart);
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
int local_player_id, int global_player_id,
RaceManager::KartType type,
PerPlayerDifficulty difficulty);
virtual std::shared_ptr<AbstractKart> createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType type,
PerPlayerDifficulty difficulty);
/** Pointer to the race GUI. The race GUI is handled by world. */
RaceGUIBase *m_race_gui;
@ -293,7 +294,7 @@ public:
/** Returns the kart with a given world id. */
AbstractKart *getKart(int kartId) const {
assert(kartId >= 0 && kartId < int(m_karts.size()));
return m_karts[kartId]; }
return m_karts[kartId].get(); }
// ------------------------------------------------------------------------
/** Returns all karts. */
const KartList & getKarts() const { return m_karts; }

View File

@ -82,7 +82,7 @@ AbstractKart* WorldWithRank::getKartAtPosition(unsigned int p) const
if(p<1 || p>m_position_index.size())
return NULL;
return m_karts[m_position_index[p-1]];
return m_karts[m_position_index[p-1]].get();
} // getKartAtPosition
//-----------------------------------------------------------------------------

View File

@ -199,7 +199,8 @@ public:
{
return (char*)(m_buffer.data()+m_current_offset);
} // getCurrentData
// ------------------------------------------------------------------------
int getCurrentOffset() const { return m_current_offset; }
// ------------------------------------------------------------------------
/** Returns the remaining length of the network string. */
unsigned int size() const { return (int)m_buffer.size()-m_current_offset; }

View File

@ -19,8 +19,9 @@
#include "network/rewind_info.hpp"
#include "network/network_config.hpp"
#include "network/rewinder.hpp"
#include "network/rewind_manager.hpp"
#include "physics/physics.hpp"
#include "items/projectile_manager.hpp"
/** Constructor for a state: it only takes the size, and allocates a buffer
* for all state info.
@ -63,16 +64,44 @@ void RewindInfoState::restore()
m_buffer->reset();
for (const std::string& name : m_rewinder_using)
{
uint16_t count = m_buffer->getUInt16();
Rewinder* r = RewindManager::get()->getRewinder(name);
if (r == NULL)
const uint16_t data_size = m_buffer->getUInt16();
const unsigned current_offset_now = m_buffer->getCurrentOffset();
std::shared_ptr<Rewinder> r =
RewindManager::get()->getRewinder(name);
if (!r)
{
// For now we only need to get missing rewinder from
// projectile_manager
r = projectile_manager->addRewinderFromNetworkState(name);
}
if (!r)
{
Log::error("RewindInfoState", "Missing rewinder %s",
name.c_str());
m_buffer->skip(count);
m_buffer->skip(data_size);
continue;
}
r->restoreState(m_buffer, count);
try
{
r->restoreState(m_buffer, data_size);
}
catch (std::exception& e)
{
Log::error("RewindInfoState", "Restore state error: %s",
e.what());
m_buffer->reset();
m_buffer->skip(current_offset_now + data_size);
continue;
}
if (m_buffer->getCurrentOffset() - current_offset_now != data_size)
{
Log::error("RewindInfoState", "Wrong size read when restore "
"state, incompatible binary?");
m_buffer->reset();
m_buffer->skip(current_offset_now + data_size);
}
} // for all rewinder
} // restore

View File

@ -21,7 +21,6 @@
#include "network/event_rewinder.hpp"
#include "network/network_string.hpp"
#include "network/rewinder.hpp"
#include "utils/cpp2011.hpp"
#include "utils/leak_check.hpp"
#include "utils/ptr_vector.hpp"
@ -173,14 +172,18 @@ public:
class RewindInfoEventFunction : public RewindInfo
{
private:
const std::function<void()> m_undo_function, m_replay_function;
const std::function<void()> m_undo_function, m_replay_function,
m_destroy_function;
public:
RewindInfoEventFunction(int ticks,
std::function<void()> undo_function = [](){},
std::function<void()> replay_function = [](){},
bool is_confirmed = true)
: RewindInfo(ticks, is_confirmed),
m_undo_function(undo_function), m_replay_function(replay_function) {}
std::function<void()> destroy_function = [](){})
: RewindInfo(ticks, true/*is_confirmed*/),
m_undo_function(undo_function), m_replay_function(replay_function),
m_destroy_function(destroy_function) {}
// ------------------------------------------------------------------------
~RewindInfoEventFunction() { m_destroy_function(); }
// ------------------------------------------------------------------------
/** An event is never 'restored', it is only rewound. */
void restore() {}

View File

@ -82,18 +82,7 @@ void RewindManager::reset()
if (!m_enable_rewind_manager) return;
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
{
if (!it->second->canBeDestroyed())
{
it++;
continue;
}
Rewinder* rewinder = it->second;
it = m_all_rewinder.erase(it);
delete rewinder;
}
clearExpiredRewinder();
m_rewind_queue.reset();
} // reset
@ -166,7 +155,9 @@ void RewindManager::saveState()
{
// TODO: check if it's worth passing in a sufficiently large buffer from
// GameProtocol - this would save the copy operation.
BareNetworkString* buffer = p.second->saveState(&rewinder_using);
BareNetworkString* buffer = NULL;
if (auto r = p.second.lock())
buffer = r->saveState(&rewinder_using);
if (buffer != NULL)
{
m_overall_state_size += buffer->size();
@ -197,12 +188,16 @@ void RewindManager::update(int ticks_not_used)
if (ticks - m_last_saved_state < m_state_frequency)
return;
// Save state
// Save state, remove expired rewinder first
clearExpiredRewinder();
if (NetworkConfig::get()->isClient())
{
auto& ret = m_local_state[ticks];
for (auto& p : m_all_rewinder)
ret.push_back(p.second->getLocalStateRestoreFunction());
{
if (auto r = p.second.lock())
ret.push_back(r->getLocalStateRestoreFunction());
}
}
else
{
@ -222,6 +217,10 @@ void RewindManager::update(int ticks_not_used)
*/
void RewindManager::playEventsTill(int world_ticks, int *ticks)
{
// We add the RewindInfoEventFunction to rewind queue before and after
// possible rewind, some RewindInfoEventFunction can be created during
// rewind
mergeRewindInfoEventFunction();
bool needs_rewind;
int rewind_ticks;
@ -255,6 +254,20 @@ void RewindManager::playEventsTill(int world_ticks, int *ticks)
m_is_rewinding = false;
} // playEventsTill
// ----------------------------------------------------------------------------
/** Adds a Rewinder to the list of all rewinders.
* \return true If successfully added, false otherwise.
*/
bool RewindManager::addRewinder(std::shared_ptr<Rewinder> rewinder)
{
if (!m_enable_rewind_manager) return false;
// Maximum 1 bit to store no of rewinder used
if (m_all_rewinder.size() == 255)
return false;
m_all_rewinder[rewinder->getUniqueIdentity()] = rewinder;
return true;
} // addRewinder
// ----------------------------------------------------------------------------
/** Rewinds to the specified time, then goes forward till the current
* World::getTime() is reached again: it will replay everything before
@ -274,7 +287,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
// can be computed between the transforms before and after
// the rewind.
for (auto& p : m_all_rewinder)
p.second->saveTransform();
{
if (auto r = p.second.lock())
r->saveTransform();
}
// Then undo the rewind infos going backwards in time
// --------------------------------------------------
@ -348,10 +364,14 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
// Now compute the errors which need to be visually smoothed
for (auto& p : m_all_rewinder)
p.second->computeError();
{
if (auto r = p.second.lock())
r->computeError();
}
history->setReplayHistory(is_history);
m_is_rewinding = false;
mergeRewindInfoEventFunction();
} // rewindTo
// ----------------------------------------------------------------------------
@ -360,3 +380,11 @@ bool RewindManager::useLocalEvent() const
return NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient() && !m_is_rewinding;
} // useLocalEvent
// ----------------------------------------------------------------------------
void RewindManager::mergeRewindInfoEventFunction()
{
for (RewindInfoEventFunction* rief : m_pending_rief)
m_rewind_queue.insertRewindInfo(rief);
m_pending_rief.clear();
} // mergeRewindInfoEventFunction

View File

@ -19,7 +19,6 @@
#ifndef HEADER_REWIND_MANAGER_HPP
#define HEADER_REWIND_MANAGER_HPP
#include "network/rewinder.hpp"
#include "network/rewind_queue.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/synchronised.hpp"
@ -27,10 +26,15 @@
#include <assert.h>
#include <atomic>
#include <functional>
#include <memory>
#include <map>
#include <set>
#include <string>
#include <vector>
class Rewinder;
class RewindInfo;
class RewindInfoEventFunction;
class EventRewinder;
/** \ingroup network
@ -93,7 +97,7 @@ private:
std::map<int, std::vector<std::function<void()> > > m_local_state;
/** A list of all objects that can be rewound. */
std::map<std::string, Rewinder*> m_all_rewinder;
std::map<std::string, std::weak_ptr<Rewinder> > m_all_rewinder;
/** The queue that stores all rewind infos. */
RewindQueue m_rewind_queue;
@ -115,8 +119,25 @@ private:
* rewinds. */
std::atomic<int> m_not_rewound_ticks;
std::vector<RewindInfoEventFunction*> m_pending_rief;
RewindManager();
~RewindManager();
// ------------------------------------------------------------------------
void clearExpiredRewinder()
{
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
{
if (it->second.expired())
{
it = m_all_rewinder.erase(it);
continue;
}
it++;
}
}
// ------------------------------------------------------------------------
void mergeRewindInfoEventFunction();
public:
// First static functions to manage rewinding.
@ -151,27 +172,18 @@ public:
void addNetworkState(BareNetworkString *buffer, int ticks);
void saveState();
// ------------------------------------------------------------------------
Rewinder* getRewinder(const std::string& name)
std::shared_ptr<Rewinder> getRewinder(const std::string& name)
{
auto it = m_all_rewinder.find(name);
if (it == m_all_rewinder.end())
return NULL;
return it->second;
if (it != m_all_rewinder.end())
{
if (auto r = it->second.lock())
return r;
}
return nullptr;
}
// ------------------------------------------------------------------------
/** Adds a Rewinder to the list of all rewinders.
* \return true If rewinding is enabled, false otherwise.
*/
bool addRewinder(Rewinder *rewinder)
{
if (!m_enable_rewind_manager) return false;
// Maximum 1 bit to store no of rewinder used
if (m_all_rewinder.size() == 255)
return false;
m_all_rewinder[rewinder->getUniqueIdentity()] = rewinder;
return true;
} // addRewinder
bool addRewinder(std::shared_ptr<Rewinder> rewinder);
// ------------------------------------------------------------------------
/** Returns true if currently a rewind is happening. */
bool isRewinding() const { return m_is_rewinding; }
@ -182,8 +194,6 @@ public:
return m_not_rewound_ticks.load(std::memory_order_relaxed);
} // getNotRewoundWorldTicks
// ------------------------------------------------------------------------
RewindQueue& getRewindQueue() { return m_rewind_queue; }
// ------------------------------------------------------------------------
/** Returns the time of the latest confirmed state. */
int getLatestConfirmedState() const
{
@ -200,6 +210,9 @@ public:
{ return m_current_rewinder_using; }
// ------------------------------------------------------------------------
bool useLocalEvent() const;
// ------------------------------------------------------------------------
void addRewindInfoEventFunction(RewindInfoEventFunction* rief)
{ m_pending_rief.push_back(rief); }
}; // RewindManager

View File

@ -21,6 +21,7 @@
#include "config/stk_config.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/rewinder.hpp"
#include "network/rewind_info.hpp"
#include "network/rewind_manager.hpp"
@ -353,8 +354,10 @@ int RewindQueue::undoUntil(int undo_ticks)
{
// A rewind is done after a state in the past is inserted. This function
// makes sure that m_current is not end()
assert(m_current != m_all_rewind_info.end());
//assert(m_current != m_all_rewind_info.end());
assert(!m_all_rewind_info.empty());
m_current = m_all_rewind_info.end();
m_current--;
while((*m_current)->getTicks() > undo_ticks ||
(*m_current)->isEvent() || !(*m_current)->isConfirmed())
{
@ -418,9 +421,9 @@ void RewindQueue::unitTesting()
virtual void rewind(BareNetworkString *s) {}
virtual void saveTransform() {}
virtual void computeError() {}
DummyRewinder() : Rewinder("dummy_rewinder", true) {}
DummyRewinder() : Rewinder() {}
};
DummyRewinder *dummy_rewinder = new DummyRewinder();
auto dummy_rewinder = std::make_shared<DummyRewinder>();
// First tests: add a state first, then an event, and make
// sure the state stays first
@ -434,7 +437,7 @@ void RewindQueue::unitTesting()
assert(q0.hasMoreRewindInfo());
assert(q0.undoUntil(0) == 0);
q0.addNetworkEvent(dummy_rewinder, NULL, 0);
q0.addNetworkEvent(dummy_rewinder.get(), NULL, 0);
// Network events are not immediately merged
assert(q0.m_all_rewind_info.size() == 1);
@ -462,9 +465,9 @@ void RewindQueue::unitTesting()
assert((*rii)->isEvent());
// Test time base comparisons: adding an event to the end
q0.addLocalEvent(dummy_rewinder, NULL, true, 4);
q0.addLocalEvent(dummy_rewinder.get(), NULL, true, 4);
// Then adding an earlier event
q0.addLocalEvent(dummy_rewinder, NULL, false, 1);
q0.addLocalEvent(dummy_rewinder.get(), NULL, false, 1);
// rii points to the 3rd element, the ones added just now
// should be elements4 and 5:
rii++;

View File

@ -19,14 +19,13 @@
#ifndef HEADER_REWIND_QUEUE_HPP
#define HEADER_REWIND_QUEUE_HPP
#include "network/rewinder.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/synchronised.hpp"
#include <assert.h>
#include <list>
#include <vector>
class BareNetworkString;
class EventRewinder;
class RewindInfo;
class TimeStepInfo;

View File

@ -20,27 +20,11 @@
#include "network/rewind_manager.hpp"
/** Constructor. It will add this object to the list of all rewindable
// ----------------------------------------------------------------------------
/** Add this object to the list of all rewindable
* objects in the rewind manager.
*/
Rewinder::Rewinder(const std::string& ui, bool can_be_destroyed, bool auto_add)
: m_unique_identity(ui)
bool Rewinder::rewinderAdd()
{
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
m_can_be_destroyed = can_be_destroyed;
if (auto_add)
add();
} // Rewinder
// ----------------------------------------------------------------------------
/** Destructor.
*/
Rewinder::~Rewinder()
{
} // ~Rewinder
// ----------------------------------------------------------------------------
void Rewinder::add()
{
RewindManager::get()->addRewinder(this);
} // Rewinder
return RewindManager::get()->addRewinder(shared_from_this());
} // rewinderAdd

View File

@ -19,33 +19,25 @@
#ifndef HEADER_REWINDER_HPP
#define HEADER_REWINDER_HPP
#include <cassert>
#include <functional>
#include <string>
#include <memory>
#include <vector>
class BareNetworkString;
class Rewinder
class Rewinder : public std::enable_shared_from_this<Rewinder>
{
protected:
void add();
// -------------------------------------------------------------------------
void setUniqueIdentity(const std::string& uid) { m_unique_identity = uid; }
private:
std::string m_unique_identity;
/** True if this object can be destroyed, i.e. if this object is a 'stand
* alone' (i.e. not used in inheritance). If the object is used in
* inheritance (e.g. KartRewinder, which is a Rewinder and Kart), then
* freeing the kart will free this rewinder instance as well.
*/
bool m_can_be_destroyed;
public:
Rewinder(const std::string& ui, bool can_be_destroyed,
bool auto_add = true);
virtual ~Rewinder();
Rewinder(const std::string& ui = "") { m_unique_identity = ui; }
virtual ~Rewinder() {}
/** Called before a rewind. Is used to save the previous position of an
* object before a rewind, so that the error due to a rewind can be
@ -89,14 +81,20 @@ public:
/** Nothing to do here. */
virtual void reset() {}
// -------------------------------------------------------------------------
/** True if this rewinder can be destroyed. Karts can not be destroyed,
* cakes can. This is used by the RewindManager in reset. */
bool canBeDestroyed() const { return m_can_be_destroyed; }
// -------------------------------------------------------------------------
virtual std::function<void()> getLocalStateRestoreFunction()
{ return nullptr; }
// -------------------------------------------------------------------------
const std::string& getUniqueIdentity() const { return m_unique_identity; }
const std::string& getUniqueIdentity() const
{
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
return m_unique_identity;
}
// -------------------------------------------------------------------------
bool rewinderAdd();
// -------------------------------------------------------------------------
template<typename T> std::shared_ptr<T> getShared()
{ return std::dynamic_pointer_cast<T>(shared_from_this()); }
}; // Rewinder
#endif

View File

@ -71,8 +71,6 @@ void* btKartRaycaster::castRay(const btVector3& from, const btVector3& to,
result.m_hitNormalInWorld.normalize();
result.m_distFraction = rayCallback.m_closestHitFraction;
result.m_triangle_index = -1;
const TriangleMesh &tm =
Track::getCurrentTrack()->getTriangleMesh();
// FIXME: this code assumes atm that the object the kart is
// driving on is the main track (and not e.g. a physical object).
// If this should not be the case (i.e. the object hit by the

View File

@ -123,12 +123,11 @@ void PhysicalObject::Settings::init()
} // Settings
// ============================================================================
PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
const XMLNode &xml_node,
TrackObject* object)
std::shared_ptr<PhysicalObject> PhysicalObject::fromXML
(bool is_dynamic, const XMLNode &xml_node, TrackObject* object)
{
PhysicalObject::Settings settings(xml_node);
return new PhysicalObject(is_dynamic, settings, object);
return std::make_shared<PhysicalObject>(is_dynamic, settings, object);
} // fromXML
// ----------------------------------------------------------------------------
@ -136,7 +135,6 @@ PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
PhysicalObject::PhysicalObject(bool is_dynamic,
const PhysicalObject::Settings& settings,
TrackObject* object)
: Rewinder("P", false/*can_be_destroyed*/, false/*auto_add*/)
{
m_shape = NULL;
m_body = NULL;
@ -793,7 +791,7 @@ void PhysicalObject::addForRewind()
SmoothNetworkBody::setAdjustVerticalOffset(false);
Rewinder::setUniqueIdentity(std::string("P") + StringUtils::toString
(Track::getCurrentTrack()->getPhysicalObjectUID()));
Rewinder::add();
Rewinder::rewinderAdd();
} // addForRewind
// ----------------------------------------------------------------------------

View File

@ -197,8 +197,8 @@ public:
PhysicalObject(bool is_dynamic, const Settings& settings,
TrackObject* object);
static PhysicalObject* fromXML(bool is_dynamic, const XMLNode &node,
TrackObject* object);
static std::shared_ptr<PhysicalObject> fromXML
(bool is_dynamic, const XMLNode &node, TrackObject* object);
virtual ~PhysicalObject ();
virtual void reset ();

View File

@ -296,11 +296,13 @@ void History::Load()
{
fgets(s, 1023, fd);
InputEvent &ie = m_all_input_events[i];
int action = 0;
if (sscanf(s, "%d %d %d %d\n", &ie.m_world_ticks, &ie.m_kart_index,
&ie.m_action, &ie.m_value) != 4 )
&action, &ie.m_value) != 4)
{
Log::warn("History", "Problems reading event: '%s'", s);
}
ie.m_action = (PlayerAction)action;
} // for i
RewindManager::setEnable(rewind_manager_was_enabled);

View File

@ -58,7 +58,7 @@ void ReplayPlay::reset()
{
for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
{
m_ghost_karts[i].reset();
m_ghost_karts[i]->reset();
}
} // reset
@ -297,7 +297,7 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay, int ca
//-----------------------------------------------------------------------------
void ReplayPlay::load()
{
m_ghost_karts.clearAndDeleteAll();
m_ghost_karts.clear();
if (m_second_replay_enabled)
loadFile(/* second replay */ true);
@ -365,11 +365,11 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
first_loaded_f_num = m_replay_file_list.at(m_second_replay_file).m_kart_list.size();
ReplayData &rd = m_replay_file_list[replay_index];
m_ghost_karts.push_back(new GhostKart(rd.m_kart_list.at(kart_num-first_loaded_f_num),
kart_num, kart_num + 1,
rd.m_kart_color.at(kart_num-first_loaded_f_num)));
m_ghost_karts[kart_num].init(RaceManager::KT_GHOST);
Controller* controller = new GhostController(getGhostKart(kart_num),
m_ghost_karts.push_back(std::make_shared<GhostKart>
(rd.m_kart_list.at(kart_num-first_loaded_f_num), kart_num, kart_num + 1,
rd.m_kart_color.at(kart_num-first_loaded_f_num)));
m_ghost_karts[kart_num]->init(RaceManager::KT_GHOST);
Controller* controller = new GhostController(getGhostKart(kart_num).get(),
rd.m_name_list[kart_num-first_loaded_f_num]);
getGhostKart(kart_num)->setController(controller);
@ -423,7 +423,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
kre.m_skidding_effect = skidding;
kre.m_red_skidding = red_skidding!=0;
kre.m_jumping = jumping != 0;
m_ghost_karts[kart_num].addReplayEvent(time,
m_ghost_karts[kart_num]->addReplayEvent(time,
btTransform(q, xyz), pi, bi, kre);
}
else
@ -472,7 +472,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
kre.m_skidding_effect = skidding;
kre.m_red_skidding = red_skidding!=0;
kre.m_jumping = jumping != 0;
m_ghost_karts[kart_num].addReplayEvent(time,
m_ghost_karts[kart_num]->addReplayEvent(time,
btTransform(q, xyz), pi, bi, kre);
}
else

View File

@ -20,10 +20,10 @@
#define HEADER_REPLAY__PLAY_HPP
#include "replay/replay_base.hpp"
#include "utils/ptr_vector.hpp"
#include "irrString.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
@ -118,7 +118,7 @@ private:
std::vector<ReplayData> m_replay_file_list;
/** All ghost karts. */
PtrVector<GhostKart> m_ghost_karts;
std::vector<std::shared_ptr<GhostKart> > m_ghost_karts;
ReplayPlay();
~ReplayPlay();
@ -162,7 +162,7 @@ public:
const unsigned int getNumReplayFile() const
{ return (unsigned int)m_replay_file_list.size(); }
// ------------------------------------------------------------------------
GhostKart* getGhostKart(int n) { return m_ghost_karts.get(n); }
std::shared_ptr<GhostKart> getGhostKart(int n) { return m_ghost_karts[n]; }
// ------------------------------------------------------------------------
const unsigned int getNumGhostKart() const
{

View File

@ -1029,7 +1029,7 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt)
if(m_plunger_move_time < dt && m_plunger_state!=PLUNGER_STATE_FAST)
{
const float fast_time = 0.3f;
if(kart->getBlockedByPlungerTicks()<fast_time)
if(kart->getBlockedByPlungerTicks()<stk_config->time2Ticks(fast_time))
{
// First time we reach faste state: select random target point
// at top of screen and set speed accordingly

View File

@ -74,7 +74,6 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
m_enabled = true;
m_presentation = NULL;
m_animator = NULL;
m_physical_object = NULL;
m_parent_library = NULL;
m_interaction = interaction;
m_presentation = presentation;
@ -86,9 +85,8 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
if (m_interaction != "ghost" && m_interaction != "none" &&
physics_settings )
{
m_physical_object = new PhysicalObject(is_dynamic,
*physics_settings,
this);
m_physical_object = std::make_shared<PhysicalObject>
(is_dynamic, *physics_settings, this);
}
reset();
@ -112,7 +110,6 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
m_presentation = NULL;
m_animator = NULL;
m_parent_library = parent_library;
m_physical_object = NULL;
xml_node.get("id", &m_id );
xml_node.get("model", &m_name );
@ -455,7 +452,6 @@ TrackObject::~TrackObject()
{
delete m_presentation;
delete m_animator;
delete m_physical_object;
} // ~TrackObject
// ----------------------------------------------------------------------------
@ -482,7 +478,7 @@ void TrackObject::setEnabled(bool enabled)
if (getType() == "mesh")
{
if (m_physical_object != NULL)
if (m_physical_object)
{
if (enabled)
m_physical_object->addBody();
@ -508,7 +504,7 @@ void TrackObject::resetEnabled()
if (getType() == "mesh")
{
if (m_physical_object != NULL)
if (m_physical_object)
{
if (m_initially_visible)
m_physical_object->addBody();
@ -581,7 +577,7 @@ void TrackObject::move(const core::vector3df& xyz, const core::vector3df& hpr,
if (m_presentation != NULL)
m_presentation->move(xyz, hpr, scale, isAbsoluteCoord);
if (update_rigid_body && m_physical_object != NULL)
if (update_rigid_body && m_physical_object)
{
movePhysicalBodyToGraphicalNode(xyz, hpr);
}

View File

@ -86,7 +86,7 @@ protected:
/** True if a kart can drive on this object. This will */
bool m_is_driveable;
PhysicalObject* m_physical_object;
std::shared_ptr<PhysicalObject> m_physical_object;
ThreeDAnimation* m_animator;
@ -164,9 +164,10 @@ public:
// ------------------------------------------------------------------------
bool isSoccerBall() const { return m_soccer_ball; }
// ------------------------------------------------------------------------
const PhysicalObject* getPhysicalObject() const { return m_physical_object; }
const PhysicalObject* getPhysicalObject() const
{ return m_physical_object.get(); }
// ------------------------------------------------------------------------
PhysicalObject* getPhysicalObject() { return m_physical_object; }
PhysicalObject* getPhysicalObject() { return m_physical_object.get(); }
// ------------------------------------------------------------------------
const core::vector3df getInitXYZ() const { return m_init_xyz; }
// ------------------------------------------------------------------------
@ -214,7 +215,7 @@ public:
/** Get the physics representation of an object.
* On the script side, the returned object is of type : @ref Scripting_PhysicalObject
*/
PhysicalObject* getPhysics() { return m_physical_object; }
PhysicalObject* getPhysics() { return m_physical_object.get(); }
/** Hide or show the object */
void setEnabled(bool mode);