Merge remote-tracking branch 'origin/master' into physics-tweaks
This commit is contained in:
commit
84c21c4af2
CMakeLists.txt
data
lib/irrlicht
src
animations
config
items
bowling.hppcake.cppcake.hppflyable.cppflyable.hppitem_manager.cppitem_manager.hppnetwork_item_manager.cppnetwork_item_manager.hppplunger.cppplunger.hpppowerup.cpppowerup.hpppowerup_manager.cpppowerup_manager.hppprojectile_manager.cppprojectile_manager.hpp
karts
abstract_kart_animation.cpp
main.cppcontroller
ghost_kart.cppkart.cppkart.hppkart_rewinder.cppkart_rewinder.hppmax_speed.cppmax_speed.hppmoveable.cppmodes
cutscene_world.cppcutscene_world.hpplinear_world.cppprofile_world.cppprofile_world.hppsoccer_world.cppsoccer_world.hppstandard_race.cppthree_strikes_battle.cppworld.cppworld.hppworld_status.hppworld_with_rank.cpp
network
network_string.hppprotocol_manager.cpp
protocols
client_lobby.cppclient_lobby.hppgame_events_protocol.cpplobby_protocol.cpplobby_protocol.hppserver_lobby.cpp
rewind_info.cpprewind_info.hpprewind_manager.cpprewind_manager.hpprewind_queue.cpprewind_queue.hpprewinder.cpprewinder.hppstk_host.cpponline
physics
race
replay
states_screens
tracks
@ -113,6 +113,7 @@ if(WIN32)
|
|||||||
set(ENV{OPENALDIR} ${PROJECT_SOURCE_DIR}/${DEPENDENCIES})
|
set(ENV{OPENALDIR} ${PROJECT_SOURCE_DIR}/${DEPENDENCIES})
|
||||||
add_definitions(-D_IRR_STATIC_LIB_)
|
add_definitions(-D_IRR_STATIC_LIB_)
|
||||||
add_definitions(-DNO_IRR_COMPILE_WITH_X11_)
|
add_definitions(-DNO_IRR_COMPILE_WITH_X11_)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_GLES2)
|
if(USE_GLES2)
|
||||||
|
@ -203,8 +203,11 @@
|
|||||||
|
|
||||||
<!-- Networking
|
<!-- Networking
|
||||||
state-frequency: how many states the server will send per second.
|
state-frequency: how many states the server will send per second.
|
||||||
|
steering-reduction: Reduce a remote kart's steering by this factor
|
||||||
|
each frame. This helps reduces oversteering by high latency
|
||||||
|
clients when they only do minor steering adjustments.
|
||||||
-->
|
-->
|
||||||
<networking state-frequency="10"/>
|
<networking state-frequency="10" steering-reduction="1.0"/>
|
||||||
|
|
||||||
<!-- The field od views for 1-4 player split screen. fov-3 is
|
<!-- The field od views for 1-4 player split screen. fov-3 is
|
||||||
actually not used (since 3 player split screen uses the
|
actually not used (since 3 player split screen uses the
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
# CMakeLists.txt for Irrlicht in STK
|
# CMakeLists.txt for Irrlicht in STK
|
||||||
find_package(PNG REQUIRED)
|
|
||||||
find_package(JPEG REQUIRED)
|
|
||||||
|
|
||||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
|
||||||
"${JPEG_INCLUDE_DIR}"
|
|
||||||
"${PNG_INCLUDE_DIRS}"
|
|
||||||
"${ZLIB_INCLUDE_DIR}")
|
|
||||||
|
|
||||||
if(MSVC OR APPLE)
|
|
||||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/" # For zconf.h on WIN32
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/../libpng/")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT SERVER_ONLY)
|
if(NOT SERVER_ONLY)
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
find_package(JPEG REQUIRED)
|
||||||
|
|
||||||
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||||
|
"${JPEG_INCLUDE_DIR}"
|
||||||
|
"${PNG_INCLUDE_DIRS}"
|
||||||
|
"${ZLIB_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/") # For zconf.h on WIN32
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC OR APPLE)
|
||||||
|
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../libpng/")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT USE_GLES2)
|
if(NOT USE_GLES2)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
include_directories(${OPENGL_INCLUDE_DIR})
|
include_directories(${OPENGL_INCLUDE_DIR})
|
||||||
@ -58,6 +61,13 @@ if(NOT SERVER_ONLY)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
||||||
|
if(MSVC)
|
||||||
|
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/")
|
||||||
|
else()
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
include_directories("${ZLIB_INCLUDE_DIR}")
|
||||||
|
endif()
|
||||||
add_definitions(-DNO_IRR_COMPILE_WITH_LIBPNG_)
|
add_definitions(-DNO_IRR_COMPILE_WITH_LIBPNG_)
|
||||||
add_definitions(-DNO_IRR_COMPILE_WITH_LIBJPEG_)
|
add_definitions(-DNO_IRR_COMPILE_WITH_LIBJPEG_)
|
||||||
add_definitions(-DNO_IRR_COMPILE_WITH_BMP_LOADER_)
|
add_definitions(-DNO_IRR_COMPILE_WITH_BMP_LOADER_)
|
||||||
|
@ -47,9 +47,6 @@ private:
|
|||||||
* one time only (which might get triggered more than once). */
|
* one time only (which might get triggered more than once). */
|
||||||
enum AnimTimeType { ATT_CYCLIC, ATT_CYCLIC_ONCE } m_anim_type;
|
enum AnimTimeType { ATT_CYCLIC, ATT_CYCLIC_ONCE } m_anim_type;
|
||||||
|
|
||||||
/** The current time used in the IPOs. */
|
|
||||||
float m_current_time;
|
|
||||||
|
|
||||||
/** The inital position of this object. */
|
/** The inital position of this object. */
|
||||||
Vec3 m_initial_xyz;
|
Vec3 m_initial_xyz;
|
||||||
|
|
||||||
@ -67,6 +64,9 @@ protected:
|
|||||||
|
|
||||||
float m_animation_duration;
|
float m_animation_duration;
|
||||||
|
|
||||||
|
/** The current time used in the IPOs. */
|
||||||
|
float m_current_time;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AnimationBase(const XMLNode &node);
|
AnimationBase(const XMLNode &node);
|
||||||
AnimationBase(Ipo *ipo);
|
AnimationBase(Ipo *ipo);
|
||||||
|
@ -75,15 +75,13 @@ void ThreeDAnimation::updateWithWorldTicks()
|
|||||||
Vec3 xyz = m_object->getPosition();
|
Vec3 xyz = m_object->getPosition();
|
||||||
Vec3 scale = m_object->getScale();
|
Vec3 scale = m_object->getScale();
|
||||||
|
|
||||||
float position = 0.0f;
|
|
||||||
if (!m_is_paused)
|
if (!m_is_paused)
|
||||||
{
|
{
|
||||||
int cur_ticks = World::getWorld()->getTicksSinceStart();
|
int cur_ticks = World::getWorld()->getTicksSinceStart();
|
||||||
float cur_time = stk_config->ticks2Time(cur_ticks);
|
m_current_time = stk_config->ticks2Time(cur_ticks);
|
||||||
position = fmodf(cur_time, m_animation_duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationBase::getAt(position, &xyz, &m_hpr, &scale); //updates all IPOs
|
AnimationBase::getAt(m_current_time, &xyz, &m_hpr, &scale); //updates all IPOs
|
||||||
//m_node->setPosition(xyz.toIrrVector());
|
//m_node->setPosition(xyz.toIrrVector());
|
||||||
//m_node->setScale(scale.toIrrVector());
|
//m_node->setScale(scale.toIrrVector());
|
||||||
|
|
||||||
|
8
src/config/stk_config.cpp
Normal file → Executable file
8
src/config/stk_config.cpp
Normal file → Executable file
@ -149,8 +149,10 @@ void STKConfig::load(const std::string &filename)
|
|||||||
CHECK_NEG(m_minimap_ai_icon, "minimap ai_icon" );
|
CHECK_NEG(m_minimap_ai_icon, "minimap ai_icon" );
|
||||||
CHECK_NEG(m_minimap_player_icon, "minimap player_icon" );
|
CHECK_NEG(m_minimap_player_icon, "minimap player_icon" );
|
||||||
CHECK_NEG(m_smooth_angle_limit, "physics smooth-angle-limit" );
|
CHECK_NEG(m_smooth_angle_limit, "physics smooth-angle-limit" );
|
||||||
CHECK_NEG(m_default_track_friction, "physics default-track-friction" );
|
CHECK_NEG(m_default_track_friction, "physics default-track-friction");
|
||||||
CHECK_NEG(m_physics_fps, "physics fps" );
|
CHECK_NEG(m_physics_fps, "physics fps" );
|
||||||
|
CHECK_NEG(m_network_state_frequeny, "network state-frequency" );
|
||||||
|
CHECK_NEG(m_network_steering_reduction,"network steering-reduction" );
|
||||||
CHECK_NEG(m_default_moveable_friction, "physics default-moveable-friction");
|
CHECK_NEG(m_default_moveable_friction, "physics default-moveable-friction");
|
||||||
CHECK_NEG(m_solver_iterations, "physics: solver-iterations" );
|
CHECK_NEG(m_solver_iterations, "physics: solver-iterations" );
|
||||||
CHECK_NEG(m_network_state_frequeny, "network solver-state-frequency" );
|
CHECK_NEG(m_network_state_frequeny, "network solver-state-frequency" );
|
||||||
@ -200,6 +202,7 @@ void STKConfig::init_defaults()
|
|||||||
m_solver_iterations = -100;
|
m_solver_iterations = -100;
|
||||||
m_solver_set_flags = 0;
|
m_solver_set_flags = 0;
|
||||||
m_solver_reset_flags = 0;
|
m_solver_reset_flags = 0;
|
||||||
|
m_network_steering_reduction = 1.0f;
|
||||||
m_title_music = NULL;
|
m_title_music = NULL;
|
||||||
m_solver_split_impulse = false;
|
m_solver_split_impulse = false;
|
||||||
m_smooth_normals = false;
|
m_smooth_normals = false;
|
||||||
@ -433,6 +436,7 @@ void STKConfig::getAllData(const XMLNode * root)
|
|||||||
if (const XMLNode *networking_node = root->getNode("networking"))
|
if (const XMLNode *networking_node = root->getNode("networking"))
|
||||||
{
|
{
|
||||||
networking_node->get("state-frequency", &m_network_state_frequeny);
|
networking_node->get("state-frequency", &m_network_state_frequeny);
|
||||||
|
networking_node->get("steering-reduction", &m_network_steering_reduction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(const XMLNode *replay_node = root->getNode("replay"))
|
if(const XMLNode *replay_node = root->getNode("replay"))
|
||||||
|
@ -89,6 +89,11 @@ public:
|
|||||||
/** How many state updates per second the server will send. */
|
/** How many state updates per second the server will send. */
|
||||||
int m_network_state_frequeny;
|
int m_network_state_frequeny;
|
||||||
|
|
||||||
|
/** In case of a network race, remote karts will get their steering somewhat
|
||||||
|
* reduced each frame. This reduces stutter when a kart only does small
|
||||||
|
* steering adjustments. */
|
||||||
|
float m_network_steering_reduction;
|
||||||
|
|
||||||
/** If the angle between a normal on a vertex and the normal of the
|
/** If the angle between a normal on a vertex and the normal of the
|
||||||
* triangle are more than this value, the physics will use the normal
|
* triangle are more than this value, the physics will use the normal
|
||||||
* of the triangle in smoothing normal. */
|
* of the triangle in smoothing normal. */
|
||||||
|
@ -53,9 +53,9 @@ public:
|
|||||||
Bowling(AbstractKart* kart);
|
Bowling(AbstractKart* kart);
|
||||||
virtual ~Bowling();
|
virtual ~Bowling();
|
||||||
static void init(const XMLNode &node, scene::IMesh *bowling);
|
static void init(const XMLNode &node, scene::IMesh *bowling);
|
||||||
virtual bool updateAndDelete(int ticks);
|
virtual bool updateAndDelete(int ticks) OVERRIDE;
|
||||||
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
|
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
|
||||||
virtual HitEffect *getHitEffect() const;
|
virtual HitEffect *getHitEffect() const OVERRIDE;
|
||||||
|
|
||||||
|
|
||||||
}; // Bowling
|
}; // Bowling
|
||||||
|
@ -119,11 +119,7 @@ Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
|
|||||||
|
|
||||||
//do not adjust height according to terrain
|
//do not adjust height according to terrain
|
||||||
setAdjustUpVelocity(false);
|
setAdjustUpVelocity(false);
|
||||||
|
additionalPhysicsProperties();
|
||||||
m_body->setActivationState(DISABLE_DEACTIVATION);
|
|
||||||
|
|
||||||
m_body->applyTorque( btVector3(5,-3,7) );
|
|
||||||
|
|
||||||
} // Cake
|
} // Cake
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -46,24 +46,36 @@ private:
|
|||||||
|
|
||||||
/** Which kart is targeted by this projectile (NULL if none). */
|
/** Which kart is targeted by this projectile (NULL if none). */
|
||||||
Moveable* m_target;
|
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:
|
public:
|
||||||
Cake (AbstractKart *kart);
|
Cake (AbstractKart *kart);
|
||||||
static void init (const XMLNode &node, scene::IMesh *cake_model);
|
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
|
/** Kinematic objects are not allowed to have a velocity (assertion in
|
||||||
* bullet), so we have to do our own velocity handling here. This
|
* bullet), so we have to do our own velocity handling here. This
|
||||||
* function returns the velocity of this object. */
|
* 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
|
/** Kinematic objects are not allowed to have a velocity (assertion in
|
||||||
* bullet), so we have to do our own velocity handling here. This
|
* bullet), so we have to do our own velocity handling here. This
|
||||||
* function sets the velocity of this object.
|
* function sets the velocity of this object.
|
||||||
* \param v Linear 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
|
}; // Cake
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +37,11 @@
|
|||||||
#include "karts/explosion_animation.hpp"
|
#include "karts/explosion_animation.hpp"
|
||||||
#include "modes/linear_world.hpp"
|
#include "modes/linear_world.hpp"
|
||||||
#include "modes/soccer_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 "physics/physics.hpp"
|
||||||
#include "tracks/track.hpp"
|
#include "tracks/track.hpp"
|
||||||
#include "utils/constants.hpp"
|
#include "utils/constants.hpp"
|
||||||
@ -75,6 +80,10 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
|
|||||||
m_owner_has_temporary_immunity = true;
|
m_owner_has_temporary_immunity = true;
|
||||||
m_do_terrain_info = true;
|
m_do_terrain_info = true;
|
||||||
m_max_lifespan = -1;
|
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
|
// Add the graphical model
|
||||||
#ifndef SERVER_ONLY
|
#ifndef SERVER_ONLY
|
||||||
@ -160,6 +169,10 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
|
|||||||
m_body->setCollisionFlags(m_body->getCollisionFlags() |
|
m_body->setCollisionFlags(m_body->getCollisionFlags() |
|
||||||
btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
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
|
} // createPhysics
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -378,7 +391,7 @@ void Flyable::setAnimation(AbstractKartAnimation *animation)
|
|||||||
*/
|
*/
|
||||||
void Flyable::updateGraphics(float dt)
|
void Flyable::updateGraphics(float dt)
|
||||||
{
|
{
|
||||||
updateSmoothedGraphics(dt);
|
Moveable::updateSmoothedGraphics(dt);
|
||||||
Moveable::updateGraphics();
|
Moveable::updateGraphics();
|
||||||
} // updateGraphics
|
} // updateGraphics
|
||||||
|
|
||||||
@ -390,6 +403,9 @@ void Flyable::updateGraphics(float dt)
|
|||||||
*/
|
*/
|
||||||
bool Flyable::updateAndDelete(int ticks)
|
bool Flyable::updateAndDelete(int ticks)
|
||||||
{
|
{
|
||||||
|
if (m_undo_creation)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (hasAnimation())
|
if (hasAnimation())
|
||||||
{
|
{
|
||||||
m_animation->update(stk_config->ticks2Time(ticks));
|
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)
|
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
|
// the owner of this flyable should not be hit by his own flyable
|
||||||
if(isOwnerImmunity(kart_hit)) return false;
|
if(isOwnerImmunity(kart_hit)) return false;
|
||||||
m_has_hit_something=true;
|
m_has_hit_something=true;
|
||||||
@ -573,5 +591,140 @@ HitEffect* Flyable::getHitEffect() const
|
|||||||
unsigned int Flyable::getOwnerId()
|
unsigned int Flyable::getOwnerId()
|
||||||
{
|
{
|
||||||
return m_owner->getWorldKartId();
|
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 */
|
/* EOF */
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "items/powerup_manager.hpp"
|
#include "items/powerup_manager.hpp"
|
||||||
#include "karts/moveable.hpp"
|
#include "karts/moveable.hpp"
|
||||||
|
#include "network/rewinder.hpp"
|
||||||
#include "tracks/terrain_info.hpp"
|
#include "tracks/terrain_info.hpp"
|
||||||
#include "utils/cpp2011.hpp"
|
#include "utils/cpp2011.hpp"
|
||||||
|
|
||||||
@ -43,7 +44,8 @@ class XMLNode;
|
|||||||
/**
|
/**
|
||||||
* \ingroup items
|
* \ingroup items
|
||||||
*/
|
*/
|
||||||
class Flyable : public Moveable, public TerrainInfo
|
class Flyable : public Moveable, public TerrainInfo,
|
||||||
|
public Rewinder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
private:
|
private:
|
||||||
@ -103,6 +105,11 @@ protected:
|
|||||||
/** Size of this flyable. */
|
/** Size of this flyable. */
|
||||||
Vec3 m_extend;
|
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.
|
// The flyable class stores the values for each flyable type, e.g.
|
||||||
// speed, min_height, max_height. These variables must be static,
|
// speed, min_height, max_height. These variables must be static,
|
||||||
// so we need arrays of these variables to have different values
|
// 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
|
/** Time since thrown. used so a kart can't hit himself when trying
|
||||||
* something, and also to put some time limit to some collectibles */
|
* 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
|
/** Set to something > -1 if this flyable should auto-destrcut after
|
||||||
* that may ticks. */
|
* that may ticks. */
|
||||||
int m_max_lifespan;
|
int m_max_lifespan;
|
||||||
|
|
||||||
/** If set to true, the kart that throwns this flyable can't collide
|
/** If set to true, the kart that throwns this flyable can't collide
|
||||||
* with it for a short time. */
|
* with it for a short time. */
|
||||||
@ -160,6 +167,13 @@ protected:
|
|||||||
const bool rotates=false,
|
const bool rotates=false,
|
||||||
const bool turn_around=false,
|
const bool turn_around=false,
|
||||||
const btTransform* customDirection=NULL);
|
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:
|
public:
|
||||||
|
|
||||||
Flyable (AbstractKart* kart,
|
Flyable (AbstractKart* kart,
|
||||||
@ -217,6 +231,31 @@ public:
|
|||||||
/** Returns the size (extend) of the mesh. */
|
/** Returns the size (extend) of the mesh. */
|
||||||
const Vec3 &getExtend() const { return m_extend; }
|
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
|
}; // Flyable
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,19 +43,20 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
std::vector<scene::IMesh *> ItemManager::m_item_mesh;
|
std::vector<scene::IMesh *> ItemManager::m_item_mesh;
|
||||||
std::vector<scene::IMesh *> ItemManager::m_item_lowres_mesh;
|
std::vector<scene::IMesh *> ItemManager::m_item_lowres_mesh;
|
||||||
std::vector<video::SColorf> ItemManager::m_glow_color;
|
std::vector<video::SColorf> ItemManager::m_glow_color;
|
||||||
bool ItemManager::m_disable_item_collection = false;
|
bool ItemManager::m_disable_item_collection = false;
|
||||||
ItemManager * ItemManager::m_item_manager = NULL;
|
std::shared_ptr<ItemManager> ItemManager::m_item_manager;
|
||||||
std::mt19937 ItemManager::m_random_engine;
|
std::mt19937 ItemManager::m_random_engine;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Creates one instance of the item manager. */
|
/** Creates one instance of the item manager. */
|
||||||
void ItemManager::create()
|
void ItemManager::create()
|
||||||
{
|
{
|
||||||
assert(!m_item_manager);
|
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
|
} // create
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -63,8 +64,7 @@ void ItemManager::create()
|
|||||||
void ItemManager::destroy()
|
void ItemManager::destroy()
|
||||||
{
|
{
|
||||||
assert(m_item_manager);
|
assert(m_item_manager);
|
||||||
delete m_item_manager;
|
m_item_manager = nullptr;
|
||||||
m_item_manager = NULL;
|
|
||||||
} // destroy
|
} // destroy
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -60,7 +60,7 @@ private:
|
|||||||
static std::mt19937 m_random_engine;
|
static std::mt19937 m_random_engine;
|
||||||
protected:
|
protected:
|
||||||
/** The instance of ItemManager while a race is on. */
|
/** The instance of ItemManager while a race is on. */
|
||||||
static ItemManager *m_item_manager;
|
static std::shared_ptr<ItemManager> m_item_manager;
|
||||||
public:
|
public:
|
||||||
static void loadDefaultItemMeshes();
|
static void loadDefaultItemMeshes();
|
||||||
static void removeTextures();
|
static void removeTextures();
|
||||||
@ -90,9 +90,10 @@ public:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Return an instance of the item manager (it does not automatically
|
/** Return an instance of the item manager (it does not automatically
|
||||||
* create one, call create for that). */
|
* create one, call create for that). */
|
||||||
static ItemManager *get() {
|
static ItemManager *get()
|
||||||
|
{
|
||||||
assert(m_item_manager);
|
assert(m_item_manager);
|
||||||
return m_item_manager;
|
return m_item_manager.get();
|
||||||
} // get
|
} // get
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
@ -119,9 +120,9 @@ protected:
|
|||||||
virtual unsigned int insertItem(Item *item);
|
virtual unsigned int insertItem(Item *item);
|
||||||
void setSwitchItems(const std::vector<int> &switch_items);
|
void setSwitchItems(const std::vector<int> &switch_items);
|
||||||
ItemManager();
|
ItemManager();
|
||||||
|
public:
|
||||||
virtual ~ItemManager();
|
virtual ~ItemManager();
|
||||||
|
|
||||||
public:
|
|
||||||
virtual Item* placeItem (ItemState::ItemType type, const Vec3& xyz,
|
virtual Item* placeItem (ItemState::ItemType type, const Vec3& xyz,
|
||||||
const Vec3 &normal);
|
const Vec3 &normal);
|
||||||
virtual Item* dropNewItem (ItemState::ItemType type,
|
virtual Item* dropNewItem (ItemState::ItemType type,
|
||||||
|
@ -31,16 +31,16 @@
|
|||||||
void NetworkItemManager::create()
|
void NetworkItemManager::create()
|
||||||
{
|
{
|
||||||
assert(!m_item_manager);
|
assert(!m_item_manager);
|
||||||
m_item_manager = new NetworkItemManager();
|
auto nim = std::shared_ptr<NetworkItemManager>(new NetworkItemManager());
|
||||||
|
nim->rewinderAdd();
|
||||||
|
m_item_manager = nim;
|
||||||
} // create
|
} // create
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
/** Creates a new instance of the item manager. This is done at startup
|
/** Creates a new instance of the item manager. This is done at startup
|
||||||
* of each race. */
|
* of each race. */
|
||||||
NetworkItemManager::NetworkItemManager()
|
NetworkItemManager::NetworkItemManager()
|
||||||
: Rewinder("N", /*can be deleted*/false),
|
: Rewinder("N"), ItemManager()
|
||||||
ItemManager()
|
|
||||||
{
|
{
|
||||||
m_last_confirmed_item_ticks.clear();
|
m_last_confirmed_item_ticks.clear();
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@ private:
|
|||||||
void forwardTime(int ticks);
|
void forwardTime(int ticks);
|
||||||
|
|
||||||
NetworkItemManager();
|
NetworkItemManager();
|
||||||
virtual ~NetworkItemManager();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void create();
|
static void create();
|
||||||
|
virtual ~NetworkItemManager();
|
||||||
|
|
||||||
void setSwitchItems(const std::vector<int> &switch_items);
|
void setSwitchItems(const std::vector<int> &switch_items);
|
||||||
void sendItemUpdate();
|
void sendItemUpdate();
|
||||||
|
@ -100,7 +100,7 @@ Plunger::Plunger(AbstractKart *kart)
|
|||||||
{
|
{
|
||||||
m_rubber_band = new RubberBand(this, kart);
|
m_rubber_band = new RubberBand(this, kart);
|
||||||
}
|
}
|
||||||
m_keep_alive = -1;
|
additionalPhysicsProperties();
|
||||||
} // Plunger
|
} // Plunger
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -47,13 +47,17 @@ private:
|
|||||||
btVector3 m_initial_velocity;
|
btVector3 m_initial_velocity;
|
||||||
|
|
||||||
bool m_reverse_mode;
|
bool m_reverse_mode;
|
||||||
|
|
||||||
|
virtual void additionalPhysicsProperties() OVERRIDE { m_keep_alive = -1; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Plunger(AbstractKart *kart);
|
Plunger(AbstractKart *kart);
|
||||||
~Plunger();
|
~Plunger();
|
||||||
static void init(const XMLNode &node, scene::IMesh* missile);
|
static void init(const XMLNode &node, scene::IMesh* missile);
|
||||||
virtual bool updateAndDelete(int ticks);
|
virtual bool updateAndDelete(int ticks) OVERRIDE;
|
||||||
virtual void hitTrack ();
|
virtual void hitTrack () OVERRIDE;
|
||||||
virtual bool hit (AbstractKart *kart, PhysicalObject *obj=NULL);
|
virtual bool hit (AbstractKart *kart, PhysicalObject *obj=NULL)
|
||||||
|
OVERRIDE;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Sets the keep-alive value. Setting it to 0 will remove the plunger
|
/** 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;}
|
void setKeepAlive(int ticks) {m_keep_alive = ticks;}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** No hit effect when it ends. */
|
/** No hit effect when it ends. */
|
||||||
virtual HitEffect *getHitEffect() const {return NULL; }
|
virtual HitEffect *getHitEffect() const OVERRIDE { return NULL; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
}; // Plunger
|
}; // Plunger
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "karts/controller/controller.hpp"
|
#include "karts/controller/controller.hpp"
|
||||||
#include "karts/kart_properties.hpp"
|
#include "karts/kart_properties.hpp"
|
||||||
#include "modes/world.hpp"
|
#include "modes/world.hpp"
|
||||||
|
#include "network/rewind_manager.hpp"
|
||||||
#include "physics/triangle_mesh.hpp"
|
#include "physics/triangle_mesh.hpp"
|
||||||
#include "tracks/track.hpp"
|
#include "tracks/track.hpp"
|
||||||
#include "utils/string_utils.hpp"
|
#include "utils/string_utils.hpp"
|
||||||
@ -211,6 +212,13 @@ void Powerup::adjustSound()
|
|||||||
}
|
}
|
||||||
} // adjustSound
|
} // adjustSound
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void Powerup::playSound()
|
||||||
|
{
|
||||||
|
if (!RewindManager::get()->isRewinding())
|
||||||
|
m_sound_use->play();
|
||||||
|
} // playSound
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Use (fire) this powerup.
|
/** Use (fire) this powerup.
|
||||||
*/
|
*/
|
||||||
@ -248,7 +256,7 @@ void Powerup::use()
|
|||||||
{
|
{
|
||||||
ItemManager::get()->switchItems();
|
ItemManager::get()->switchItems();
|
||||||
m_sound_use->setPosition(m_kart->getXYZ());
|
m_sound_use->setPosition(m_kart->getXYZ());
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PowerupManager::POWERUP_CAKE:
|
case PowerupManager::POWERUP_CAKE:
|
||||||
@ -258,7 +266,7 @@ void Powerup::use()
|
|||||||
if(stk_config->m_shield_restrict_weapons)
|
if(stk_config->m_shield_restrict_weapons)
|
||||||
m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield
|
m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield
|
||||||
Powerup::adjustSound();
|
Powerup::adjustSound();
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
|
|
||||||
projectile_manager->newProjectile(m_kart, m_type);
|
projectile_manager->newProjectile(m_kart, m_type);
|
||||||
break ;
|
break ;
|
||||||
@ -280,7 +288,7 @@ void Powerup::use()
|
|||||||
if(!new_item) return;
|
if(!new_item) return;
|
||||||
|
|
||||||
Powerup::adjustSound();
|
Powerup::adjustSound();
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
}
|
}
|
||||||
else // if the kart is looking forward, use the bubblegum as a shield
|
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.
|
//In this case this is a workaround, since the bubblegum item has two different sounds.
|
||||||
|
|
||||||
Powerup::adjustSound();
|
Powerup::adjustSound();
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
|
|
||||||
} // end of PowerupManager::POWERUP_BUBBLEGUM
|
} // end of PowerupManager::POWERUP_BUBBLEGUM
|
||||||
break;
|
break;
|
||||||
@ -359,7 +367,7 @@ void Powerup::use()
|
|||||||
else
|
else
|
||||||
m_sound_use->setPosition(m_kart->getXYZ());
|
m_sound_use->setPosition(m_kart->getXYZ());
|
||||||
|
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,7 +426,7 @@ void Powerup::use()
|
|||||||
m_sound_use->setPosition(m_kart->getXYZ());
|
m_sound_use->setPosition(m_kart->getXYZ());
|
||||||
else if(player_kart)
|
else if(player_kart)
|
||||||
m_sound_use->setPosition(player_kart->getXYZ());
|
m_sound_use->setPosition(player_kart->getXYZ());
|
||||||
m_sound_use->play();
|
playSound();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -36,9 +36,6 @@ class SFXBase;
|
|||||||
class Powerup : public NoCopy
|
class Powerup : public NoCopy
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/** A synchronised random number generator for network games. */
|
|
||||||
RandomGenerator m_random;
|
|
||||||
|
|
||||||
/** Sound effect that is being played. */
|
/** Sound effect that is being played. */
|
||||||
SFXBase *m_sound_use;
|
SFXBase *m_sound_use;
|
||||||
|
|
||||||
@ -51,6 +48,7 @@ private:
|
|||||||
/** The owner (kart) of this powerup. */
|
/** The owner (kart) of this powerup. */
|
||||||
AbstractKart* m_kart;
|
AbstractKart* m_kart;
|
||||||
|
|
||||||
|
void playSound();
|
||||||
public:
|
public:
|
||||||
Powerup (AbstractKart* kart_);
|
Powerup (AbstractKart* kart_);
|
||||||
~Powerup ();
|
~Powerup ();
|
||||||
|
@ -298,7 +298,7 @@ void PowerupManager::WeightsData::convertRankToSection(int rank, int *prev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The last kart always uses the data for the last section
|
// 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;
|
*prev = *next = m_weights_for_section.size() - 1;
|
||||||
*weight = 1.0f;
|
*weight = 1.0f;
|
||||||
@ -600,9 +600,11 @@ void PowerupManager::unitTesting()
|
|||||||
int num_weights = wd.m_summed_weights_for_rank[0].back();
|
int num_weights = wd.m_summed_weights_for_rank[0].back();
|
||||||
for(int i=0; i<num_weights; i++)
|
for(int i=0; i<num_weights; i++)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
assert( powerup_manager->getRandomPowerup(1, &n, i)==POWERUP_BOWLING );
|
assert( powerup_manager->getRandomPowerup(1, &n, i)==POWERUP_BOWLING );
|
||||||
assert(n==3);
|
assert(n==3);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 2: Test all possible random numbers for 5 karts and rank 5
|
// Test 2: Test all possible random numbers for 5 karts and rank 5
|
||||||
|
@ -139,7 +139,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const int RAND_CLASS_RANGE = 1000;
|
|
||||||
|
|
||||||
/** The icon for each powerup. */
|
/** The icon for each powerup. */
|
||||||
Material* m_all_icons [POWERUP_MAX];
|
Material* m_all_icons [POWERUP_MAX];
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include "items/powerup.hpp"
|
#include "items/powerup.hpp"
|
||||||
#include "items/rubber_ball.hpp"
|
#include "items/rubber_ball.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
|
#include "modes/world.hpp"
|
||||||
|
#include "network/rewind_manager.hpp"
|
||||||
|
|
||||||
ProjectileManager *projectile_manager=0;
|
ProjectileManager *projectile_manager=0;
|
||||||
|
|
||||||
@ -45,12 +47,6 @@ void ProjectileManager::removeTextures()
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ProjectileManager::cleanup()
|
void ProjectileManager::cleanup()
|
||||||
{
|
{
|
||||||
for(Projectiles::iterator i = m_active_projectiles.begin();
|
|
||||||
i != m_active_projectiles.end(); ++i)
|
|
||||||
{
|
|
||||||
delete *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_active_projectiles.clear();
|
m_active_projectiles.clear();
|
||||||
for(HitEffects::iterator i = m_active_hit_effects.begin();
|
for(HitEffects::iterator i = m_active_hit_effects.begin();
|
||||||
i != m_active_hit_effects.end(); ++i)
|
i != m_active_hit_effects.end(); ++i)
|
||||||
@ -68,12 +64,8 @@ void ProjectileManager::cleanup()
|
|||||||
*/
|
*/
|
||||||
void ProjectileManager::updateGraphics(float dt)
|
void ProjectileManager::updateGraphics(float dt)
|
||||||
{
|
{
|
||||||
for (auto p = m_active_projectiles.begin();
|
for (auto& p : m_active_projectiles)
|
||||||
p != m_active_projectiles.end(); ++p)
|
p.second->updateGraphics(dt);
|
||||||
{
|
|
||||||
(*p)->updateGraphics(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // updateGraphics
|
} // updateGraphics
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -82,6 +74,8 @@ void ProjectileManager::update(int ticks)
|
|||||||
{
|
{
|
||||||
updateServer(ticks);
|
updateServer(ticks);
|
||||||
|
|
||||||
|
if (RewindManager::get()->isRewinding())
|
||||||
|
return;
|
||||||
HitEffects::iterator he = m_active_hit_effects.begin();
|
HitEffects::iterator he = m_active_hit_effects.begin();
|
||||||
while(he!=m_active_hit_effects.end())
|
while(he!=m_active_hit_effects.end())
|
||||||
{
|
{
|
||||||
@ -107,19 +101,25 @@ void ProjectileManager::update(int ticks)
|
|||||||
/** Updates all rockets on the server (or no networking). */
|
/** Updates all rockets on the server (or no networking). */
|
||||||
void ProjectileManager::updateServer(int ticks)
|
void ProjectileManager::updateServer(int ticks)
|
||||||
{
|
{
|
||||||
Projectiles::iterator p = m_active_projectiles.begin();
|
auto p = m_active_projectiles.begin();
|
||||||
while(p!=m_active_projectiles.end())
|
while (p != m_active_projectiles.end())
|
||||||
{
|
{
|
||||||
bool can_be_deleted = (*p)->updateAndDelete(ticks);
|
if (p->second->isUndoCreation())
|
||||||
if(can_be_deleted)
|
|
||||||
{
|
{
|
||||||
HitEffect *he = (*p)->getHitEffect();
|
p++;
|
||||||
if(he)
|
continue;
|
||||||
addHitEffect(he);
|
}
|
||||||
Flyable *f=*p;
|
bool can_be_deleted = p->second->updateAndDelete(ticks);
|
||||||
Projectiles::iterator p_next=m_active_projectiles.erase(p);
|
if (can_be_deleted)
|
||||||
delete f;
|
{
|
||||||
p=p_next;
|
if (!p->second->hasUndoneDestruction())
|
||||||
|
{
|
||||||
|
HitEffect *he = p->second->getHitEffect();
|
||||||
|
if (he)
|
||||||
|
addHitEffect(he);
|
||||||
|
}
|
||||||
|
p->second->handleUndoDestruction();
|
||||||
|
p = m_active_projectiles.erase(p);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
p++;
|
p++;
|
||||||
@ -132,20 +132,40 @@ void ProjectileManager::updateServer(int ticks)
|
|||||||
* \param kart The kart which shoots the projectile.
|
* \param kart The kart which shoots the projectile.
|
||||||
* \param type Type of projectile.
|
* \param type Type of projectile.
|
||||||
*/
|
*/
|
||||||
Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
|
std::shared_ptr<Flyable>
|
||||||
PowerupManager::PowerupType type)
|
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)
|
switch(type)
|
||||||
{
|
{
|
||||||
case PowerupManager::POWERUP_BOWLING: f = new Bowling(kart); break;
|
case PowerupManager::POWERUP_BOWLING:
|
||||||
case PowerupManager::POWERUP_PLUNGER: f = new Plunger(kart); break;
|
f = std::make_shared<Bowling>(kart);
|
||||||
case PowerupManager::POWERUP_CAKE: f = new Cake(kart); break;
|
break;
|
||||||
case PowerupManager::POWERUP_RUBBERBALL: f = new RubberBall(kart);
|
case PowerupManager::POWERUP_PLUNGER:
|
||||||
break;
|
f = std::make_shared<Plunger>(kart);
|
||||||
default: return NULL;
|
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;
|
return f;
|
||||||
} // newProjectile
|
} // newProjectile
|
||||||
|
|
||||||
@ -158,13 +178,15 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
|
|||||||
bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
|
bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
|
||||||
float radius)
|
float radius)
|
||||||
{
|
{
|
||||||
float r2 = radius*radius;
|
float r2 = radius * radius;
|
||||||
|
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
|
||||||
for(Projectiles::iterator i = m_active_projectiles.begin();
|
i++)
|
||||||
i != m_active_projectiles.end(); i++)
|
|
||||||
{
|
{
|
||||||
float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
|
if (i->second->isUndoCreation())
|
||||||
if(dist2<r2) return true;
|
continue;
|
||||||
|
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
|
||||||
|
if (dist2 < r2)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} // projectileIsClose
|
} // projectileIsClose
|
||||||
@ -179,21 +201,101 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
|
|||||||
int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
|
int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
|
||||||
float radius, PowerupManager::PowerupType type)
|
float radius, PowerupManager::PowerupType type)
|
||||||
{
|
{
|
||||||
float r2 = radius*radius;
|
float r2 = radius * radius;
|
||||||
int projectileCount = 0;
|
int projectile_count = 0;
|
||||||
|
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
|
||||||
for(Projectiles::iterator i = m_active_projectiles.begin();
|
i++)
|
||||||
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());
|
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
|
||||||
if(dist2<r2)
|
if (dist2 < r2)
|
||||||
{
|
{
|
||||||
|
projectile_count++;
|
||||||
projectileCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return projectileCount;
|
return projectile_count;
|
||||||
} // getNearbyProjectileCount
|
} // 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
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#ifndef HEADER_PROJECTILEMANAGER_HPP
|
#ifndef HEADER_PROJECTILEMANAGER_HPP
|
||||||
#define HEADER_PROJECTILEMANAGER_HPP
|
#define HEADER_PROJECTILEMANAGER_HPP
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
@ -32,6 +34,7 @@ namespace irr
|
|||||||
class AbstractKart;
|
class AbstractKart;
|
||||||
class Flyable;
|
class Flyable;
|
||||||
class HitEffect;
|
class HitEffect;
|
||||||
|
class Rewinder;
|
||||||
class Track;
|
class Track;
|
||||||
class Vec3;
|
class Vec3;
|
||||||
|
|
||||||
@ -41,17 +44,18 @@ class Vec3;
|
|||||||
class ProjectileManager : public NoCopy
|
class ProjectileManager : public NoCopy
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef std::vector<Flyable*> Projectiles;
|
|
||||||
typedef std::vector<HitEffect*> HitEffects;
|
typedef std::vector<HitEffect*> HitEffects;
|
||||||
|
|
||||||
/** The list of all active projectiles, i.e. projectiles which are
|
/** The list of all active projectiles, i.e. projectiles which are
|
||||||
* currently moving on the track. */
|
* 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
|
/** All active hit effects, i.e. hit effects which are currently
|
||||||
* being shown or have a sfx playing. */
|
* being shown or have a sfx playing. */
|
||||||
HitEffects m_active_hit_effects;
|
HitEffects m_active_hit_effects;
|
||||||
|
|
||||||
|
std::string getUniqueIdentity(AbstractKart* kart,
|
||||||
|
PowerupManager::PowerupType type);
|
||||||
void updateServer(int ticks);
|
void updateServer(int ticks);
|
||||||
public:
|
public:
|
||||||
ProjectileManager() {}
|
ProjectileManager() {}
|
||||||
@ -60,9 +64,6 @@ public:
|
|||||||
void cleanup ();
|
void cleanup ();
|
||||||
void update (int ticks);
|
void update (int ticks);
|
||||||
void updateGraphics (float dt);
|
void updateGraphics (float dt);
|
||||||
Flyable* newProjectile (AbstractKart *kart,
|
|
||||||
PowerupManager::PowerupType type);
|
|
||||||
void Deactivate (Flyable *p) {}
|
|
||||||
void removeTextures ();
|
void removeTextures ();
|
||||||
bool projectileIsClose(const AbstractKart * const kart,
|
bool projectileIsClose(const AbstractKart * const kart,
|
||||||
float radius);
|
float radius);
|
||||||
@ -74,6 +75,19 @@ public:
|
|||||||
* \param hit_effect The hit effect to be added. */
|
* \param hit_effect The hit effect to be added. */
|
||||||
void addHitEffect(HitEffect *hit_effect)
|
void addHitEffect(HitEffect *hit_effect)
|
||||||
{ m_active_hit_effects.push_back(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;
|
extern ProjectileManager *projectile_manager;
|
||||||
|
@ -89,7 +89,7 @@ AbstractKartAnimation::~AbstractKartAnimation()
|
|||||||
Vec3 linear_velocity = kart->getBody()->getLinearVelocity();
|
Vec3 linear_velocity = kart->getBody()->getLinearVelocity();
|
||||||
Vec3 angular_velocity = kart->getBody()->getAngularVelocity();
|
Vec3 angular_velocity = kart->getBody()->getAngularVelocity();
|
||||||
btTransform transform = kart->getBody()->getWorldTransform();
|
btTransform transform = kart->getBody()->getWorldTransform();
|
||||||
RewindManager::get()->getRewindQueue().insertRewindInfo(new
|
RewindManager::get()->addRewindInfoEventFunction(new
|
||||||
RewindInfoEventFunction(
|
RewindInfoEventFunction(
|
||||||
World::getWorld()->getTicksSinceStart(),
|
World::getWorld()->getTicksSinceStart(),
|
||||||
[kart]()
|
[kart]()
|
||||||
|
@ -35,7 +35,8 @@ Controller::Controller(AbstractKart *kart)
|
|||||||
setControllerName("Controller");
|
setControllerName("Controller");
|
||||||
} // Controller
|
} // Controller
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
core::stringw Controller::getName() const
|
core::stringw Controller::getName() const
|
||||||
{
|
{
|
||||||
return translations->fribidize(m_kart->getName());
|
return translations->fribidize(m_kart->getName());
|
||||||
}
|
} // getName
|
||||||
|
18
src/karts/controller/network_player_controller.hpp
Normal file → Executable file
18
src/karts/controller/network_player_controller.hpp
Normal file → Executable file
@ -18,6 +18,7 @@
|
|||||||
#define HEADER_NETWORK_PLAYER_CONTROLLER_HPP
|
#define HEADER_NETWORK_PLAYER_CONTROLLER_HPP
|
||||||
|
|
||||||
#include "karts/controller/player_controller.hpp"
|
#include "karts/controller/player_controller.hpp"
|
||||||
|
#include "network/network_config.hpp"
|
||||||
|
|
||||||
class AbstractKart;
|
class AbstractKart;
|
||||||
class Player;
|
class Player;
|
||||||
@ -42,6 +43,23 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
} // isLocal
|
} // isLocal
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
/** Update for network controller. For player with a high ping it is
|
||||||
|
* useful to reduce shaking by reducing the steering somewhat in each
|
||||||
|
* frame: If the player does a quick correction only, because of the high
|
||||||
|
* latency the predicted path will curve way too much. By automatically
|
||||||
|
* reducing it, this error is reduced. And even if the player steers more
|
||||||
|
* the error is hopefully acceptable. */
|
||||||
|
virtual void update(int ticks)
|
||||||
|
{
|
||||||
|
PlayerController::update(ticks);
|
||||||
|
if (NetworkConfig::get()->isClient())
|
||||||
|
{
|
||||||
|
m_controls->setSteer( m_controls->getSteer()
|
||||||
|
* stk_config->m_network_steering_reduction);
|
||||||
|
}
|
||||||
|
} // update
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
}; // NetworkPlayerController
|
}; // NetworkPlayerController
|
||||||
|
|
||||||
#endif // NETWORK_PLAYER_CONTROLLER_HPP
|
#endif // NETWORK_PLAYER_CONTROLLER_HPP
|
||||||
|
@ -47,6 +47,7 @@ void GhostKart::reset()
|
|||||||
Kart::reset();
|
Kart::reset();
|
||||||
// This will set the correct start position
|
// This will set the correct start position
|
||||||
update(0);
|
update(0);
|
||||||
|
updateGraphics(0);
|
||||||
m_last_egg_idx = 0;
|
m_last_egg_idx = 0;
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
|
|
||||||
#include <algorithm> // for min and max
|
#include <algorithm> // for min and max
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
|||||||
m_bubblegum_ticks = 0;
|
m_bubblegum_ticks = 0;
|
||||||
m_bubblegum_torque = 0.0f;
|
m_bubblegum_torque = 0.0f;
|
||||||
m_invulnerable_ticks = 0;
|
m_invulnerable_ticks = 0;
|
||||||
m_squash_ticks = 0;
|
m_squash_time = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
m_shadow = NULL;
|
m_shadow = NULL;
|
||||||
m_wheel_box = NULL;
|
m_wheel_box = NULL;
|
||||||
@ -366,7 +367,7 @@ void Kart::reset()
|
|||||||
m_bubblegum_ticks = 0;
|
m_bubblegum_ticks = 0;
|
||||||
m_bubblegum_torque = 0.0f;
|
m_bubblegum_torque = 0.0f;
|
||||||
m_invulnerable_ticks = 0;
|
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_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
|
||||||
m_collected_energy = 0;
|
m_collected_energy = 0;
|
||||||
m_has_started = false;
|
m_has_started = false;
|
||||||
@ -858,6 +859,8 @@ void Kart::adjustSpeed(float f)
|
|||||||
*/
|
*/
|
||||||
void Kart::updateWeight()
|
void Kart::updateWeight()
|
||||||
{
|
{
|
||||||
|
if (!m_body)
|
||||||
|
return;
|
||||||
float mass = m_kart_properties->getMass() + m_attachment->weightAdjust();
|
float mass = m_kart_properties->getMass() + m_attachment->weightAdjust();
|
||||||
if (m_weight != mass)
|
if (m_weight != mass)
|
||||||
{
|
{
|
||||||
@ -1280,34 +1283,12 @@ void Kart::update(int ticks)
|
|||||||
// Reset any instand speed increase in the bullet kart
|
// Reset any instand speed increase in the bullet kart
|
||||||
m_vehicle->setMinSpeed(0);
|
m_vehicle->setMinSpeed(0);
|
||||||
|
|
||||||
if(m_squash_ticks>=0)
|
if (m_bubblegum_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)
|
|
||||||
{
|
{
|
||||||
m_bubblegum_ticks -= ticks;
|
m_bubblegum_ticks -= ticks;
|
||||||
if (m_bubblegum_ticks <= 0.0f)
|
if (m_bubblegum_ticks <= 0)
|
||||||
{
|
{
|
||||||
m_bubblegum_torque = 0.0f;
|
m_bubblegum_torque = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1757,23 +1738,42 @@ void Kart::setSquash(float time, float slowdown)
|
|||||||
ExplosionAnimation::create(this);
|
ExplosionAnimation::create(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
|
|
||||||
m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown,
|
m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown,
|
||||||
stk_config->time2Ticks(0.1f),
|
stk_config->time2Ticks(0.1f),
|
||||||
stk_config->time2Ticks(time));
|
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_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
|
||||||
m_wheel_box = irr_driver->getSceneManager()->addDummyTransformationSceneNode(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])
|
if (!m_wheel_box)
|
||||||
wheels[i]->setParent(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
|
} // setSquash
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -2946,6 +2946,30 @@ void Kart::updateGraphics(float dt)
|
|||||||
if (m_custom_sounds[n] != NULL) m_custom_sounds[n]->position(getXYZ());
|
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++)
|
for (int i = 0; i < EMITTER_COUNT; i++)
|
||||||
m_emitters[i]->setPosition(getXYZ());
|
m_emitters[i]->setPosition(getXYZ());
|
||||||
m_skid_sound->setPosition(getXYZ());
|
m_skid_sound->setPosition(getXYZ());
|
||||||
|
@ -160,17 +160,17 @@ protected:
|
|||||||
int m_bounce_back_ticks;
|
int m_bounce_back_ticks;
|
||||||
|
|
||||||
/** Time a kart is invulnerable. */
|
/** 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
|
/** How long a kart is being squashed. If this is >0
|
||||||
* the kart is squashed. */
|
* the kart is squashed. */
|
||||||
int m_squash_ticks;
|
float m_squash_time;
|
||||||
|
|
||||||
/** Current leaning of the kart. */
|
/** Current leaning of the kart. */
|
||||||
float m_current_lean;
|
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. */
|
/** 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. */
|
/** The torque to apply after hitting a bubble gum. */
|
||||||
float m_bubblegum_torque;
|
float m_bubblegum_torque;
|
||||||
@ -218,12 +218,9 @@ protected:
|
|||||||
|
|
||||||
/** When a kart has its view blocked by the plunger, this variable will be
|
/** 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. */
|
* > 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. */
|
/** The current speed (i.e. length of velocity vector) of this kart. */
|
||||||
float m_speed;
|
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**/
|
/** For smoothing engine sound**/
|
||||||
float m_last_factor_engine_sound;
|
float m_last_factor_engine_sound;
|
||||||
@ -499,7 +496,7 @@ public:
|
|||||||
virtual bool isOnMinNitroTime() const OVERRIDE { return m_min_nitro_ticks > 0; }
|
virtual bool isOnMinNitroTime() const OVERRIDE { return m_min_nitro_ticks > 0; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns if the kart is currently being squashed. */
|
/** 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. */
|
/** Shows the star effect for a certain time. */
|
||||||
virtual void showStarEffect(float t) OVERRIDE;
|
virtual void showStarEffect(float t) OVERRIDE;
|
||||||
|
@ -38,8 +38,7 @@ KartRewinder::KartRewinder(const std::string& ident,
|
|||||||
const btTransform& init_transform,
|
const btTransform& init_transform,
|
||||||
PerPlayerDifficulty difficulty,
|
PerPlayerDifficulty difficulty,
|
||||||
std::shared_ptr<RenderInfo> ri)
|
std::shared_ptr<RenderInfo> ri)
|
||||||
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id),
|
: Rewinder(std::string("K") + StringUtils::toString(world_kart_id))
|
||||||
/*can_be_destroyed*/ false)
|
|
||||||
, Kart(ident, world_kart_id, position, init_transform, difficulty,
|
, Kart(ident, world_kart_id, position, init_transform, difficulty,
|
||||||
ri)
|
ri)
|
||||||
{
|
{
|
||||||
@ -144,6 +143,15 @@ BareNetworkString* KartRewinder::saveState(std::vector<std::string>* ru)
|
|||||||
// -----------
|
// -----------
|
||||||
m_skidding->saveState(buffer);
|
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;
|
return buffer;
|
||||||
} // saveState
|
} // saveState
|
||||||
|
|
||||||
@ -203,15 +211,21 @@ void KartRewinder::restoreState(BareNetworkString *buffer, int count)
|
|||||||
float nitro = buffer->getFloat();
|
float nitro = buffer->getFloat();
|
||||||
setEnergy(nitro);
|
setEnergy(nitro);
|
||||||
|
|
||||||
// 5) Max speed info
|
// 4) Max speed info
|
||||||
// ------------------
|
// ------------------
|
||||||
m_max_speed->rewindTo(buffer);
|
m_max_speed->rewindTo(buffer);
|
||||||
|
|
||||||
// 6) Skidding
|
// 5) Skidding
|
||||||
// -----------
|
// -----------
|
||||||
m_skidding->rewindTo(buffer);
|
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
|
} // restoreState
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -223,25 +237,16 @@ void KartRewinder::update(int ticks)
|
|||||||
Kart::update(ticks);
|
Kart::update(ticks);
|
||||||
} // update
|
} // update
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
void KartRewinder::rewindToEvent(BareNetworkString *buffer)
|
|
||||||
{
|
|
||||||
} // rewindToEvent
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
std::function<void()> KartRewinder::getLocalStateRestoreFunction()
|
std::function<void()> KartRewinder::getLocalStateRestoreFunction()
|
||||||
{
|
{
|
||||||
if (m_eliminated)
|
if (m_eliminated)
|
||||||
return nullptr;
|
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;
|
bool has_started = m_has_started;
|
||||||
int bubblegum_ticks = m_bubblegum_ticks;
|
|
||||||
int bounce_back_ticks = m_bounce_back_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;
|
int brake_ticks = m_brake_ticks;
|
||||||
int8_t min_nitro_ticks = m_min_nitro_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;
|
steer_val_r = pc->m_steer_val_r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [has_started, bubblegum_ticks, bounce_back_ticks,
|
return [has_started, bounce_back_ticks, brake_ticks, min_nitro_ticks,
|
||||||
invulnerable_ticks, squash_ticks, fire_clicked,
|
initial_speed, node_scale, steer_val_l, steer_val_r, this]()
|
||||||
view_blocked_by_plunger, brake_ticks, min_nitro_ticks, initial_speed,
|
|
||||||
node_scale, steer_val_l, steer_val_r, this]()
|
|
||||||
{
|
{
|
||||||
m_has_started = has_started;
|
m_has_started = has_started;
|
||||||
m_bubblegum_ticks = bubblegum_ticks;
|
|
||||||
m_bounce_back_ticks = bounce_back_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_brake_ticks = brake_ticks;
|
||||||
m_min_nitro_ticks = min_nitro_ticks;
|
m_min_nitro_ticks = min_nitro_ticks;
|
||||||
getAttachment()->setInitialSpeed(initial_speed);
|
getAttachment()->setInitialSpeed(initial_speed);
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
OVERRIDE;
|
OVERRIDE;
|
||||||
void reset() OVERRIDE;
|
void reset() OVERRIDE;
|
||||||
virtual void restoreState(BareNetworkString *p, int count) 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 void update(int ticks) OVERRIDE;
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
virtual float getSteerPercent() const OVERRIDE
|
virtual float getSteerPercent() const OVERRIDE
|
||||||
|
@ -280,6 +280,15 @@ int MaxSpeed::getSpeedIncreaseTicksLeft(unsigned int category)
|
|||||||
return m_speed_increase[category].getTimeLeft();
|
return m_speed_increase[category].getTimeLeft();
|
||||||
} // getSpeedIncreaseTimeLeft
|
} // 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
|
/** Updates all speed increase and decrease objects, and determines the
|
||||||
* current maximum speed. Note that the function can be called with
|
* current maximum speed. Note that the function can be called with
|
||||||
|
@ -158,11 +158,13 @@ private:
|
|||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
/** Returns the current slowdown fracftion, taking a 'fade in'
|
/** Returns the current slowdown fracftion, taking a 'fade in'
|
||||||
* into account. */
|
* 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
|
/** Returns if this speed decrease is active atm. A duration of
|
||||||
* -1 indicates an ongoing effect. */
|
* -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
|
}; // SpeedDecrease
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -188,6 +190,7 @@ public:
|
|||||||
void setSlowdown(unsigned int category, float max_speed_fraction,
|
void setSlowdown(unsigned int category, float max_speed_fraction,
|
||||||
int fade_in_time, int duration=-1);
|
int fade_in_time, int duration=-1);
|
||||||
int getSpeedIncreaseTicksLeft(unsigned int category);
|
int getSpeedIncreaseTicksLeft(unsigned int category);
|
||||||
|
int isSpeedDecreaseActive(unsigned int category);
|
||||||
void update(int ticks);
|
void update(int ticks);
|
||||||
void reset();
|
void reset();
|
||||||
void saveState(BareNetworkString *buffer) const;
|
void saveState(BareNetworkString *buffer) const;
|
||||||
|
@ -62,7 +62,10 @@ void Moveable::setNode(scene::ISceneNode *n)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void Moveable::updateSmoothedGraphics(float dt)
|
void Moveable::updateSmoothedGraphics(float dt)
|
||||||
{
|
{
|
||||||
SmoothNetworkBody::updateSmoothedGraphics(m_transform, getVelocity(), dt);
|
Vec3 velocity;
|
||||||
|
if (m_body)
|
||||||
|
velocity = m_body->getLinearVelocity();
|
||||||
|
SmoothNetworkBody::updateSmoothedGraphics(m_transform, velocity, dt);
|
||||||
#undef DEBUG_SMOOTHING
|
#undef DEBUG_SMOOTHING
|
||||||
#ifdef DEBUG_SMOOTHING
|
#ifdef DEBUG_SMOOTHING
|
||||||
// Gnuplot compare command
|
// Gnuplot compare command
|
||||||
|
33
src/main.cpp
33
src/main.cpp
@ -603,11 +603,13 @@ void cmdLineHelp()
|
|||||||
" --disable-lan Disable LAN detection (connect using WAN).\n"
|
" --disable-lan Disable LAN detection (connect using WAN).\n"
|
||||||
" --auto-connect Automatically connect to fist server and start race\n"
|
" --auto-connect Automatically connect to fist server and start race\n"
|
||||||
" --max-players=n Maximum number of clients (server only).\n"
|
" --max-players=n Maximum number of clients (server only).\n"
|
||||||
|
" --min-players=n Minimum number of clients (server only).\n"
|
||||||
" --motd Message showing in all lobby of clients, can specify a .txt file.\n"
|
" --motd Message showing in all lobby of clients, can specify a .txt file.\n"
|
||||||
" --auto-end Automatically end network game after 1st player finished\n"
|
" --auto-end Automatically end network game after 1st player finished\n"
|
||||||
" for some time (currently his finished time * 0.25 + 15.0). \n"
|
" for some time (currently his finished time * 0.25 + 15.0). \n"
|
||||||
" --team-choosing Allow choosing team in lobby, implicitly allowed in lan or\n"
|
" --team-choosing Allow choosing team in lobby, implicitly allowed in lan or\n"
|
||||||
" password protected server.\n"
|
" password protected server. This function cannot be used in\n"
|
||||||
|
" owner-less server.\n"
|
||||||
" --soccer-timed Use time limit mode in network soccer game.\n"
|
" --soccer-timed Use time limit mode in network soccer game.\n"
|
||||||
" --soccer-goals Use goals limit mode in network soccer game.\n"
|
" --soccer-goals Use goals limit mode in network soccer game.\n"
|
||||||
" --network-gp=n Specify number of tracks used in network grand prix.\n"
|
" --network-gp=n Specify number of tracks used in network grand prix.\n"
|
||||||
@ -1139,12 +1141,28 @@ int handleCmdLine()
|
|||||||
NetworkConfig::get()->setServerIdFile(
|
NetworkConfig::get()->setServerIdFile(
|
||||||
file_manager->getUserConfigFile(s));
|
file_manager->getUserConfigFile(s));
|
||||||
}
|
}
|
||||||
if(CommandLine::has("--disable-polling"))
|
if (CommandLine::has("--disable-polling"))
|
||||||
|
{
|
||||||
Online::RequestManager::m_disable_polling = true;
|
Online::RequestManager::m_disable_polling = true;
|
||||||
if(CommandLine::has("--max-players", &n))
|
}
|
||||||
UserConfigParams::m_server_max_players=n;
|
if (CommandLine::has("--max-players", &n))
|
||||||
NetworkConfig::get()->
|
{
|
||||||
setMaxPlayers(UserConfigParams::m_server_max_players);
|
UserConfigParams::m_server_max_players = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UserConfigParams::m_server_max_players < 1)
|
||||||
|
{
|
||||||
|
UserConfigParams::m_server_max_players = 1;
|
||||||
|
}
|
||||||
|
NetworkConfig::get()->setMaxPlayers(UserConfigParams::m_server_max_players);
|
||||||
|
|
||||||
|
if (CommandLine::has("--min-players", &n))
|
||||||
|
{
|
||||||
|
float threshold = ((float)(n) - 0.5f) /
|
||||||
|
UserConfigParams::m_server_max_players;
|
||||||
|
threshold = std::max(std::min(threshold, 1.0f), 0.0f);
|
||||||
|
UserConfigParams::m_start_game_threshold = threshold;
|
||||||
|
}
|
||||||
if (CommandLine::has("--port", &n))
|
if (CommandLine::has("--port", &n))
|
||||||
{
|
{
|
||||||
// We don't know if this instance is going to be a client
|
// We don't know if this instance is going to be a client
|
||||||
@ -1158,7 +1176,8 @@ int handleCmdLine()
|
|||||||
}
|
}
|
||||||
if (CommandLine::has("--team-choosing"))
|
if (CommandLine::has("--team-choosing"))
|
||||||
{
|
{
|
||||||
NetworkConfig::get()->setTeamChoosing(true);
|
if (!NetworkConfig::get()->isOwnerLess())
|
||||||
|
NetworkConfig::get()->setTeamChoosing(true);
|
||||||
}
|
}
|
||||||
if (CommandLine::has("--connect-now", &s))
|
if (CommandLine::has("--connect-now", &s))
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,8 @@ CutsceneWorld::CutsceneWorld() : World()
|
|||||||
{
|
{
|
||||||
m_time_at_second_reset = 0.0f;
|
m_time_at_second_reset = 0.0f;
|
||||||
m_aborted = false;
|
m_aborted = false;
|
||||||
WorldStatus::setClockMode(CLOCK_NONE);
|
WorldStatus::setClockMode(CLOCK_CHRONO);
|
||||||
|
m_phase = RACE_PHASE;
|
||||||
m_use_highscores = false;
|
m_use_highscores = false;
|
||||||
m_play_track_intro_sound = false;
|
m_play_track_intro_sound = false;
|
||||||
m_play_ready_set_go_sounds = false;
|
m_play_ready_set_go_sounds = false;
|
||||||
@ -170,7 +171,12 @@ void CutsceneWorld::init()
|
|||||||
CutsceneWorld::~CutsceneWorld()
|
CutsceneWorld::~CutsceneWorld()
|
||||||
{
|
{
|
||||||
} // ~CutsceneWorld
|
} // ~CutsceneWorld
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void CutsceneWorld::reset()
|
||||||
|
{
|
||||||
|
World::reset();
|
||||||
|
m_phase = RACE_PHASE;
|
||||||
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Returns the internal identifier for this race.
|
/** Returns the internal identifier for this race.
|
||||||
*/
|
*/
|
||||||
@ -231,7 +237,6 @@ void CutsceneWorld::update(int ticks)
|
|||||||
{
|
{
|
||||||
// this way of calculating time and dt is more in line with what
|
// this way of calculating time and dt is more in line with what
|
||||||
// irrlicht does and provides better synchronisation
|
// irrlicht does and provides better synchronisation
|
||||||
double prev_time = m_time;
|
|
||||||
double now = StkTime::getRealTime();
|
double now = StkTime::getRealTime();
|
||||||
m_time = now - m_time_at_second_reset;
|
m_time = now - m_time_at_second_reset;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,8 @@ public:
|
|||||||
|
|
||||||
virtual void init() OVERRIDE;
|
virtual void init() OVERRIDE;
|
||||||
|
|
||||||
|
virtual void reset() OVERRIDE;
|
||||||
|
|
||||||
// clock events
|
// clock events
|
||||||
virtual bool isRaceOver() OVERRIDE;
|
virtual bool isRaceOver() OVERRIDE;
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ void LinearWorld::update(int ticks)
|
|||||||
for(unsigned int n=0; n<kart_amount; n++)
|
for(unsigned int n=0; n<kart_amount; n++)
|
||||||
{
|
{
|
||||||
KartInfo& kart_info = m_kart_info[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
|
// Nothing to do for karts that are currently being
|
||||||
// rescued or eliminated
|
// rescued or eliminated
|
||||||
@ -218,7 +218,7 @@ void LinearWorld::update(int ticks)
|
|||||||
// Update the estimated finish time.
|
// Update the estimated finish time.
|
||||||
// This is used by the AI
|
// This is used by the AI
|
||||||
m_kart_info[i].m_estimated_finish =
|
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,
|
// If one player and a ghost, or two compared ghosts,
|
||||||
// compute the live time difference
|
// compute the live time difference
|
||||||
@ -328,7 +328,7 @@ void LinearWorld::updateLiveDifference()
|
|||||||
void LinearWorld::newLap(unsigned int kart_index)
|
void LinearWorld::newLap(unsigned int kart_index)
|
||||||
{
|
{
|
||||||
KartInfo &kart_info = m_kart_info[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
|
// Reset reset-after-lap achievements
|
||||||
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
||||||
@ -556,7 +556,7 @@ void LinearWorld::getKartsDisplayInfo(
|
|||||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||||
{
|
{
|
||||||
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
||||||
AbstractKart* kart = m_karts[i];
|
AbstractKart* kart = m_karts[i].get();
|
||||||
|
|
||||||
// reset color
|
// reset color
|
||||||
rank_info.m_color = video::SColor(255, 255, 255, 255);
|
rank_info.m_color = video::SColor(255, 255, 255, 255);
|
||||||
@ -585,7 +585,7 @@ void LinearWorld::getKartsDisplayInfo(
|
|||||||
{
|
{
|
||||||
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
||||||
KartInfo& kart_info = m_kart_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();
|
const int position = kart->getPosition();
|
||||||
|
|
||||||
@ -799,7 +799,7 @@ void LinearWorld::updateRacePosition()
|
|||||||
// so that debug output is still correct!!!!!!!!!!!
|
// so that debug output is still correct!!!!!!!!!!!
|
||||||
for (unsigned int i=0; i<kart_amount; i++)
|
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
|
// Karts that are either eliminated or have finished the
|
||||||
// race already have their (final) position assigned. If
|
// race already have their (final) position assigned. If
|
||||||
// these karts would get their rank updated, it could happen
|
// 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());
|
Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime());
|
||||||
for (unsigned int i=0; i<kart_amount; i++)
|
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,"
|
Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u,"
|
||||||
" progress %u, finished %d, eliminated %d, initial position %u.",
|
" progress %u, finished %d, eliminated %d, initial position %u.",
|
||||||
kart->getIdent().c_str(),
|
kart->getIdent().c_str(),
|
||||||
@ -973,7 +973,7 @@ void LinearWorld::checkForWrongDirection(unsigned int i, float dt)
|
|||||||
|
|
||||||
KartInfo &ki = m_kart_info[i];
|
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
|
// 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
|
// 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.
|
// will be one direction in which it isn't going backwards anyway.
|
||||||
|
@ -103,19 +103,18 @@ void ProfileWorld::setProfileModeLaps(int laps)
|
|||||||
* this player globally (i.e. including network players).
|
* this player globally (i.e. including network players).
|
||||||
* \param init_pos The start XYZ coordinates.
|
* \param init_pos The start XYZ coordinates.
|
||||||
*/
|
*/
|
||||||
AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
|
std::shared_ptr<AbstractKart> ProfileWorld::createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType type,
|
int global_player_id, RaceManager::KartType kart_type,
|
||||||
PerPlayerDifficulty difficulty)
|
PerPlayerDifficulty difficulty)
|
||||||
{
|
{
|
||||||
btTransform init_pos = getStartTransform(index);
|
btTransform init_pos = getStartTransform(index);
|
||||||
|
|
||||||
Kart *new_kart = new KartWithStats(kart_ident,
|
std::shared_ptr<KartWithStats> new_kart =
|
||||||
/*world kart id*/ index,
|
std::make_shared<KartWithStats>(kart_ident, /*world kart id*/ index,
|
||||||
/*position*/ index+1,
|
/*position*/ index + 1, init_pos, difficulty);
|
||||||
init_pos, difficulty);
|
|
||||||
new_kart->init(RaceManager::KT_AI);
|
new_kart->init(RaceManager::KT_AI);
|
||||||
Controller *controller = loadAIController(new_kart);
|
Controller *controller = loadAIController(new_kart.get());
|
||||||
new_kart->setController(controller);
|
new_kart->setController(controller);
|
||||||
|
|
||||||
// Create a camera for the last kart (since this way more of the
|
// 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)
|
if (index == (int)race_manager->getNumberOfKarts()-1)
|
||||||
{
|
{
|
||||||
// The camera keeps track of all cameras and will free them
|
// 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;
|
return new_kart;
|
||||||
} // createKart
|
} // createKart
|
||||||
@ -197,7 +196,7 @@ void ProfileWorld::enterRaceOverState()
|
|||||||
// ---------- update rank ------
|
// ---------- update rank ------
|
||||||
if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
|
if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
|
||||||
continue;
|
continue;
|
||||||
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
|
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i].get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print framerate statistics
|
// Print framerate statistics
|
||||||
@ -229,9 +228,9 @@ void ProfileWorld::enterRaceOverState()
|
|||||||
|
|
||||||
std::set<std::string> all_groups;
|
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());
|
max_t = std::max(max_t, kart->getFinishTime());
|
||||||
min_t = std::min(min_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;
|
float av_time = 0.0f, energy = 0;
|
||||||
for ( unsigned int i = 0; i < (unsigned int)m_karts.size(); ++i)
|
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();
|
const std::string &name=kart->getController()->getControllerName();
|
||||||
if(name!=*it)
|
if(name!=*it)
|
||||||
continue;
|
continue;
|
||||||
|
@ -72,10 +72,10 @@ protected:
|
|||||||
* used by DemoWorld. */
|
* used by DemoWorld. */
|
||||||
static int m_num_laps;
|
static int m_num_laps;
|
||||||
|
|
||||||
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
|
virtual std::shared_ptr<AbstractKart> createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType type,
|
int global_player_id, RaceManager::KartType type,
|
||||||
PerPlayerDifficulty difficulty);
|
PerPlayerDifficulty difficulty);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ProfileWorld();
|
ProfileWorld();
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
#include "network/stk_host.hpp"
|
#include "network/stk_host.hpp"
|
||||||
#include "physics/physics.hpp"
|
#include "physics/physics.hpp"
|
||||||
#include "states_screens/race_gui_base.hpp"
|
#include "states_screens/race_gui_base.hpp"
|
||||||
|
#include "tracks/graph.hpp"
|
||||||
|
#include "tracks/quad.hpp"
|
||||||
#include "tracks/track.hpp"
|
#include "tracks/track.hpp"
|
||||||
#include "tracks/track_object_manager.hpp"
|
#include "tracks/track_object_manager.hpp"
|
||||||
#include "tracks/track_sector.hpp"
|
#include "tracks/track_sector.hpp"
|
||||||
@ -120,6 +122,7 @@ void SoccerWorld::init()
|
|||||||
Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");
|
Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");
|
||||||
|
|
||||||
m_bgd.init(m_ball->getPhysicalObject()->getRadius());
|
m_bgd.init(m_ball->getPhysicalObject()->getRadius());
|
||||||
|
m_ball_body->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
|
||||||
} // init
|
} // init
|
||||||
|
|
||||||
@ -211,10 +214,10 @@ const std::string& SoccerWorld::getIdent() const
|
|||||||
void SoccerWorld::update(int ticks)
|
void SoccerWorld::update(int ticks)
|
||||||
{
|
{
|
||||||
updateBallPosition(ticks);
|
updateBallPosition(ticks);
|
||||||
|
updateSectorForKarts();
|
||||||
if (Track::getCurrentTrack()->hasNavMesh() &&
|
if (Track::getCurrentTrack()->hasNavMesh() &&
|
||||||
!NetworkConfig::get()->isNetworking())
|
!NetworkConfig::get()->isNetworking())
|
||||||
{
|
{
|
||||||
updateSectorForKarts();
|
|
||||||
updateAIData();
|
updateAIData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +228,7 @@ void SoccerWorld::update(int ticks)
|
|||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < m_karts.size(); i++)
|
for (unsigned int i = 0; i < m_karts.size(); i++)
|
||||||
{
|
{
|
||||||
AbstractKart* kart = m_karts[i];
|
auto& kart = m_karts[i];
|
||||||
if (kart->isEliminated())
|
if (kart->isEliminated())
|
||||||
continue;
|
continue;
|
||||||
kart->getBody()->setLinearVelocity(Vec3(0.0f));
|
kart->getBody()->setLinearVelocity(Vec3(0.0f));
|
||||||
@ -332,7 +335,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
|
|||||||
}
|
}
|
||||||
for (unsigned i = 0; i < m_karts.size(); i++)
|
for (unsigned i = 0; i < m_karts.size(); i++)
|
||||||
{
|
{
|
||||||
AbstractKart* kart = m_karts[i];
|
auto& kart = m_karts[i];
|
||||||
if (kart->isEliminated())
|
if (kart->isEliminated())
|
||||||
continue;
|
continue;
|
||||||
kart->getBody()->setLinearVelocity(Vec3(0.0f));
|
kart->getBody()->setLinearVelocity(Vec3(0.0f));
|
||||||
@ -353,7 +356,7 @@ void SoccerWorld::handleResetBallFromServer(const NetworkString& ns)
|
|||||||
"%d when reset player", ticks_back_to_own_goal, ticks_now);
|
"%d when reset player", ticks_back_to_own_goal, ticks_now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RewindManager::get()->getRewindQueue().insertRewindInfo(new
|
RewindManager::get()->addRewindInfoEventFunction(new
|
||||||
RewindInfoEventFunction(ticks_back_to_own_goal,
|
RewindInfoEventFunction(ticks_back_to_own_goal,
|
||||||
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
|
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
|
||||||
|
|
||||||
@ -403,7 +406,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
|
|||||||
m_ball->setEnabled(false);
|
m_ball->setEnabled(false);
|
||||||
for (unsigned i = 0; i < m_karts.size(); i++)
|
for (unsigned i = 0; i < m_karts.size(); i++)
|
||||||
{
|
{
|
||||||
AbstractKart* kart = m_karts[i];
|
auto& kart = m_karts[i];
|
||||||
if (kart->isEliminated())
|
if (kart->isEliminated())
|
||||||
continue;
|
continue;
|
||||||
btTransform transform_now = kart->getBody()->getWorldTransform();
|
btTransform transform_now = kart->getBody()->getWorldTransform();
|
||||||
@ -413,7 +416,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
|
|||||||
kart->setTrans(transform_now);
|
kart->setTrans(transform_now);
|
||||||
m_goal_transforms[i] = transform_now;
|
m_goal_transforms[i] = transform_now;
|
||||||
}
|
}
|
||||||
RewindManager::get()->getRewindQueue().insertRewindInfo(new
|
RewindManager::get()->addRewindInfoEventFunction(new
|
||||||
RewindInfoEventFunction(ticks_back_to_own_goal,
|
RewindInfoEventFunction(ticks_back_to_own_goal,
|
||||||
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
|
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
|
||||||
|
|
||||||
@ -428,7 +431,7 @@ void SoccerWorld::resetKartsToSelfGoals()
|
|||||||
setPhase(WorldStatus::RACE_PHASE);
|
setPhase(WorldStatus::RACE_PHASE);
|
||||||
for (unsigned i = 0; i < m_karts.size(); i++)
|
for (unsigned i = 0; i < m_karts.size(); i++)
|
||||||
{
|
{
|
||||||
AbstractKart* kart = m_karts[i];
|
auto& kart = m_karts[i];
|
||||||
if (kart->isEliminated())
|
if (kart->isEliminated())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -436,7 +439,7 @@ void SoccerWorld::resetKartsToSelfGoals()
|
|||||||
kart->getBody()->setAngularVelocity(Vec3(0.0f));
|
kart->getBody()->setAngularVelocity(Vec3(0.0f));
|
||||||
unsigned index = m_kart_position_map.at(kart->getWorldKartId());
|
unsigned index = m_kart_position_map.at(kart->getWorldKartId());
|
||||||
btTransform t = Track::getCurrentTrack()->getStartTransform(index);
|
btTransform t = Track::getCurrentTrack()->getStartTransform(index);
|
||||||
moveKartTo(kart, t);
|
moveKartTo(kart.get(), t);
|
||||||
}
|
}
|
||||||
} // resetKartsToSelfGoals
|
} // resetKartsToSelfGoals
|
||||||
|
|
||||||
@ -529,10 +532,10 @@ bool SoccerWorld::getKartSoccerResult(unsigned int kart_id) const
|
|||||||
} // getKartSoccerResult
|
} // getKartSoccerResult
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
std::shared_ptr<AbstractKart> SoccerWorld::createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType kart_type,
|
int global_player_id, RaceManager::KartType kart_type,
|
||||||
PerPlayerDifficulty difficulty)
|
PerPlayerDifficulty difficulty)
|
||||||
{
|
{
|
||||||
int cur_red = getTeamNum(SOCCER_TEAM_RED);
|
int cur_red = getTeamNum(SOCCER_TEAM_RED);
|
||||||
int cur_blue = getTeamNum(SOCCER_TEAM_BLUE);
|
int cur_blue = getTeamNum(SOCCER_TEAM_BLUE);
|
||||||
@ -587,16 +590,19 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
|||||||
std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
|
std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
|
||||||
ri = (team == SOCCER_TEAM_BLUE ? std::make_shared<RenderInfo>(0.66f) :
|
ri = (team == SOCCER_TEAM_BLUE ? std::make_shared<RenderInfo>(0.66f) :
|
||||||
std::make_shared<RenderInfo>(1.0f));
|
std::make_shared<RenderInfo>(1.0f));
|
||||||
AbstractKart* new_kart;
|
|
||||||
|
std::shared_ptr<AbstractKart> new_kart;
|
||||||
if (RewindManager::get()->isEnabled())
|
if (RewindManager::get()->isEnabled())
|
||||||
{
|
{
|
||||||
new_kart = new KartRewinder(kart_ident, index, position, init_pos,
|
auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
|
||||||
difficulty, ri);
|
init_pos, difficulty, ri);
|
||||||
|
kr->rewinderAdd();
|
||||||
|
new_kart = kr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_kart = new Kart(kart_ident, index, position, init_pos, difficulty,
|
new_kart = std::make_shared<Kart>(kart_ident, index, position,
|
||||||
ri);
|
init_pos, difficulty, ri);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_kart->init(race_manager->getKartType(index));
|
new_kart->init(race_manager->getKartType(index));
|
||||||
@ -605,18 +611,18 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
|||||||
switch(kart_type)
|
switch(kart_type)
|
||||||
{
|
{
|
||||||
case RaceManager::KT_PLAYER:
|
case RaceManager::KT_PLAYER:
|
||||||
controller = new LocalPlayerController(new_kart, local_player_id,
|
controller = new LocalPlayerController(new_kart.get(), local_player_id,
|
||||||
difficulty);
|
difficulty);
|
||||||
m_num_players ++;
|
m_num_players ++;
|
||||||
break;
|
break;
|
||||||
case RaceManager::KT_NETWORK_PLAYER:
|
case RaceManager::KT_NETWORK_PLAYER:
|
||||||
controller = new NetworkPlayerController(new_kart);
|
controller = new NetworkPlayerController(new_kart.get());
|
||||||
if (!online_name.empty())
|
if (!online_name.empty())
|
||||||
new_kart->setOnScreenText(online_name.c_str());
|
new_kart->setOnScreenText(online_name.c_str());
|
||||||
m_num_players++;
|
m_num_players++;
|
||||||
break;
|
break;
|
||||||
case RaceManager::KT_AI:
|
case RaceManager::KT_AI:
|
||||||
controller = loadAIController(new_kart);
|
controller = loadAIController(new_kart.get());
|
||||||
break;
|
break;
|
||||||
case RaceManager::KT_GHOST:
|
case RaceManager::KT_GHOST:
|
||||||
break;
|
break;
|
||||||
@ -808,13 +814,26 @@ int SoccerWorld::getTeamNum(SoccerTeam team) const
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
unsigned int SoccerWorld::getRescuePositionIndex(AbstractKart *kart)
|
unsigned int SoccerWorld::getRescuePositionIndex(AbstractKart *kart)
|
||||||
{
|
{
|
||||||
std::map<int, unsigned int>::const_iterator n =
|
int last_valid_node =
|
||||||
m_kart_position_map.find(kart->getWorldKartId());
|
getTrackSector(kart->getWorldKartId())->getLastValidGraphNode();
|
||||||
|
if (last_valid_node >= 0)
|
||||||
assert (n != m_kart_position_map.end());
|
return last_valid_node;
|
||||||
return n->second;
|
Log::warn("SoccerWorld", "Missing last valid node for rescuing");
|
||||||
|
return 0;
|
||||||
} // getRescuePositionIndex
|
} // getRescuePositionIndex
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
btTransform SoccerWorld::getRescueTransform(unsigned int rescue_pos) const
|
||||||
|
{
|
||||||
|
const Vec3 &xyz = Graph::get()->getQuad(rescue_pos)->getCenter();
|
||||||
|
const Vec3 &normal = Graph::get()->getQuad(rescue_pos)->getNormal();
|
||||||
|
btTransform pos;
|
||||||
|
pos.setOrigin(xyz);
|
||||||
|
btQuaternion q1 = shortestArcQuat(Vec3(0.0f, 1.0f, 0.0f), normal);
|
||||||
|
pos.setRotation(q1);
|
||||||
|
return pos;
|
||||||
|
} // getRescueTransform
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void SoccerWorld::enterRaceOverState()
|
void SoccerWorld::enterRaceOverState()
|
||||||
{
|
{
|
||||||
|
@ -51,10 +51,10 @@ public:
|
|||||||
}; // ScorerData
|
}; // ScorerData
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
|
virtual std::shared_ptr<AbstractKart> createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType type,
|
int global_player_id, RaceManager::KartType type,
|
||||||
PerPlayerDifficulty difficulty) OVERRIDE;
|
PerPlayerDifficulty difficulty) OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class KartDistanceMap
|
class KartDistanceMap
|
||||||
@ -329,7 +329,8 @@ public:
|
|||||||
virtual void reset() OVERRIDE;
|
virtual void reset() OVERRIDE;
|
||||||
|
|
||||||
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
|
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
|
||||||
|
virtual btTransform getRescueTransform(unsigned int rescue_pos) const
|
||||||
|
OVERRIDE;
|
||||||
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
||||||
virtual void getKartsDisplayInfo(
|
virtual void getKartsDisplayInfo(
|
||||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE {}
|
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE {}
|
||||||
|
@ -103,7 +103,7 @@ void StandardRace::endRaceEarly()
|
|||||||
for (unsigned int i = 1; i <= kart_amount; i++)
|
for (unsigned int i = 1; i <= kart_amount; i++)
|
||||||
{
|
{
|
||||||
int kartid = m_position_index[i-1];
|
int kartid = m_position_index[i-1];
|
||||||
AbstractKart* kart = m_karts[kartid];
|
AbstractKart* kart = m_karts[kartid].get();
|
||||||
|
|
||||||
if (kart->hasFinishedRace())
|
if (kart->hasFinishedRace())
|
||||||
{
|
{
|
||||||
@ -140,7 +140,7 @@ void StandardRace::endRaceEarly()
|
|||||||
int kartid = active_players[i];
|
int kartid = active_players[i];
|
||||||
int position = getNumKarts() - (int) active_players.size() + 1 + i;
|
int position = getNumKarts() - (int) active_players.size() + 1 + i;
|
||||||
setKartPosition(kartid, position);
|
setKartPosition(kartid, position);
|
||||||
float punished_time = estimateFinishTimeForKart(m_karts[kartid])
|
float punished_time = estimateFinishTimeForKart(m_karts[kartid].get())
|
||||||
+ worse_finish_time - WorldStatus::getTime();
|
+ worse_finish_time - WorldStatus::getTime();
|
||||||
m_karts[kartid]->finishedRace(punished_time);
|
m_karts[kartid]->finishedRace(punished_time);
|
||||||
|
|
||||||
|
@ -722,18 +722,18 @@ void ThreeStrikesBattle::loadCustomModels()
|
|||||||
// Now add them
|
// Now add them
|
||||||
for (unsigned int i = 0; i < pos.size(); i++)
|
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,
|
(int)m_karts.size() + 1, pos[i], PLAYER_DIFFICULTY_NORMAL,
|
||||||
std::make_shared<RenderInfo>(1.0f));
|
std::make_shared<RenderInfo>(1.0f));
|
||||||
sta->init(RaceManager::KartType::KT_SPARE_TIRE);
|
sta->init(RaceManager::KartType::KT_SPARE_TIRE);
|
||||||
sta->setController(new SpareTireAI(sta));
|
sta->setController(new SpareTireAI(sta.get()));
|
||||||
|
|
||||||
m_karts.push_back(sta);
|
m_karts.push_back(sta);
|
||||||
race_manager->addSpareTireKart(sta_list[i]);
|
race_manager->addSpareTireKart(sta_list[i]);
|
||||||
|
|
||||||
// Copy STA pointer to m_spare_tire_karts array, allowing them
|
// Copy STA pointer to m_spare_tire_karts array, allowing them
|
||||||
// to respawn easily
|
// 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();
|
unsigned int sta_num = race_manager->getNumSpareTireKarts();
|
||||||
assert(m_spare_tire_karts.size() == sta_num);
|
assert(m_spare_tire_karts.size() == sta_num);
|
||||||
|
@ -120,7 +120,7 @@ World* World::m_world = NULL;
|
|||||||
*/
|
*/
|
||||||
World::World() : WorldStatus()
|
World::World() : WorldStatus()
|
||||||
{
|
{
|
||||||
|
RewindManager::setEnable(NetworkConfig::get()->isNetworking());
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
m_magic_number = 0xB01D6543;
|
m_magic_number = 0xB01D6543;
|
||||||
#endif
|
#endif
|
||||||
@ -212,10 +212,9 @@ void World::init()
|
|||||||
: race_manager->getKartIdent(i);
|
: race_manager->getKartIdent(i);
|
||||||
int local_player_id = race_manager->getKartLocalPlayerId(i);
|
int local_player_id = race_manager->getKartLocalPlayerId(i);
|
||||||
int global_player_id = race_manager->getKartGlobalPlayerId(i);
|
int global_player_id = race_manager->getKartGlobalPlayerId(i);
|
||||||
AbstractKart* newkart = createKart(kart_ident, i, local_player_id,
|
auto newkart = createKart(kart_ident, i, local_player_id,
|
||||||
global_player_id,
|
global_player_id, race_manager->getKartType(i),
|
||||||
race_manager->getKartType(i),
|
race_manager->getPlayerDifficulty(i));
|
||||||
race_manager->getPlayerDifficulty(i));
|
|
||||||
m_karts.push_back(newkart);
|
m_karts.push_back(newkart);
|
||||||
|
|
||||||
} // for i
|
} // for i
|
||||||
@ -301,6 +300,7 @@ void World::reset()
|
|||||||
SFXManager::get()->resumeAll();
|
SFXManager::get()->resumeAll();
|
||||||
|
|
||||||
projectile_manager->cleanup();
|
projectile_manager->cleanup();
|
||||||
|
RewindManager::get()->reset();
|
||||||
race_manager->reset();
|
race_manager->reset();
|
||||||
// Make sure to overwrite the data from the previous race.
|
// Make sure to overwrite the data from the previous race.
|
||||||
if(!history->replayHistory()) history->initRecording();
|
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
|
* \param global_player_id If the kart is a player kart this is the index of
|
||||||
* this player globally (i.e. including network players).
|
* this player globally (i.e. including network players).
|
||||||
*/
|
*/
|
||||||
AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
std::shared_ptr<AbstractKart> World::createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType kart_type,
|
int global_player_id, RaceManager::KartType kart_type,
|
||||||
PerPlayerDifficulty difficulty)
|
PerPlayerDifficulty difficulty)
|
||||||
{
|
{
|
||||||
unsigned int gk = 0;
|
unsigned int gk = 0;
|
||||||
if (race_manager->hasGhostKarts())
|
if (race_manager->hasGhostKarts())
|
||||||
@ -355,13 +355,19 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
|||||||
|
|
||||||
int position = index+1;
|
int position = index+1;
|
||||||
btTransform init_pos = getStartTransform(index - gk);
|
btTransform init_pos = getStartTransform(index - gk);
|
||||||
AbstractKart *new_kart;
|
std::shared_ptr<AbstractKart> new_kart;
|
||||||
if (RewindManager::get()->isEnabled())
|
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
|
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));
|
new_kart->init(race_manager->getKartType(index));
|
||||||
Controller *controller = NULL;
|
Controller *controller = NULL;
|
||||||
@ -369,7 +375,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
|||||||
{
|
{
|
||||||
case RaceManager::KT_PLAYER:
|
case RaceManager::KT_PLAYER:
|
||||||
{
|
{
|
||||||
controller = new LocalPlayerController(new_kart, local_player_id,
|
controller = new LocalPlayerController(new_kart.get(), local_player_id,
|
||||||
difficulty);
|
difficulty);
|
||||||
const PlayerProfile* p = StateManager::get()
|
const PlayerProfile* p = StateManager::get()
|
||||||
->getActivePlayer(local_player_id)->getConstProfile();
|
->getActivePlayer(local_player_id)->getConstProfile();
|
||||||
@ -383,7 +389,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
|||||||
}
|
}
|
||||||
case RaceManager::KT_NETWORK_PLAYER:
|
case RaceManager::KT_NETWORK_PLAYER:
|
||||||
{
|
{
|
||||||
controller = new NetworkPlayerController(new_kart);
|
controller = new NetworkPlayerController(new_kart.get());
|
||||||
if (!online_name.empty())
|
if (!online_name.empty())
|
||||||
new_kart->setOnScreenText(online_name.c_str());
|
new_kart->setOnScreenText(online_name.c_str());
|
||||||
m_num_players++;
|
m_num_players++;
|
||||||
@ -391,7 +397,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
|||||||
}
|
}
|
||||||
case RaceManager::KT_AI:
|
case RaceManager::KT_AI:
|
||||||
{
|
{
|
||||||
controller = loadAIController(new_kart);
|
controller = loadAIController(new_kart.get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RaceManager::KT_GHOST:
|
case RaceManager::KT_GHOST:
|
||||||
@ -417,7 +423,7 @@ const btTransform &World::getStartTransform(int index)
|
|||||||
/** Creates an AI controller for the kart.
|
/** Creates an AI controller for the kart.
|
||||||
* \param kart The kart to be controlled by an AI.
|
* \param kart The kart to be controlled by an AI.
|
||||||
*/
|
*/
|
||||||
Controller* World::loadAIController(AbstractKart *kart)
|
Controller* World::loadAIController(AbstractKart* kart)
|
||||||
{
|
{
|
||||||
Controller *controller;
|
Controller *controller;
|
||||||
int turn=0;
|
int turn=0;
|
||||||
@ -485,13 +491,7 @@ World::~World()
|
|||||||
|
|
||||||
Weather::kill();
|
Weather::kill();
|
||||||
|
|
||||||
for ( unsigned int i = 0 ; i < m_karts.size() ; i++ )
|
m_karts.clear();
|
||||||
{
|
|
||||||
// Let ReplayPlay destroy the ghost karts
|
|
||||||
if (m_karts[i]->isGhostKart()) continue;
|
|
||||||
delete m_karts[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(race_manager->hasGhostKarts() || race_manager->isRecordingRace())
|
if(race_manager->hasGhostKarts() || race_manager->isRecordingRace())
|
||||||
{
|
{
|
||||||
// Destroy the old replay object, which also stored the ghost
|
// Destroy the old replay object, which also stored the ghost
|
||||||
@ -502,7 +502,6 @@ World::~World()
|
|||||||
ReplayPlay::destroy();
|
ReplayPlay::destroy();
|
||||||
ReplayPlay::create();
|
ReplayPlay::create();
|
||||||
}
|
}
|
||||||
m_karts.clear();
|
|
||||||
if(race_manager->isRecordingRace())
|
if(race_manager->isRecordingRace())
|
||||||
ReplayRecorder::get()->reset();
|
ReplayRecorder::get()->reset();
|
||||||
race_manager->setRaceGhostKarts(false);
|
race_manager->setRaceGhostKarts(false);
|
||||||
@ -567,7 +566,8 @@ void World::terminateRace()
|
|||||||
{
|
{
|
||||||
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
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
|
} // i<kart_amount
|
||||||
@ -699,7 +699,7 @@ void World::resetAllKarts()
|
|||||||
btTransform t = getRescueTransform(rescue_pos);
|
btTransform t = getRescueTransform(rescue_pos);
|
||||||
// This will print out warnings if there is no terrain under
|
// This will print out warnings if there is no terrain under
|
||||||
// the kart, or the kart is being dropped on a reset texture
|
// 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
|
} // rescue_pos<getNumberOfRescuePositions
|
||||||
|
|
||||||
@ -725,7 +725,7 @@ void World::resetAllKarts()
|
|||||||
Vec3 up_offset = (*i)->getNormal() * (0.5f * ((*i)->getKartHeight()));
|
Vec3 up_offset = (*i)->getNormal() * (0.5f * ((*i)->getKartHeight()));
|
||||||
(*i)->setXYZ(xyz+up_offset);
|
(*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)
|
if (!kart_over_ground)
|
||||||
{
|
{
|
||||||
@ -1055,14 +1055,16 @@ void World::update(int ticks)
|
|||||||
m_karts[i]->update(ticks);
|
m_karts[i]->update(ticks);
|
||||||
}
|
}
|
||||||
PROFILER_POP_CPU_MARKER();
|
PROFILER_POP_CPU_MARKER();
|
||||||
|
|
||||||
if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(ticks);
|
if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(ticks);
|
||||||
Physics::getInstance()->update(ticks);
|
|
||||||
|
|
||||||
PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
|
PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
|
||||||
projectile_manager->update(ticks);
|
projectile_manager->update(ticks);
|
||||||
PROFILER_POP_CPU_MARKER();
|
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();
|
PROFILER_POP_CPU_MARKER();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -1165,7 +1167,7 @@ void World::updateHighscores(int* best_highscore_rank)
|
|||||||
if (!m_karts[index[pos]]->hasFinishedRace()) continue;
|
if (!m_karts[index[pos]]->hasFinishedRace()) continue;
|
||||||
|
|
||||||
assert(index[pos] < m_karts.size());
|
assert(index[pos] < m_karts.size());
|
||||||
Kart *k = (Kart*)m_karts[index[pos]];
|
Kart *k = (Kart*)m_karts[index[pos]].get();
|
||||||
|
|
||||||
Highscores* highscores = getHighscores();
|
Highscores* highscores = getHighscores();
|
||||||
|
|
||||||
@ -1197,14 +1199,17 @@ void World::updateHighscores(int* best_highscore_rank)
|
|||||||
*/
|
*/
|
||||||
AbstractKart *World::getPlayerKart(unsigned int n) const
|
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++)
|
for(unsigned int i = 0; i < m_karts.size(); i++)
|
||||||
if(m_karts[i]->getController()->isPlayerController())
|
{
|
||||||
|
if (m_karts[i]->getController()->isPlayerController())
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
if(count==n) return m_karts[i];
|
if (count == n)
|
||||||
|
return m_karts[i].get();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
} // getPlayerKart
|
} // getPlayerKart
|
||||||
|
|
||||||
@ -1225,7 +1230,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
|
|||||||
void World::eliminateKart(int kart_id, bool notify_of_elimination)
|
void World::eliminateKart(int kart_id, bool notify_of_elimination)
|
||||||
{
|
{
|
||||||
assert(kart_id < (int)m_karts.size());
|
assert(kart_id < (int)m_karts.size());
|
||||||
AbstractKart *kart = m_karts[kart_id];
|
AbstractKart *kart = m_karts[kart_id].get();
|
||||||
if (kart->isGhostKart()) return;
|
if (kart->isGhostKart()) return;
|
||||||
|
|
||||||
// Display a message about the eliminated kart in the race guia
|
// Display a message about the eliminated kart in the race guia
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
* battle, etc.)
|
* battle, etc.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ public:
|
|||||||
class World : public WorldStatus
|
class World : public WorldStatus
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::vector<AbstractKart*> KartList;
|
typedef std::vector<std::shared_ptr<AbstractKart> > KartList;
|
||||||
private:
|
private:
|
||||||
/** A pointer to the global world object for a race. */
|
/** A pointer to the global world object for a race. */
|
||||||
static World *m_world;
|
static World *m_world;
|
||||||
@ -117,10 +118,10 @@ protected:
|
|||||||
Controller*
|
Controller*
|
||||||
loadAIController (AbstractKart *kart);
|
loadAIController (AbstractKart *kart);
|
||||||
|
|
||||||
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
|
virtual std::shared_ptr<AbstractKart> createKart
|
||||||
int local_player_id, int global_player_id,
|
(const std::string &kart_ident, int index, int local_player_id,
|
||||||
RaceManager::KartType type,
|
int global_player_id, RaceManager::KartType type,
|
||||||
PerPlayerDifficulty difficulty);
|
PerPlayerDifficulty difficulty);
|
||||||
|
|
||||||
/** Pointer to the race GUI. The race GUI is handled by world. */
|
/** Pointer to the race GUI. The race GUI is handled by world. */
|
||||||
RaceGUIBase *m_race_gui;
|
RaceGUIBase *m_race_gui;
|
||||||
@ -293,7 +294,7 @@ public:
|
|||||||
/** Returns the kart with a given world id. */
|
/** Returns the kart with a given world id. */
|
||||||
AbstractKart *getKart(int kartId) const {
|
AbstractKart *getKart(int kartId) const {
|
||||||
assert(kartId >= 0 && kartId < int(m_karts.size()));
|
assert(kartId >= 0 && kartId < int(m_karts.size()));
|
||||||
return m_karts[kartId]; }
|
return m_karts[kartId].get(); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns all karts. */
|
/** Returns all karts. */
|
||||||
const KartList & getKarts() const { return m_karts; }
|
const KartList & getKarts() const { return m_karts; }
|
||||||
|
@ -112,9 +112,9 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
bool m_play_track_intro_sound;
|
bool m_play_track_intro_sound;
|
||||||
bool m_play_ready_set_go_sounds;
|
bool m_play_ready_set_go_sounds;
|
||||||
|
Phase m_phase;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Phase m_phase;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remember previous phase e.g. on pause
|
* Remember previous phase e.g. on pause
|
||||||
|
@ -82,7 +82,7 @@ AbstractKart* WorldWithRank::getKartAtPosition(unsigned int p) const
|
|||||||
if(p<1 || p>m_position_index.size())
|
if(p<1 || p>m_position_index.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return m_karts[m_position_index[p-1]];
|
return m_karts[m_position_index[p-1]].get();
|
||||||
} // getKartAtPosition
|
} // getKartAtPosition
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -74,6 +74,10 @@ protected:
|
|||||||
*/
|
*/
|
||||||
std::string getString(int len) const
|
std::string getString(int len) const
|
||||||
{
|
{
|
||||||
|
if (m_current_offset > (int)m_buffer.size() ||
|
||||||
|
m_current_offset + len > (int)m_buffer.size())
|
||||||
|
throw std::out_of_range("getString out of range.");
|
||||||
|
|
||||||
std::string a(m_buffer.begin() + (m_current_offset ),
|
std::string a(m_buffer.begin() + (m_current_offset ),
|
||||||
m_buffer.begin() + (m_current_offset + len));
|
m_buffer.begin() + (m_current_offset + len));
|
||||||
m_current_offset += len;
|
m_current_offset += len;
|
||||||
@ -101,7 +105,7 @@ protected:
|
|||||||
{
|
{
|
||||||
result <<= 8; // offset one byte
|
result <<= 8; // offset one byte
|
||||||
// add the data to result
|
// add the data to result
|
||||||
result += m_buffer[offset - a];
|
result += m_buffer.at(offset - a);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} // get(int pos)
|
} // get(int pos)
|
||||||
@ -110,7 +114,7 @@ protected:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
T get() const
|
T get() const
|
||||||
{
|
{
|
||||||
return m_buffer[m_current_offset++];
|
return m_buffer.at(m_current_offset++);
|
||||||
} // get
|
} // get
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -195,7 +199,8 @@ public:
|
|||||||
{
|
{
|
||||||
return (char*)(m_buffer.data()+m_current_offset);
|
return (char*)(m_buffer.data()+m_current_offset);
|
||||||
} // getCurrentData
|
} // getCurrentData
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
int getCurrentOffset() const { return m_current_offset; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the remaining length of the network string. */
|
/** Returns the remaining length of the network string. */
|
||||||
unsigned int size() const { return (int)m_buffer.size()-m_current_offset; }
|
unsigned int size() const { return (int)m_buffer.size()-m_current_offset; }
|
||||||
@ -424,8 +429,7 @@ public:
|
|||||||
/** Returns the protocol type of this message. */
|
/** Returns the protocol type of this message. */
|
||||||
ProtocolType getProtocolType() const
|
ProtocolType getProtocolType() const
|
||||||
{
|
{
|
||||||
assert(!m_buffer.empty());
|
return (ProtocolType)(m_buffer.at(0) & ~PROTOCOL_SYNCHRONOUS);
|
||||||
return (ProtocolType)(m_buffer[0] & ~PROTOCOL_SYNCHRONOUS);
|
|
||||||
} // getProtocolType
|
} // getProtocolType
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -378,14 +378,15 @@ bool ProtocolManager::sendEvent(Event* event)
|
|||||||
bool can_be_deleted = false;
|
bool can_be_deleted = false;
|
||||||
if (event->getType() == EVENT_TYPE_MESSAGE)
|
if (event->getType() == EVENT_TYPE_MESSAGE)
|
||||||
{
|
{
|
||||||
OneProtocolType &opt = m_all_protocols[event->data().getProtocolType()];
|
OneProtocolType &opt =
|
||||||
|
m_all_protocols.at(event->data().getProtocolType());
|
||||||
can_be_deleted = opt.notifyEvent(event);
|
can_be_deleted = opt.notifyEvent(event);
|
||||||
}
|
}
|
||||||
else // connect or disconnect event --> test all protocols
|
else // connect or disconnect event --> test all protocols
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < m_all_protocols.size(); i++)
|
for (unsigned int i = 0; i < m_all_protocols.size(); i++)
|
||||||
{
|
{
|
||||||
can_be_deleted |= m_all_protocols[i].notifyEvent(event);
|
can_be_deleted |= m_all_protocols.at(i).notifyEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return can_be_deleted || StkTime::getTimeSinceEpoch() - event->getArrivalTime()
|
return can_be_deleted || StkTime::getTimeSinceEpoch() - event->getArrivalTime()
|
||||||
@ -432,7 +433,16 @@ void ProtocolManager::update(int ticks)
|
|||||||
while (i != m_sync_events_to_process.getData().end())
|
while (i != m_sync_events_to_process.getData().end())
|
||||||
{
|
{
|
||||||
m_sync_events_to_process.unlock();
|
m_sync_events_to_process.unlock();
|
||||||
bool can_be_deleted = sendEvent(*i);
|
bool can_be_deleted = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
can_be_deleted = sendEvent(*i);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log::error("ProtocolManager", "Synchronous event error: %s",
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
m_sync_events_to_process.lock();
|
m_sync_events_to_process.lock();
|
||||||
if (can_be_deleted)
|
if (can_be_deleted)
|
||||||
{
|
{
|
||||||
@ -478,7 +488,16 @@ void ProtocolManager::asynchronousUpdate()
|
|||||||
m_async_events_to_process.unlock();
|
m_async_events_to_process.unlock();
|
||||||
|
|
||||||
m_all_protocols[(*i)->getType()].lock();
|
m_all_protocols[(*i)->getType()].lock();
|
||||||
bool result = sendEvent(*i);
|
bool result = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = sendEvent(*i);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log::error("ProtocolManager", "Asynchronous event error: %s",
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
m_all_protocols[(*i)->getType()].unlock();
|
m_all_protocols[(*i)->getType()].unlock();
|
||||||
|
|
||||||
m_async_events_to_process.lock();
|
m_async_events_to_process.lock();
|
||||||
|
@ -166,6 +166,7 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
|
|||||||
case LE_CONNECTION_REFUSED: connectionRefused(event); break;
|
case LE_CONNECTION_REFUSED: connectionRefused(event); break;
|
||||||
case LE_VOTE: displayPlayerVote(event); break;
|
case LE_VOTE: displayPlayerVote(event); break;
|
||||||
case LE_SERVER_OWNERSHIP: becomingServerOwner(); break;
|
case LE_SERVER_OWNERSHIP: becomingServerOwner(); break;
|
||||||
|
case LE_BAD_TEAM: handleBadTeam(); break;
|
||||||
default: break;
|
default: break;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
@ -610,10 +611,21 @@ void ClientLobby::updatePlayerList(Event* event)
|
|||||||
NetworkingLobby::getInstance()->updatePlayers(players);
|
NetworkingLobby::getInstance()->updatePlayers(players);
|
||||||
} // updatePlayerList
|
} // updatePlayerList
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ClientLobby::handleBadTeam()
|
||||||
|
{
|
||||||
|
SFXManager::get()->quickSound("anvil");
|
||||||
|
//I18N: Display when all players are in red or blue team, which the race
|
||||||
|
//will not be allowed to start
|
||||||
|
core::stringw msg = _("All players joined red or blue team.");
|
||||||
|
MessageQueue::add(MessageQueue::MT_ERROR, msg);
|
||||||
|
} // handleBadTeam
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ClientLobby::becomingServerOwner()
|
void ClientLobby::becomingServerOwner()
|
||||||
{
|
{
|
||||||
SFXManager::get()->quickSound("wee");
|
SFXManager::get()->quickSound("wee");
|
||||||
|
//I18N: Display when a player is allow to control the server
|
||||||
core::stringw msg = _("You are now the owner of server.");
|
core::stringw msg = _("You are now the owner of server.");
|
||||||
MessageQueue::add(MessageQueue::MT_GENERIC, msg);
|
MessageQueue::add(MessageQueue::MT_GENERIC, msg);
|
||||||
STKHost::get()->setAuthorisedToControl(true);
|
STKHost::get()->setAuthorisedToControl(true);
|
||||||
|
@ -45,6 +45,7 @@ private:
|
|||||||
void updatePlayerList(Event* event);
|
void updatePlayerList(Event* event);
|
||||||
void handleChat(Event* event);
|
void handleChat(Event* event);
|
||||||
void handleServerInfo(Event* event);
|
void handleServerInfo(Event* event);
|
||||||
|
void handleBadTeam();
|
||||||
void becomingServerOwner();
|
void becomingServerOwner();
|
||||||
|
|
||||||
void clearPlayers();
|
void clearPlayers();
|
||||||
|
@ -54,14 +54,14 @@ bool GameEventsProtocol::notifyEvent(Event* event)
|
|||||||
case GE_RESET_BALL:
|
case GE_RESET_BALL:
|
||||||
{
|
{
|
||||||
if (!sw)
|
if (!sw)
|
||||||
throw("No soccer world");
|
throw std::invalid_argument("No soccer world");
|
||||||
sw->handleResetBallFromServer(data);
|
sw->handleResetBallFromServer(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GE_PLAYER_GOAL:
|
case GE_PLAYER_GOAL:
|
||||||
{
|
{
|
||||||
if (!sw)
|
if (!sw)
|
||||||
throw("No soccer world");
|
throw std::invalid_argument("No soccer world");
|
||||||
sw->handlePlayerGoalFromServer(data);
|
sw->handlePlayerGoalFromServer(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "network/protocols/game_protocol.hpp"
|
#include "network/protocols/game_protocol.hpp"
|
||||||
#include "network/protocols/game_events_protocol.hpp"
|
#include "network/protocols/game_events_protocol.hpp"
|
||||||
#include "network/race_event_manager.hpp"
|
#include "network/race_event_manager.hpp"
|
||||||
#include "network/rewind_manager.hpp"
|
|
||||||
#include "race/race_manager.hpp"
|
#include "race/race_manager.hpp"
|
||||||
#include "states_screens/state_manager.hpp"
|
#include "states_screens/state_manager.hpp"
|
||||||
|
|
||||||
@ -59,8 +58,6 @@ LobbyProtocol::~LobbyProtocol()
|
|||||||
void LobbyProtocol::loadWorld()
|
void LobbyProtocol::loadWorld()
|
||||||
{
|
{
|
||||||
Log::info("LobbyProtocol", "Ready !");
|
Log::info("LobbyProtocol", "Ready !");
|
||||||
RewindManager::setEnable(true);
|
|
||||||
|
|
||||||
// Race startup sequence
|
// Race startup sequence
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// This creates the network world.
|
// This creates the network world.
|
||||||
|
@ -60,7 +60,8 @@ public:
|
|||||||
LE_CHAT,
|
LE_CHAT,
|
||||||
LE_SERVER_OWNERSHIP,
|
LE_SERVER_OWNERSHIP,
|
||||||
LE_KICK_HOST,
|
LE_KICK_HOST,
|
||||||
LE_CHANGE_TEAM
|
LE_CHANGE_TEAM,
|
||||||
|
LE_BAD_TEAM
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RejectReason : uint8_t
|
enum RejectReason : uint8_t
|
||||||
|
@ -381,7 +381,7 @@ void ServerLobby::asynchronousUpdate()
|
|||||||
if (NetworkConfig::get()->isOwnerLess())
|
if (NetworkConfig::get()->isOwnerLess())
|
||||||
{
|
{
|
||||||
auto players = m_game_setup->getPlayers();
|
auto players = m_game_setup->getPlayers();
|
||||||
if (((float)players.size() >
|
if (((float)players.size() >=
|
||||||
(float)NetworkConfig::get()->getMaxPlayers() *
|
(float)NetworkConfig::get()->getMaxPlayers() *
|
||||||
UserConfigParams::m_start_game_threshold ||
|
UserConfigParams::m_start_game_threshold ||
|
||||||
m_game_setup->isGrandPrixStarted()) &&
|
m_game_setup->isGrandPrixStarted()) &&
|
||||||
@ -761,6 +761,31 @@ void ServerLobby::startSelection(const Event *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NetworkConfig::get()->hasTeamChoosing())
|
||||||
|
{
|
||||||
|
int red_count = 0;
|
||||||
|
int blue_count = 0;
|
||||||
|
auto players = m_game_setup->getConnectedPlayers();
|
||||||
|
for (auto& player : players)
|
||||||
|
{
|
||||||
|
if (player->getTeam() == SOCCER_TEAM_RED)
|
||||||
|
red_count++;
|
||||||
|
else if (player->getTeam() == SOCCER_TEAM_BLUE)
|
||||||
|
blue_count++;
|
||||||
|
if (red_count != 0 && blue_count != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((red_count == 0 || blue_count == 0) && players.size() != 1)
|
||||||
|
{
|
||||||
|
Log::warn("ServerLobby", "Bad team choosing.");
|
||||||
|
NetworkString* bt = getNetworkString();
|
||||||
|
bt->addUInt8(LE_BAD_TEAM);
|
||||||
|
sendMessageToPeers(bt, true/*reliable*/);
|
||||||
|
delete bt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
|
ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
|
||||||
if (NetworkConfig::get()->isWAN())
|
if (NetworkConfig::get()->isWAN())
|
||||||
{
|
{
|
||||||
@ -1857,16 +1882,25 @@ void ServerLobby::handlePendingConnection()
|
|||||||
auto key = m_keys.find(online_id);
|
auto key = m_keys.find(online_id);
|
||||||
if (key != m_keys.end() && key->second.m_tried == false)
|
if (key != m_keys.end() && key->second.m_tried == false)
|
||||||
{
|
{
|
||||||
if (decryptConnectionRequest(peer, it->second.second,
|
try
|
||||||
key->second.m_aes_key, key->second.m_aes_iv, online_id,
|
|
||||||
key->second.m_name))
|
|
||||||
{
|
{
|
||||||
it = m_pending_connection.erase(it);
|
if (decryptConnectionRequest(peer, it->second.second,
|
||||||
m_keys.erase(online_id);
|
key->second.m_aes_key, key->second.m_aes_iv, online_id,
|
||||||
continue;
|
key->second.m_name))
|
||||||
|
{
|
||||||
|
it = m_pending_connection.erase(it);
|
||||||
|
m_keys.erase(online_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
key->second.m_tried = true;
|
||||||
}
|
}
|
||||||
else
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log::error("ServerLobby",
|
||||||
|
"handlePendingConnection error: %s", e.what());
|
||||||
key->second.m_tried = true;
|
key->second.m_tried = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#include "network/rewind_info.hpp"
|
#include "network/rewind_info.hpp"
|
||||||
|
|
||||||
#include "network/network_config.hpp"
|
#include "network/network_config.hpp"
|
||||||
|
#include "network/rewinder.hpp"
|
||||||
#include "network/rewind_manager.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
|
/** Constructor for a state: it only takes the size, and allocates a buffer
|
||||||
* for all state info.
|
* for all state info.
|
||||||
@ -63,16 +64,44 @@ void RewindInfoState::restore()
|
|||||||
m_buffer->reset();
|
m_buffer->reset();
|
||||||
for (const std::string& name : m_rewinder_using)
|
for (const std::string& name : m_rewinder_using)
|
||||||
{
|
{
|
||||||
uint16_t count = m_buffer->getUInt16();
|
const uint16_t data_size = m_buffer->getUInt16();
|
||||||
Rewinder* r = RewindManager::get()->getRewinder(name);
|
const unsigned current_offset_now = m_buffer->getCurrentOffset();
|
||||||
if (r == NULL)
|
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",
|
Log::error("RewindInfoState", "Missing rewinder %s",
|
||||||
name.c_str());
|
name.c_str());
|
||||||
m_buffer->skip(count);
|
m_buffer->skip(data_size);
|
||||||
continue;
|
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
|
} // for all rewinder
|
||||||
} // restore
|
} // restore
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include "network/event_rewinder.hpp"
|
#include "network/event_rewinder.hpp"
|
||||||
#include "network/network_string.hpp"
|
#include "network/network_string.hpp"
|
||||||
#include "network/rewinder.hpp"
|
|
||||||
#include "utils/cpp2011.hpp"
|
#include "utils/cpp2011.hpp"
|
||||||
#include "utils/leak_check.hpp"
|
#include "utils/leak_check.hpp"
|
||||||
#include "utils/ptr_vector.hpp"
|
#include "utils/ptr_vector.hpp"
|
||||||
@ -173,14 +172,18 @@ public:
|
|||||||
class RewindInfoEventFunction : public RewindInfo
|
class RewindInfoEventFunction : public RewindInfo
|
||||||
{
|
{
|
||||||
private:
|
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:
|
public:
|
||||||
RewindInfoEventFunction(int ticks,
|
RewindInfoEventFunction(int ticks,
|
||||||
std::function<void()> undo_function = [](){},
|
std::function<void()> undo_function = [](){},
|
||||||
std::function<void()> replay_function = [](){},
|
std::function<void()> replay_function = [](){},
|
||||||
bool is_confirmed = true)
|
std::function<void()> destroy_function = [](){})
|
||||||
: RewindInfo(ticks, is_confirmed),
|
: RewindInfo(ticks, true/*is_confirmed*/),
|
||||||
m_undo_function(undo_function), m_replay_function(replay_function) {}
|
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. */
|
/** An event is never 'restored', it is only rewound. */
|
||||||
void restore() {}
|
void restore() {}
|
||||||
|
@ -82,18 +82,7 @@ void RewindManager::reset()
|
|||||||
|
|
||||||
if (!m_enable_rewind_manager) return;
|
if (!m_enable_rewind_manager) return;
|
||||||
|
|
||||||
for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
|
clearExpiredRewinder();
|
||||||
{
|
|
||||||
if (!it->second->canBeDestroyed())
|
|
||||||
{
|
|
||||||
it++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Rewinder* rewinder = it->second;
|
|
||||||
it = m_all_rewinder.erase(it);
|
|
||||||
delete rewinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rewind_queue.reset();
|
m_rewind_queue.reset();
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
@ -166,7 +155,9 @@ void RewindManager::saveState()
|
|||||||
{
|
{
|
||||||
// TODO: check if it's worth passing in a sufficiently large buffer from
|
// TODO: check if it's worth passing in a sufficiently large buffer from
|
||||||
// GameProtocol - this would save the copy operation.
|
// 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)
|
if (buffer != NULL)
|
||||||
{
|
{
|
||||||
m_overall_state_size += buffer->size();
|
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)
|
if (ticks - m_last_saved_state < m_state_frequency)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Save state
|
// Save state, remove expired rewinder first
|
||||||
|
clearExpiredRewinder();
|
||||||
if (NetworkConfig::get()->isClient())
|
if (NetworkConfig::get()->isClient())
|
||||||
{
|
{
|
||||||
auto& ret = m_local_state[ticks];
|
auto& ret = m_local_state[ticks];
|
||||||
for (auto& p : m_all_rewinder)
|
for (auto& p : m_all_rewinder)
|
||||||
ret.push_back(p.second->getLocalStateRestoreFunction());
|
{
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
ret.push_back(r->getLocalStateRestoreFunction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -222,6 +217,10 @@ void RewindManager::update(int ticks_not_used)
|
|||||||
*/
|
*/
|
||||||
void RewindManager::playEventsTill(int world_ticks, int *ticks)
|
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;
|
bool needs_rewind;
|
||||||
int rewind_ticks;
|
int rewind_ticks;
|
||||||
|
|
||||||
@ -255,6 +254,20 @@ void RewindManager::playEventsTill(int world_ticks, int *ticks)
|
|||||||
m_is_rewinding = false;
|
m_is_rewinding = false;
|
||||||
} // playEventsTill
|
} // 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
|
/** Rewinds to the specified time, then goes forward till the current
|
||||||
* World::getTime() is reached again: it will replay everything before
|
* World::getTime() is reached again: it will replay everything before
|
||||||
@ -274,7 +287,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
|
|||||||
// can be computed between the transforms before and after
|
// can be computed between the transforms before and after
|
||||||
// the rewind.
|
// the rewind.
|
||||||
for (auto& p : m_all_rewinder)
|
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
|
// 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
|
// Now compute the errors which need to be visually smoothed
|
||||||
for (auto& p : m_all_rewinder)
|
for (auto& p : m_all_rewinder)
|
||||||
p.second->computeError();
|
{
|
||||||
|
if (auto r = p.second.lock())
|
||||||
|
r->computeError();
|
||||||
|
}
|
||||||
|
|
||||||
history->setReplayHistory(is_history);
|
history->setReplayHistory(is_history);
|
||||||
m_is_rewinding = false;
|
m_is_rewinding = false;
|
||||||
|
mergeRewindInfoEventFunction();
|
||||||
} // rewindTo
|
} // rewindTo
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -360,3 +380,11 @@ bool RewindManager::useLocalEvent() const
|
|||||||
return NetworkConfig::get()->isNetworking() &&
|
return NetworkConfig::get()->isNetworking() &&
|
||||||
NetworkConfig::get()->isClient() && !m_is_rewinding;
|
NetworkConfig::get()->isClient() && !m_is_rewinding;
|
||||||
} // useLocalEvent
|
} // useLocalEvent
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void RewindManager::mergeRewindInfoEventFunction()
|
||||||
|
{
|
||||||
|
for (RewindInfoEventFunction* rief : m_pending_rief)
|
||||||
|
m_rewind_queue.insertRewindInfo(rief);
|
||||||
|
m_pending_rief.clear();
|
||||||
|
} // mergeRewindInfoEventFunction
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#ifndef HEADER_REWIND_MANAGER_HPP
|
#ifndef HEADER_REWIND_MANAGER_HPP
|
||||||
#define HEADER_REWIND_MANAGER_HPP
|
#define HEADER_REWIND_MANAGER_HPP
|
||||||
|
|
||||||
#include "network/rewinder.hpp"
|
|
||||||
#include "network/rewind_queue.hpp"
|
#include "network/rewind_queue.hpp"
|
||||||
#include "utils/ptr_vector.hpp"
|
#include "utils/ptr_vector.hpp"
|
||||||
#include "utils/synchronised.hpp"
|
#include "utils/synchronised.hpp"
|
||||||
@ -27,10 +26,15 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class Rewinder;
|
||||||
class RewindInfo;
|
class RewindInfo;
|
||||||
|
class RewindInfoEventFunction;
|
||||||
class EventRewinder;
|
class EventRewinder;
|
||||||
|
|
||||||
/** \ingroup network
|
/** \ingroup network
|
||||||
@ -93,7 +97,7 @@ private:
|
|||||||
std::map<int, std::vector<std::function<void()> > > m_local_state;
|
std::map<int, std::vector<std::function<void()> > > m_local_state;
|
||||||
|
|
||||||
/** A list of all objects that can be rewound. */
|
/** 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. */
|
/** The queue that stores all rewind infos. */
|
||||||
RewindQueue m_rewind_queue;
|
RewindQueue m_rewind_queue;
|
||||||
@ -115,8 +119,25 @@ private:
|
|||||||
* rewinds. */
|
* rewinds. */
|
||||||
std::atomic<int> m_not_rewound_ticks;
|
std::atomic<int> m_not_rewound_ticks;
|
||||||
|
|
||||||
|
std::vector<RewindInfoEventFunction*> m_pending_rief;
|
||||||
|
|
||||||
RewindManager();
|
RewindManager();
|
||||||
~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:
|
public:
|
||||||
// First static functions to manage rewinding.
|
// First static functions to manage rewinding.
|
||||||
@ -151,27 +172,18 @@ public:
|
|||||||
void addNetworkState(BareNetworkString *buffer, int ticks);
|
void addNetworkState(BareNetworkString *buffer, int ticks);
|
||||||
void saveState();
|
void saveState();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
Rewinder* getRewinder(const std::string& name)
|
std::shared_ptr<Rewinder> getRewinder(const std::string& name)
|
||||||
{
|
{
|
||||||
auto it = m_all_rewinder.find(name);
|
auto it = m_all_rewinder.find(name);
|
||||||
if (it == m_all_rewinder.end())
|
if (it != m_all_rewinder.end())
|
||||||
return NULL;
|
{
|
||||||
return it->second;
|
if (auto r = it->second.lock())
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Adds a Rewinder to the list of all rewinders.
|
bool addRewinder(std::shared_ptr<Rewinder> rewinder);
|
||||||
* \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
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns true if currently a rewind is happening. */
|
/** Returns true if currently a rewind is happening. */
|
||||||
bool isRewinding() const { return m_is_rewinding; }
|
bool isRewinding() const { return m_is_rewinding; }
|
||||||
@ -182,8 +194,6 @@ public:
|
|||||||
return m_not_rewound_ticks.load(std::memory_order_relaxed);
|
return m_not_rewound_ticks.load(std::memory_order_relaxed);
|
||||||
} // getNotRewoundWorldTicks
|
} // getNotRewoundWorldTicks
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
RewindQueue& getRewindQueue() { return m_rewind_queue; }
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
/** Returns the time of the latest confirmed state. */
|
/** Returns the time of the latest confirmed state. */
|
||||||
int getLatestConfirmedState() const
|
int getLatestConfirmedState() const
|
||||||
{
|
{
|
||||||
@ -200,6 +210,9 @@ public:
|
|||||||
{ return m_current_rewinder_using; }
|
{ return m_current_rewinder_using; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
bool useLocalEvent() const;
|
bool useLocalEvent() const;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void addRewindInfoEventFunction(RewindInfoEventFunction* rief)
|
||||||
|
{ m_pending_rief.push_back(rief); }
|
||||||
|
|
||||||
}; // RewindManager
|
}; // RewindManager
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "config/stk_config.hpp"
|
#include "config/stk_config.hpp"
|
||||||
#include "modes/world.hpp"
|
#include "modes/world.hpp"
|
||||||
#include "network/network_config.hpp"
|
#include "network/network_config.hpp"
|
||||||
|
#include "network/rewinder.hpp"
|
||||||
#include "network/rewind_info.hpp"
|
#include "network/rewind_info.hpp"
|
||||||
#include "network/rewind_manager.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
|
// A rewind is done after a state in the past is inserted. This function
|
||||||
// makes sure that m_current is not end()
|
// 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 ||
|
while((*m_current)->getTicks() > undo_ticks ||
|
||||||
(*m_current)->isEvent() || !(*m_current)->isConfirmed())
|
(*m_current)->isEvent() || !(*m_current)->isConfirmed())
|
||||||
{
|
{
|
||||||
@ -418,9 +421,9 @@ void RewindQueue::unitTesting()
|
|||||||
virtual void rewind(BareNetworkString *s) {}
|
virtual void rewind(BareNetworkString *s) {}
|
||||||
virtual void saveTransform() {}
|
virtual void saveTransform() {}
|
||||||
virtual void computeError() {}
|
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
|
// First tests: add a state first, then an event, and make
|
||||||
// sure the state stays first
|
// sure the state stays first
|
||||||
@ -434,7 +437,7 @@ void RewindQueue::unitTesting()
|
|||||||
assert(q0.hasMoreRewindInfo());
|
assert(q0.hasMoreRewindInfo());
|
||||||
assert(q0.undoUntil(0) == 0);
|
assert(q0.undoUntil(0) == 0);
|
||||||
|
|
||||||
q0.addNetworkEvent(dummy_rewinder, NULL, 0);
|
q0.addNetworkEvent(dummy_rewinder.get(), NULL, 0);
|
||||||
// Network events are not immediately merged
|
// Network events are not immediately merged
|
||||||
assert(q0.m_all_rewind_info.size() == 1);
|
assert(q0.m_all_rewind_info.size() == 1);
|
||||||
|
|
||||||
@ -462,9 +465,9 @@ void RewindQueue::unitTesting()
|
|||||||
assert((*rii)->isEvent());
|
assert((*rii)->isEvent());
|
||||||
|
|
||||||
// Test time base comparisons: adding an event to the end
|
// 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
|
// 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
|
// rii points to the 3rd element, the ones added just now
|
||||||
// should be elements4 and 5:
|
// should be elements4 and 5:
|
||||||
rii++;
|
rii++;
|
||||||
|
@ -19,14 +19,13 @@
|
|||||||
#ifndef HEADER_REWIND_QUEUE_HPP
|
#ifndef HEADER_REWIND_QUEUE_HPP
|
||||||
#define HEADER_REWIND_QUEUE_HPP
|
#define HEADER_REWIND_QUEUE_HPP
|
||||||
|
|
||||||
#include "network/rewinder.hpp"
|
|
||||||
#include "utils/ptr_vector.hpp"
|
|
||||||
#include "utils/synchronised.hpp"
|
#include "utils/synchronised.hpp"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class BareNetworkString;
|
||||||
class EventRewinder;
|
class EventRewinder;
|
||||||
class RewindInfo;
|
class RewindInfo;
|
||||||
class TimeStepInfo;
|
class TimeStepInfo;
|
||||||
|
@ -20,27 +20,11 @@
|
|||||||
|
|
||||||
#include "network/rewind_manager.hpp"
|
#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.
|
* objects in the rewind manager.
|
||||||
*/
|
*/
|
||||||
Rewinder::Rewinder(const std::string& ui, bool can_be_destroyed, bool auto_add)
|
bool Rewinder::rewinderAdd()
|
||||||
: m_unique_identity(ui)
|
|
||||||
{
|
{
|
||||||
assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
|
return RewindManager::get()->addRewinder(shared_from_this());
|
||||||
m_can_be_destroyed = can_be_destroyed;
|
} // rewinderAdd
|
||||||
if (auto_add)
|
|
||||||
add();
|
|
||||||
} // Rewinder
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
/** Destructor.
|
|
||||||
*/
|
|
||||||
Rewinder::~Rewinder()
|
|
||||||
{
|
|
||||||
} // ~Rewinder
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
void Rewinder::add()
|
|
||||||
{
|
|
||||||
RewindManager::get()->addRewinder(this);
|
|
||||||
} // Rewinder
|
|
||||||
|
@ -19,33 +19,25 @@
|
|||||||
#ifndef HEADER_REWINDER_HPP
|
#ifndef HEADER_REWINDER_HPP
|
||||||
#define HEADER_REWINDER_HPP
|
#define HEADER_REWINDER_HPP
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class BareNetworkString;
|
class BareNetworkString;
|
||||||
|
|
||||||
class Rewinder
|
class Rewinder : public std::enable_shared_from_this<Rewinder>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void add();
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
void setUniqueIdentity(const std::string& uid) { m_unique_identity = uid; }
|
void setUniqueIdentity(const std::string& uid) { m_unique_identity = uid; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_unique_identity;
|
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:
|
public:
|
||||||
Rewinder(const std::string& ui, bool can_be_destroyed,
|
Rewinder(const std::string& ui = "") { m_unique_identity = ui; }
|
||||||
bool auto_add = true);
|
|
||||||
virtual ~Rewinder();
|
virtual ~Rewinder() {}
|
||||||
|
|
||||||
/** Called before a rewind. Is used to save the previous position of an
|
/** 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
|
* object before a rewind, so that the error due to a rewind can be
|
||||||
@ -89,14 +81,20 @@ public:
|
|||||||
/** Nothing to do here. */
|
/** Nothing to do here. */
|
||||||
virtual void reset() {}
|
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()
|
virtual std::function<void()> getLocalStateRestoreFunction()
|
||||||
{ return nullptr; }
|
{ 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
|
}; // Rewinder
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -720,7 +720,15 @@ void STKHost::mainLoop()
|
|||||||
auto sl = LobbyProtocol::get<ServerLobby>();
|
auto sl = LobbyProtocol::get<ServerLobby>();
|
||||||
if (direct_socket && sl && sl->waitingForPlayers())
|
if (direct_socket && sl && sl->waitingForPlayers())
|
||||||
{
|
{
|
||||||
handleDirectSocketRequest(direct_socket, sl);
|
try
|
||||||
|
{
|
||||||
|
handleDirectSocketRequest(direct_socket, sl);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log::warn("STKHost", "Direct socket error: %s",
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
} // if discovery host
|
} // if discovery host
|
||||||
|
|
||||||
if (is_server)
|
if (is_server)
|
||||||
|
@ -344,6 +344,14 @@ namespace Online
|
|||||||
request->queue();
|
request->queue();
|
||||||
} // requestPoll()
|
} // requestPoll()
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
OnlinePlayerProfile::PollRequest::PollRequest()
|
||||||
|
: XMLRequest(true)
|
||||||
|
{
|
||||||
|
m_disable_sending_log = NetworkConfig::get()->isNetworking() &&
|
||||||
|
NetworkConfig::get()->isServer();
|
||||||
|
} // PollRequest
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Callback for the poll request. Parses the information and spawns
|
/** Callback for the poll request. Parses the information and spawns
|
||||||
* notifications accordingly.
|
* notifications accordingly.
|
||||||
|
@ -61,7 +61,7 @@ namespace Online
|
|||||||
{
|
{
|
||||||
virtual void callback ();
|
virtual void callback ();
|
||||||
public:
|
public:
|
||||||
PollRequest() : XMLRequest(true) {}
|
PollRequest();
|
||||||
}; // PollRequest
|
}; // PollRequest
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -71,8 +71,6 @@ void* btKartRaycaster::castRay(const btVector3& from, const btVector3& to,
|
|||||||
result.m_hitNormalInWorld.normalize();
|
result.m_hitNormalInWorld.normalize();
|
||||||
result.m_distFraction = rayCallback.m_closestHitFraction;
|
result.m_distFraction = rayCallback.m_closestHitFraction;
|
||||||
result.m_triangle_index = -1;
|
result.m_triangle_index = -1;
|
||||||
const TriangleMesh &tm =
|
|
||||||
Track::getCurrentTrack()->getTriangleMesh();
|
|
||||||
// FIXME: this code assumes atm that the object the kart is
|
// FIXME: this code assumes atm that the object the kart is
|
||||||
// driving on is the main track (and not e.g. a physical object).
|
// 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
|
// If this should not be the case (i.e. the object hit by the
|
||||||
|
@ -123,12 +123,11 @@ void PhysicalObject::Settings::init()
|
|||||||
} // Settings
|
} // Settings
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
|
std::shared_ptr<PhysicalObject> PhysicalObject::fromXML
|
||||||
const XMLNode &xml_node,
|
(bool is_dynamic, const XMLNode &xml_node, TrackObject* object)
|
||||||
TrackObject* object)
|
|
||||||
{
|
{
|
||||||
PhysicalObject::Settings settings(xml_node);
|
PhysicalObject::Settings settings(xml_node);
|
||||||
return new PhysicalObject(is_dynamic, settings, object);
|
return std::make_shared<PhysicalObject>(is_dynamic, settings, object);
|
||||||
} // fromXML
|
} // fromXML
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -136,7 +135,6 @@ PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
|
|||||||
PhysicalObject::PhysicalObject(bool is_dynamic,
|
PhysicalObject::PhysicalObject(bool is_dynamic,
|
||||||
const PhysicalObject::Settings& settings,
|
const PhysicalObject::Settings& settings,
|
||||||
TrackObject* object)
|
TrackObject* object)
|
||||||
: Rewinder("P", false/*can_be_destroyed*/, false/*auto_add*/)
|
|
||||||
{
|
{
|
||||||
m_shape = NULL;
|
m_shape = NULL;
|
||||||
m_body = NULL;
|
m_body = NULL;
|
||||||
@ -793,7 +791,7 @@ void PhysicalObject::addForRewind()
|
|||||||
SmoothNetworkBody::setAdjustVerticalOffset(false);
|
SmoothNetworkBody::setAdjustVerticalOffset(false);
|
||||||
Rewinder::setUniqueIdentity(std::string("P") + StringUtils::toString
|
Rewinder::setUniqueIdentity(std::string("P") + StringUtils::toString
|
||||||
(Track::getCurrentTrack()->getPhysicalObjectUID()));
|
(Track::getCurrentTrack()->getPhysicalObjectUID()));
|
||||||
Rewinder::add();
|
Rewinder::rewinderAdd();
|
||||||
} // addForRewind
|
} // addForRewind
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -197,8 +197,8 @@ public:
|
|||||||
PhysicalObject(bool is_dynamic, const Settings& settings,
|
PhysicalObject(bool is_dynamic, const Settings& settings,
|
||||||
TrackObject* object);
|
TrackObject* object);
|
||||||
|
|
||||||
static PhysicalObject* fromXML(bool is_dynamic, const XMLNode &node,
|
static std::shared_ptr<PhysicalObject> fromXML
|
||||||
TrackObject* object);
|
(bool is_dynamic, const XMLNode &node, TrackObject* object);
|
||||||
|
|
||||||
virtual ~PhysicalObject ();
|
virtual ~PhysicalObject ();
|
||||||
virtual void reset ();
|
virtual void reset ();
|
||||||
|
@ -296,11 +296,13 @@ void History::Load()
|
|||||||
{
|
{
|
||||||
fgets(s, 1023, fd);
|
fgets(s, 1023, fd);
|
||||||
InputEvent &ie = m_all_input_events[i];
|
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,
|
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);
|
Log::warn("History", "Problems reading event: '%s'", s);
|
||||||
}
|
}
|
||||||
|
ie.m_action = (PlayerAction)action;
|
||||||
} // for i
|
} // for i
|
||||||
RewindManager::setEnable(rewind_manager_was_enabled);
|
RewindManager::setEnable(rewind_manager_was_enabled);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ void ReplayPlay::reset()
|
|||||||
{
|
{
|
||||||
for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
|
for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
|
||||||
{
|
{
|
||||||
m_ghost_karts[i].reset();
|
m_ghost_karts[i]->reset();
|
||||||
}
|
}
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay, int ca
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ReplayPlay::load()
|
void ReplayPlay::load()
|
||||||
{
|
{
|
||||||
m_ghost_karts.clearAndDeleteAll();
|
m_ghost_karts.clear();
|
||||||
|
|
||||||
if (m_second_replay_enabled)
|
if (m_second_replay_enabled)
|
||||||
loadFile(/* second replay */ true);
|
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();
|
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];
|
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),
|
m_ghost_karts.push_back(std::make_shared<GhostKart>
|
||||||
kart_num, kart_num + 1,
|
(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)));
|
rd.m_kart_color.at(kart_num-first_loaded_f_num)));
|
||||||
m_ghost_karts[kart_num].init(RaceManager::KT_GHOST);
|
m_ghost_karts[kart_num]->init(RaceManager::KT_GHOST);
|
||||||
Controller* controller = new GhostController(getGhostKart(kart_num),
|
Controller* controller = new GhostController(getGhostKart(kart_num).get(),
|
||||||
rd.m_name_list[kart_num-first_loaded_f_num]);
|
rd.m_name_list[kart_num-first_loaded_f_num]);
|
||||||
getGhostKart(kart_num)->setController(controller);
|
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_skidding_effect = skidding;
|
||||||
kre.m_red_skidding = red_skidding!=0;
|
kre.m_red_skidding = red_skidding!=0;
|
||||||
kre.m_jumping = jumping != 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);
|
btTransform(q, xyz), pi, bi, kre);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -472,7 +472,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
|
|||||||
kre.m_skidding_effect = skidding;
|
kre.m_skidding_effect = skidding;
|
||||||
kre.m_red_skidding = red_skidding!=0;
|
kre.m_red_skidding = red_skidding!=0;
|
||||||
kre.m_jumping = jumping != 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);
|
btTransform(q, xyz), pi, bi, kre);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
#define HEADER_REPLAY__PLAY_HPP
|
#define HEADER_REPLAY__PLAY_HPP
|
||||||
|
|
||||||
#include "replay/replay_base.hpp"
|
#include "replay/replay_base.hpp"
|
||||||
#include "utils/ptr_vector.hpp"
|
|
||||||
|
|
||||||
#include "irrString.h"
|
#include "irrString.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ private:
|
|||||||
std::vector<ReplayData> m_replay_file_list;
|
std::vector<ReplayData> m_replay_file_list;
|
||||||
|
|
||||||
/** All ghost karts. */
|
/** All ghost karts. */
|
||||||
PtrVector<GhostKart> m_ghost_karts;
|
std::vector<std::shared_ptr<GhostKart> > m_ghost_karts;
|
||||||
|
|
||||||
ReplayPlay();
|
ReplayPlay();
|
||||||
~ReplayPlay();
|
~ReplayPlay();
|
||||||
@ -162,7 +162,7 @@ public:
|
|||||||
const unsigned int getNumReplayFile() const
|
const unsigned int getNumReplayFile() const
|
||||||
{ return (unsigned int)m_replay_file_list.size(); }
|
{ 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
|
const unsigned int getNumGhostKart() const
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "states_screens/networking_lobby.hpp"
|
#include "states_screens/networking_lobby.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ void NetworkingLobby::onUpdate(float delta)
|
|||||||
if (m_timeout_message->isVisible() && m_player_list)
|
if (m_timeout_message->isVisible() && m_player_list)
|
||||||
{
|
{
|
||||||
float cur_player = (float)(m_player_list->getItemCount());
|
float cur_player = (float)(m_player_list->getItemCount());
|
||||||
if (cur_player > m_server_max_player * m_start_threshold &&
|
if (cur_player >= m_server_max_player * m_start_threshold &&
|
||||||
m_cur_starting_timer == std::numeric_limits<float>::max())
|
m_cur_starting_timer == std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
m_cur_starting_timer = m_start_timeout;
|
m_cur_starting_timer = m_start_timeout;
|
||||||
@ -220,7 +221,13 @@ void NetworkingLobby::onUpdate(float delta)
|
|||||||
else if (cur_player < m_server_max_player * m_start_threshold)
|
else if (cur_player < m_server_max_player * m_start_threshold)
|
||||||
{
|
{
|
||||||
m_cur_starting_timer = std::numeric_limits<float>::max();
|
m_cur_starting_timer = std::numeric_limits<float>::max();
|
||||||
m_timeout_message->setText(L"", true);
|
//I18N: In the networking lobby, display the number of players
|
||||||
|
//required to start a game for owner-less server
|
||||||
|
core::stringw msg =
|
||||||
|
_P("Game will start if there is more than %d player.",
|
||||||
|
"Game will start if there are more than %d players.",
|
||||||
|
(int)ceil(m_server_max_player * m_start_threshold) - 1);
|
||||||
|
m_timeout_message->setText(msg, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cur_starting_timer != std::numeric_limits<float>::max())
|
if (m_cur_starting_timer != std::numeric_limits<float>::max())
|
||||||
|
@ -1029,7 +1029,7 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt)
|
|||||||
if(m_plunger_move_time < dt && m_plunger_state!=PLUNGER_STATE_FAST)
|
if(m_plunger_move_time < dt && m_plunger_state!=PLUNGER_STATE_FAST)
|
||||||
{
|
{
|
||||||
const float fast_time = 0.3f;
|
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
|
// First time we reach faste state: select random target point
|
||||||
// at top of screen and set speed accordingly
|
// at top of screen and set speed accordingly
|
||||||
|
@ -189,10 +189,6 @@ void RaceGUIOverworld::renderGlobal(float dt)
|
|||||||
if (race_manager->getIfEmptyScreenSpaceExists() &&
|
if (race_manager->getIfEmptyScreenSpaceExists() &&
|
||||||
!GUIEngine::ModalDialog::isADialogActive())
|
!GUIEngine::ModalDialog::isADialogActive())
|
||||||
{
|
{
|
||||||
const float sqrt_num_players =
|
|
||||||
sqrtf((float)race_manager->getNumLocalPlayers());
|
|
||||||
const int rows = (int)ceil(sqrt_num_players);
|
|
||||||
const int cols = (int)round(sqrt_num_players);
|
|
||||||
static video::SColor black = video::SColor(255,0,0,0);
|
static video::SColor black = video::SColor(255,0,0,0);
|
||||||
GL32_draw2DRectangle(black, irr_driver->getSplitscreenWindow(
|
GL32_draw2DRectangle(black, irr_driver->getSplitscreenWindow(
|
||||||
race_manager->getNumLocalPlayers()));
|
race_manager->getNumLocalPlayers()));
|
||||||
|
@ -277,12 +277,16 @@ void TracksScreen::init()
|
|||||||
//I18N: In track screen
|
//I18N: In track screen
|
||||||
getWidget<LabelWidget>("lap-text")->setText(_("Number of goals to win"), false);
|
getWidget<LabelWidget>("lap-text")->setText(_("Number of goals to win"), false);
|
||||||
m_laps->setValue(UserConfigParams::m_num_goals);
|
m_laps->setValue(UserConfigParams::m_num_goals);
|
||||||
|
m_laps->setMin(1);
|
||||||
|
m_laps->setMax(10);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//I18N: In track screen
|
//I18N: In track screen
|
||||||
getWidget<LabelWidget>("lap-text")->setText(_("Maximum time (min.)"), false);
|
getWidget<LabelWidget>("lap-text")->setText(_("Maximum time (min.)"), false);
|
||||||
m_laps->setValue(UserConfigParams::m_soccer_time_limit);
|
m_laps->setValue(UserConfigParams::m_soccer_time_limit);
|
||||||
|
m_laps->setMin(1);
|
||||||
|
m_laps->setMax(15);
|
||||||
}
|
}
|
||||||
getWidget("reverse-text")->setVisible(true);
|
getWidget("reverse-text")->setVisible(true);
|
||||||
//I18N: In track screen
|
//I18N: In track screen
|
||||||
@ -296,6 +300,8 @@ void TracksScreen::init()
|
|||||||
//I18N: In track screen
|
//I18N: In track screen
|
||||||
getWidget<LabelWidget>("lap-text")->setText(_("Number of laps"), false);
|
getWidget<LabelWidget>("lap-text")->setText(_("Number of laps"), false);
|
||||||
m_laps->setVisible(true);
|
m_laps->setVisible(true);
|
||||||
|
m_laps->setMin(1);
|
||||||
|
m_laps->setMax(20);
|
||||||
m_laps->setValue(UserConfigParams::m_num_laps);
|
m_laps->setValue(UserConfigParams::m_num_laps);
|
||||||
getWidget("reverse-text")->setVisible(true);
|
getWidget("reverse-text")->setVisible(true);
|
||||||
//I18N: In track screen
|
//I18N: In track screen
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// SuperTuxKart - a fun racing game with go-kart
|
|
||||||
// Copyright (C) 2009-2015 Joerg Henrichs
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation; either version 3
|
|
||||||
// of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
#include "tracks/ambient_light_sphere.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "graphics/camera.hpp"
|
|
||||||
#include "io/xml_node.hpp"
|
|
||||||
#include "karts/abstract_kart.hpp"
|
|
||||||
#include "race/race_manager.hpp"
|
|
||||||
#include "tracks/track.hpp"
|
|
||||||
|
|
||||||
/** Constructor for a checksphere.
|
|
||||||
* \param node XML node containing the parameters for this checkline.
|
|
||||||
*/
|
|
||||||
AmbientLightSphere::AmbientLightSphere(const XMLNode &node,
|
|
||||||
unsigned int index)
|
|
||||||
: CheckSphere(node, index)
|
|
||||||
{
|
|
||||||
m_ambient_color = video::SColor(255, 0, 255, 0); // green
|
|
||||||
m_inner_radius2 = 1;
|
|
||||||
node.get("inner-radius", &m_inner_radius2);
|
|
||||||
m_inner_radius2 *= m_inner_radius2; // store the squared value
|
|
||||||
node.get("color", &m_ambient_color);
|
|
||||||
} // AmbientLightSphere
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
void AmbientLightSphere::update(float dt)
|
|
||||||
{
|
|
||||||
CheckStructure::update(dt);
|
|
||||||
|
|
||||||
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
|
|
||||||
{
|
|
||||||
Camera *camera = Camera::getCamera(i);
|
|
||||||
const AbstractKart *kart=camera->getKart();
|
|
||||||
if(!kart) continue;
|
|
||||||
if(isInside(i))
|
|
||||||
{
|
|
||||||
float d2=getDistance2ForKart(i);
|
|
||||||
video::SColor color;
|
|
||||||
Track *track=Track::getCurrentTrack();
|
|
||||||
if(d2<m_inner_radius2)
|
|
||||||
{ // Inside inner radius --> use new ambient color
|
|
||||||
color = m_ambient_color;
|
|
||||||
}
|
|
||||||
else // Interpolate between default and this ambient color
|
|
||||||
{
|
|
||||||
float f = (getRadius2()-d2)/(getRadius2()-m_inner_radius2);
|
|
||||||
const video::SColor &def = track->getDefaultAmbientColor();
|
|
||||||
color = m_ambient_color.getInterpolated(def, f);
|
|
||||||
}
|
|
||||||
camera->setAmbientLight(color);
|
|
||||||
} // if active
|
|
||||||
} // for i<num_karts
|
|
||||||
} // update
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
/** Only calls the sphere check if the kart is a player kart, since other
|
|
||||||
* karts won't change the ambient light.
|
|
||||||
* \param old_pos Position in previous frame.
|
|
||||||
* \param new_pos Position in current frame.
|
|
||||||
* \param indx Index of the kart, can be used to store kart specific
|
|
||||||
* additional data.
|
|
||||||
*/
|
|
||||||
bool AmbientLightSphere::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
|
||||||
unsigned int indx)
|
|
||||||
{
|
|
||||||
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
|
|
||||||
{
|
|
||||||
if(Camera::getCamera(i)->getKart()->getWorldKartId()==indx)
|
|
||||||
return CheckSphere::isTriggered(old_pos, new_pos, indx);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} // isTriggered
|
|
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// SuperTuxKart - a fun racing game with go-kart
|
|
||||||
// Copyright (C) 2009-2015 Joerg Henrichs
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation; either version 3
|
|
||||||
// of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
#ifndef HEADER_AMBIENT_LIGHT_SPHERE_HPP
|
|
||||||
#define HEADER_AMBIENT_LIGHT_SPHERE_HPP
|
|
||||||
|
|
||||||
#include <SColor.h>
|
|
||||||
using namespace irr;
|
|
||||||
|
|
||||||
#include "tracks/check_sphere.hpp"
|
|
||||||
|
|
||||||
class XMLNode;
|
|
||||||
class CheckManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief This class implements a check sphere that is used to change the ambient
|
|
||||||
* light if a kart is inside this sphere.
|
|
||||||
*
|
|
||||||
* Besides a normal radius this sphere also has a 2nd 'inner' radius: player karts
|
|
||||||
* inside the inner radius will have the full new ambient light, karts outside the
|
|
||||||
* default light, and karts in between will mix the light dependent on distance.
|
|
||||||
*
|
|
||||||
* \ingroup tracks
|
|
||||||
*/
|
|
||||||
class AmbientLightSphere : public CheckSphere
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
/** The inner radius defines the area during which the ambient light
|
|
||||||
* is extrapolated. The square of the value specified in the scene
|
|
||||||
* file is stored. */
|
|
||||||
float m_inner_radius2;
|
|
||||||
|
|
||||||
/** THe full ambient color to use once the kart is inside the
|
|
||||||
* inner radius. */
|
|
||||||
video::SColor m_ambient_color;
|
|
||||||
public:
|
|
||||||
AmbientLightSphere(const XMLNode &node, unsigned int index);
|
|
||||||
virtual ~AmbientLightSphere() {};
|
|
||||||
virtual void update(float dt);
|
|
||||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
|
||||||
unsigned int indx);
|
|
||||||
}; // AmbientLightSphere
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
#include "io/xml_node.hpp"
|
#include "io/xml_node.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
#include "tracks/ambient_light_sphere.hpp"
|
|
||||||
#include "tracks/check_cannon.hpp"
|
#include "tracks/check_cannon.hpp"
|
||||||
#include "tracks/check_goal.hpp"
|
#include "tracks/check_goal.hpp"
|
||||||
#include "tracks/check_lap.hpp"
|
#include "tracks/check_lap.hpp"
|
||||||
#include "tracks/check_line.hpp"
|
#include "tracks/check_line.hpp"
|
||||||
|
#include "tracks/check_sphere.hpp"
|
||||||
#include "tracks/check_structure.hpp"
|
#include "tracks/check_structure.hpp"
|
||||||
#include "tracks/drive_graph.hpp"
|
#include "tracks/drive_graph.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
|
@ -120,7 +120,7 @@ void Graph::cleanupDebugMesh()
|
|||||||
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
|
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
|
||||||
*/
|
*/
|
||||||
void Graph::createMesh(bool show_invisible, bool enable_transparency,
|
void Graph::createMesh(bool show_invisible, bool enable_transparency,
|
||||||
const video::SColor *track_color)
|
const video::SColor *track_color, bool invert_x_z)
|
||||||
{
|
{
|
||||||
#ifndef SERVER_ONLY
|
#ifndef SERVER_ONLY
|
||||||
// The debug track will not be lighted or culled.
|
// The debug track will not be lighted or culled.
|
||||||
@ -172,6 +172,18 @@ void Graph::createMesh(bool show_invisible, bool enable_transparency,
|
|||||||
differentNodeColor(count, &this_color);
|
differentNodeColor(count, &this_color);
|
||||||
// Transfer the 4 points of the current quad to the list of vertices
|
// Transfer the 4 points of the current quad to the list of vertices
|
||||||
m_all_nodes[count]->getVertices(new_v+4*i, this_color);
|
m_all_nodes[count]->getVertices(new_v+4*i, this_color);
|
||||||
|
if (invert_x_z)
|
||||||
|
{
|
||||||
|
auto* vptr = new_v + 4 * i;
|
||||||
|
vptr[0].Pos.X = -vptr[0].Pos.X;
|
||||||
|
vptr[0].Pos.Z = -vptr[0].Pos.Z;
|
||||||
|
vptr[1].Pos.X = -vptr[1].Pos.X;
|
||||||
|
vptr[1].Pos.Z = -vptr[1].Pos.Z;
|
||||||
|
vptr[2].Pos.X = -vptr[2].Pos.X;
|
||||||
|
vptr[2].Pos.Z = -vptr[2].Pos.Z;
|
||||||
|
vptr[3].Pos.X = -vptr[3].Pos.X;
|
||||||
|
vptr[3].Pos.Z = -vptr[3].Pos.Z;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the indices for the triangles
|
// Set up the indices for the triangles
|
||||||
// (note, afaik with opengl we could use quads directly, but the code
|
// (note, afaik with opengl we could use quads directly, but the code
|
||||||
@ -244,7 +256,7 @@ void Graph::createMesh(bool show_invisible, bool enable_transparency,
|
|||||||
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
|
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
|
||||||
*/
|
*/
|
||||||
void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
|
void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
|
||||||
const video::SColor *track_color)
|
const video::SColor *track_color, bool invert_x_z)
|
||||||
{
|
{
|
||||||
#ifndef SERVER_ONLY
|
#ifndef SERVER_ONLY
|
||||||
|
|
||||||
@ -294,6 +306,18 @@ void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
|
|||||||
differentNodeColor(count, &this_color);
|
differentNodeColor(count, &this_color);
|
||||||
// Transfer the 4 points of the current quad to the list of vertices
|
// Transfer the 4 points of the current quad to the list of vertices
|
||||||
m_all_nodes[count]->getSPMVertices(vertices.data() + (4 * i), this_color);
|
m_all_nodes[count]->getSPMVertices(vertices.data() + (4 * i), this_color);
|
||||||
|
if (invert_x_z)
|
||||||
|
{
|
||||||
|
auto* vptr = vertices.data() + (4 * i);
|
||||||
|
vptr[0].m_position.X = -vptr[0].m_position.X;
|
||||||
|
vptr[0].m_position.Z = -vptr[0].m_position.Z;
|
||||||
|
vptr[1].m_position.X = -vptr[1].m_position.X;
|
||||||
|
vptr[1].m_position.Z = -vptr[1].m_position.Z;
|
||||||
|
vptr[2].m_position.X = -vptr[2].m_position.X;
|
||||||
|
vptr[2].m_position.Z = -vptr[2].m_position.Z;
|
||||||
|
vptr[3].m_position.X = -vptr[3].m_position.X;
|
||||||
|
vptr[3].m_position.Z = -vptr[3].m_position.Z;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the indices for the triangles
|
// Set up the indices for the triangles
|
||||||
indices[6 * i] = 4 * i + 2; // First triangle: vertex 0, 1, 2
|
indices[6 * i] = 4 * i + 2; // First triangle: vertex 0, 1, 2
|
||||||
@ -366,7 +390,8 @@ void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
|
|||||||
*/
|
*/
|
||||||
RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension,
|
RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
const video::SColor &fill_color)
|
const video::SColor &fill_color,
|
||||||
|
bool invert_x_z)
|
||||||
{
|
{
|
||||||
// Skip minimap when profiling
|
// Skip minimap when profiling
|
||||||
if (ProfileWorld::isNoGraphics()) return NULL;
|
if (ProfileWorld::isNoGraphics()) return NULL;
|
||||||
@ -384,14 +409,14 @@ RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension,
|
|||||||
if (CVS->isGLSL())
|
if (CVS->isGLSL())
|
||||||
{
|
{
|
||||||
createMeshSP(/*show_invisible part of the track*/ false,
|
createMeshSP(/*show_invisible part of the track*/ false,
|
||||||
/*enable_transparency*/ false,
|
/*enable_transparency*/ false, /*track_color*/&fill_color,
|
||||||
/*track_color*/ &fill_color);
|
invert_x_z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
createMesh(/*show_invisible part of the track*/ false,
|
createMesh(/*show_invisible part of the track*/ false,
|
||||||
/*enable_transparency*/ false,
|
/*enable_transparency*/ false, /*track_color*/&fill_color,
|
||||||
/*track_color*/ &fill_color);
|
invert_x_z);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -93,11 +93,13 @@ private:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void createMesh(bool show_invisible=true,
|
void createMesh(bool show_invisible=true,
|
||||||
bool enable_transparency=false,
|
bool enable_transparency=false,
|
||||||
const video::SColor *track_color=NULL);
|
const video::SColor *track_color=NULL,
|
||||||
|
bool invert_x_z = false);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void createMeshSP(bool show_invisible=true,
|
void createMeshSP(bool show_invisible=true,
|
||||||
bool enable_transparency=false,
|
bool enable_transparency=false,
|
||||||
const video::SColor *track_color=NULL);
|
const video::SColor *track_color=NULL,
|
||||||
|
bool invert_x_z = false);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void cleanupDebugMesh();
|
void cleanupDebugMesh();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -143,7 +145,8 @@ public:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
RenderTarget* makeMiniMap(const core::dimension2du &dimension,
|
RenderTarget* makeMiniMap(const core::dimension2du &dimension,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
const video::SColor &fill_color);
|
const video::SColor &fill_color,
|
||||||
|
bool invert_x_z);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -105,6 +105,7 @@ Track::Track(const std::string &filename)
|
|||||||
m_magic_number = 0x17AC3802;
|
m_magic_number = 0x17AC3802;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_minimap_invert_x_z = false;
|
||||||
m_materials_loaded = false;
|
m_materials_loaded = false;
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_root =
|
m_root =
|
||||||
@ -709,6 +710,23 @@ void Track::startMusic() const
|
|||||||
*/
|
*/
|
||||||
void Track::loadArenaGraph(const XMLNode &node)
|
void Track::loadArenaGraph(const XMLNode &node)
|
||||||
{
|
{
|
||||||
|
// Determine if rotate minimap is needed for soccer mode (for blue team)
|
||||||
|
// Only need to test local player
|
||||||
|
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||||
|
{
|
||||||
|
const unsigned pk = race_manager->getNumPlayers();
|
||||||
|
for (unsigned i = 0; i < pk; i++)
|
||||||
|
{
|
||||||
|
if (!race_manager->getKartInfo(i).isNetworkPlayer() &&
|
||||||
|
race_manager->getKartInfo(i).getSoccerTeam() ==
|
||||||
|
SOCCER_TEAM_BLUE)
|
||||||
|
{
|
||||||
|
m_minimap_invert_x_z = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node);
|
ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node);
|
||||||
Graph::setGraph(graph);
|
Graph::setGraph(graph);
|
||||||
|
|
||||||
@ -786,7 +804,15 @@ void Track::loadDriveGraph(unsigned int mode_id, const bool reverse)
|
|||||||
|
|
||||||
void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
|
void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
|
||||||
{
|
{
|
||||||
Graph::get()->mapPoint2MiniMap(xyz, draw_at);
|
if (m_minimap_invert_x_z)
|
||||||
|
{
|
||||||
|
Vec3 invert = xyz;
|
||||||
|
invert.setX(-xyz.x());
|
||||||
|
invert.setZ(-xyz.z());
|
||||||
|
Graph::get()->mapPoint2MiniMap(invert, draw_at);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Graph::get()->mapPoint2MiniMap(xyz, draw_at);
|
||||||
draw_at->setX(draw_at->getX() * m_minimap_x_scale);
|
draw_at->setX(draw_at->getX() * m_minimap_x_scale);
|
||||||
draw_at->setY(draw_at->getY() * m_minimap_y_scale);
|
draw_at->setY(draw_at->getY() * m_minimap_y_scale);
|
||||||
}
|
}
|
||||||
@ -1115,7 +1141,9 @@ void Track::loadMinimap()
|
|||||||
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
||||||
|
|
||||||
//Use twice the size of the rendered minimap to reduce significantly aliasing
|
//Use twice the size of the rendered minimap to reduce significantly aliasing
|
||||||
m_render_target = Graph::get()->makeMiniMap(m_mini_map_size*2, "minimap::" + m_ident, video::SColor(127, 255, 255, 255));
|
m_render_target = Graph::get()->makeMiniMap(m_mini_map_size * 2,
|
||||||
|
"minimap::" + m_ident, video::SColor(127, 255, 255, 255),
|
||||||
|
m_minimap_invert_x_z);
|
||||||
if (!m_render_target) return;
|
if (!m_render_target) return;
|
||||||
|
|
||||||
core::dimension2du mini_map_texture_size = m_render_target->getTextureSize();
|
core::dimension2du mini_map_texture_size = m_render_target->getTextureSize();
|
||||||
@ -1737,6 +1765,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CameraEnd::clearEndCameras();
|
CameraEnd::clearEndCameras();
|
||||||
|
m_minimap_invert_x_z = false;
|
||||||
m_sky_type = SKY_NONE;
|
m_sky_type = SKY_NONE;
|
||||||
m_track_object_manager = new TrackObjectManager();
|
m_track_object_manager = new TrackObjectManager();
|
||||||
|
|
||||||
|
@ -365,6 +365,8 @@ private:
|
|||||||
float m_displacement_speed;
|
float m_displacement_speed;
|
||||||
int m_physical_object_uid;
|
int m_physical_object_uid;
|
||||||
|
|
||||||
|
bool m_minimap_invert_x_z;
|
||||||
|
|
||||||
/** The levels for color correction
|
/** The levels for color correction
|
||||||
* m_color_inlevel(black, gamma, white)
|
* m_color_inlevel(black, gamma, white)
|
||||||
* m_color_outlevel(black, white)*/
|
* m_color_outlevel(black, white)*/
|
||||||
|
@ -74,7 +74,6 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
|
|||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
m_presentation = NULL;
|
m_presentation = NULL;
|
||||||
m_animator = NULL;
|
m_animator = NULL;
|
||||||
m_physical_object = NULL;
|
|
||||||
m_parent_library = NULL;
|
m_parent_library = NULL;
|
||||||
m_interaction = interaction;
|
m_interaction = interaction;
|
||||||
m_presentation = presentation;
|
m_presentation = presentation;
|
||||||
@ -86,9 +85,8 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
|
|||||||
if (m_interaction != "ghost" && m_interaction != "none" &&
|
if (m_interaction != "ghost" && m_interaction != "none" &&
|
||||||
physics_settings )
|
physics_settings )
|
||||||
{
|
{
|
||||||
m_physical_object = new PhysicalObject(is_dynamic,
|
m_physical_object = std::make_shared<PhysicalObject>
|
||||||
*physics_settings,
|
(is_dynamic, *physics_settings, this);
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
@ -112,7 +110,6 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
|
|||||||
m_presentation = NULL;
|
m_presentation = NULL;
|
||||||
m_animator = NULL;
|
m_animator = NULL;
|
||||||
m_parent_library = parent_library;
|
m_parent_library = parent_library;
|
||||||
m_physical_object = NULL;
|
|
||||||
|
|
||||||
xml_node.get("id", &m_id );
|
xml_node.get("id", &m_id );
|
||||||
xml_node.get("model", &m_name );
|
xml_node.get("model", &m_name );
|
||||||
@ -455,7 +452,6 @@ TrackObject::~TrackObject()
|
|||||||
{
|
{
|
||||||
delete m_presentation;
|
delete m_presentation;
|
||||||
delete m_animator;
|
delete m_animator;
|
||||||
delete m_physical_object;
|
|
||||||
} // ~TrackObject
|
} // ~TrackObject
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -482,7 +478,7 @@ void TrackObject::setEnabled(bool enabled)
|
|||||||
|
|
||||||
if (getType() == "mesh")
|
if (getType() == "mesh")
|
||||||
{
|
{
|
||||||
if (m_physical_object != NULL)
|
if (m_physical_object)
|
||||||
{
|
{
|
||||||
if (enabled)
|
if (enabled)
|
||||||
m_physical_object->addBody();
|
m_physical_object->addBody();
|
||||||
@ -508,7 +504,7 @@ void TrackObject::resetEnabled()
|
|||||||
|
|
||||||
if (getType() == "mesh")
|
if (getType() == "mesh")
|
||||||
{
|
{
|
||||||
if (m_physical_object != NULL)
|
if (m_physical_object)
|
||||||
{
|
{
|
||||||
if (m_initially_visible)
|
if (m_initially_visible)
|
||||||
m_physical_object->addBody();
|
m_physical_object->addBody();
|
||||||
@ -581,7 +577,7 @@ void TrackObject::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
|||||||
if (m_presentation != NULL)
|
if (m_presentation != NULL)
|
||||||
m_presentation->move(xyz, hpr, scale, isAbsoluteCoord);
|
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);
|
movePhysicalBodyToGraphicalNode(xyz, hpr);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ protected:
|
|||||||
/** True if a kart can drive on this object. This will */
|
/** True if a kart can drive on this object. This will */
|
||||||
bool m_is_driveable;
|
bool m_is_driveable;
|
||||||
|
|
||||||
PhysicalObject* m_physical_object;
|
std::shared_ptr<PhysicalObject> m_physical_object;
|
||||||
|
|
||||||
ThreeDAnimation* m_animator;
|
ThreeDAnimation* m_animator;
|
||||||
|
|
||||||
@ -164,9 +164,10 @@ public:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
bool isSoccerBall() const { return m_soccer_ball; }
|
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; }
|
const core::vector3df getInitXYZ() const { return m_init_xyz; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -214,7 +215,7 @@ public:
|
|||||||
/** Get the physics representation of an object.
|
/** Get the physics representation of an object.
|
||||||
* On the script side, the returned object is of type : @ref Scripting_PhysicalObject
|
* 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 */
|
/** Hide or show the object */
|
||||||
void setEnabled(bool mode);
|
void setEnabled(bool mode);
|
||||||
|
|
||||||
|
@ -74,18 +74,21 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
|
|||||||
prev_sector, test_nodes, ignore_vertical);
|
prev_sector, test_nodes, ignore_vertical);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArenaGraph (battle and soccer mode) doesn't need the code below
|
// Keep the last valid graph node for arena mode
|
||||||
if (ag) return;
|
if (ag)
|
||||||
|
{
|
||||||
|
if (prev_sector != Graph::UNKNOWN_SECTOR)
|
||||||
|
m_last_valid_graph_node = prev_sector;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// keep the current quad as the latest valid one IF the player has one
|
// keep the current quad as the latest valid one IF the player has one
|
||||||
// of the required checklines
|
// of the required checklines
|
||||||
const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node);
|
const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node);
|
||||||
const std::vector<int>& checkline_requirements = dn->getChecklineRequirements();
|
const std::vector<int>& checkline_requirements = dn->getChecklineRequirements();
|
||||||
|
|
||||||
bool isValidQuad = false;
|
|
||||||
if (checkline_requirements.size() == 0)
|
if (checkline_requirements.size() == 0)
|
||||||
{
|
{
|
||||||
isValidQuad = true;
|
|
||||||
if (m_on_road)
|
if (m_on_road)
|
||||||
m_last_valid_graph_node = m_current_graph_node;
|
m_last_valid_graph_node = m_current_graph_node;
|
||||||
}
|
}
|
||||||
@ -98,7 +101,6 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
|
|||||||
//has_prerequisite = true;
|
//has_prerequisite = true;
|
||||||
if (m_on_road)
|
if (m_on_road)
|
||||||
m_last_valid_graph_node = m_current_graph_node;
|
m_last_valid_graph_node = m_current_graph_node;
|
||||||
isValidQuad = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,8 @@ public:
|
|||||||
bool isOnRoad() const { return m_on_road; }
|
bool isOnRoad() const { return m_on_road; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void setLastTriggeredCheckline(int i) { m_last_triggered_checkline = i; }
|
void setLastTriggeredCheckline(int i) { m_last_triggered_checkline = i; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
int getLastValidGraphNode() const { return m_last_valid_graph_node; }
|
||||||
|
|
||||||
}; // TrackSector
|
}; // TrackSector
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user