diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index ef98185a5..4cd87a229 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -41,6 +41,7 @@ #include "karts/explosion_animation.hpp" #include "modes/linear_world.hpp" #include "network/compress_network_body.hpp" +#include "network/network_config.hpp" #include "network/network_string.hpp" #include "network/rewind_manager.hpp" #include "physics/physics.hpp" @@ -426,6 +427,10 @@ bool Flyable::updateAndDelete(int ticks) return false; } // if animation + // Round down values in network for better synchronization + if (NetworkConfig::get()->roundValuesNow()) + CompressNetworkBody::compress(m_body.get(), m_motion_state.get()); + // 32767 for max m_ticks_since_thrown so the last bit for animation save if (m_ticks_since_thrown < 32767) m_ticks_since_thrown += ticks; @@ -654,9 +659,8 @@ BareNetworkString* Flyable::saveState(std::vector* ru) m_animation->saveState(buffer); else { - CompressNetworkBody::compress(m_body->getWorldTransform(), - m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer, - m_body.get(), m_motion_state.get()); + CompressNetworkBody::compress( + m_body.get(), m_motion_state.get(), buffer); } return buffer; } // saveState @@ -684,14 +688,9 @@ void Flyable::restoreState(BareNetworkString *buffer, int count) // will set m_animation to null delete m_animation; } - btTransform t; - Vec3 lv, av; - CompressNetworkBody::decompress(buffer, &t, &lv, &av); - - m_body->setLinearVelocity(lv); - m_body->setAngularVelocity(av); - m_body->proceedToTransform(t); - setTrans(t); + CompressNetworkBody::decompress( + buffer, m_body.get(), m_motion_state.get()); + m_transform = m_body->getWorldTransform(); } m_ticks_since_thrown = ticks_since_thrown_animation & 32767; m_has_server_state = true; diff --git a/src/karts/moveable.hpp b/src/karts/moveable.hpp index 3905791e0..c67143d45 100644 --- a/src/karts/moveable.hpp +++ b/src/karts/moveable.hpp @@ -46,8 +46,6 @@ class Moveable: public NoCopy, { private: Vec3 m_velocityLC; /** m_body; diff --git a/src/network/compress_network_body.hpp b/src/network/compress_network_body.hpp index 6a953201d..10b2cc2ae 100644 --- a/src/network/compress_network_body.hpp +++ b/src/network/compress_network_body.hpp @@ -29,49 +29,68 @@ namespace CompressNetworkBody { using namespace MiniGLM; // ------------------------------------------------------------------------ - inline void compress(btTransform t, const Vec3& lv, const Vec3& av, - BareNetworkString* bns, btRigidBody* body, - btMotionState* ms) + inline void setRoundedDownValues(float x, float y, float z, + uint32_t compressed_q, + short lvx, short lvy, short lvz, + short avx, short avy, short avz, + btRigidBody* body, btMotionState* ms) { - bns->add(t.getOrigin()); - uint32_t compressed_q = compressQuaternion(t.getRotation()); - bns->addUInt32(compressed_q); - std::array lvs = - {{ toFloat16(lv.x()), toFloat16(lv.y()), toFloat16(lv.z()) }}; - bns->addUInt16(lvs[0]).addUInt16(lvs[1]).addUInt16(lvs[2]); - std::array avs = - {{ toFloat16(av.x()), toFloat16(av.y()), toFloat16(av.z()) }}; - bns->addUInt16(avs[0]).addUInt16(avs[1]).addUInt16(avs[2]); + btTransform trans; + trans.setOrigin(btVector3(x,y,z)); + trans.setRotation(decompressbtQuaternion(compressed_q)); + btVector3 lv(toFloat32(lvx), toFloat32(lvy), toFloat32(lvz)); + btVector3 av(toFloat32(avx), toFloat32(avy), toFloat32(avz)); - btQuaternion uncompressed_q = decompressbtQuaternion(compressed_q); - t.setRotation(uncompressed_q); - Vec3 uncompressed_lv(toFloat32(lvs[0]), toFloat32(lvs[1]), - toFloat32(lvs[2])); - Vec3 uncompressed_av(toFloat32(avs[0]), toFloat32(avs[1]), - toFloat32(avs[2])); - body->setWorldTransform(t); - ms->setWorldTransform(t); - body->setInterpolationWorldTransform(t); - body->setLinearVelocity(uncompressed_lv); - body->setAngularVelocity(uncompressed_av); - body->setInterpolationLinearVelocity(uncompressed_lv); - body->setInterpolationAngularVelocity(uncompressed_av); + body->setWorldTransform(trans); + ms->setWorldTransform(trans); + body->setInterpolationWorldTransform(trans); + body->setLinearVelocity(lv); + body->setAngularVelocity(av); + body->setInterpolationLinearVelocity(lv); + body->setInterpolationAngularVelocity(av); + body->updateInertiaTensor(); + } // setRoundedDownValues + // ------------------------------------------------------------------------ + inline void compress(btRigidBody* body, btMotionState* ms, + BareNetworkString* bns = NULL) + { + float x = body->getWorldTransform().getOrigin().x(); + float y = body->getWorldTransform().getOrigin().y(); + float z = body->getWorldTransform().getOrigin().z(); + uint32_t compressed_q = + compressQuaternion(body->getWorldTransform().getRotation()); + short lvx = toFloat16(body->getLinearVelocity().x()); + short lvy = toFloat16(body->getLinearVelocity().y()); + short lvz = toFloat16(body->getLinearVelocity().z()); + short avx = toFloat16(body->getAngularVelocity().x()); + short avy = toFloat16(body->getAngularVelocity().y()); + short avz = toFloat16(body->getAngularVelocity().z()); + setRoundedDownValues(x, y, z, compressed_q, lvx, lvy, lvz, avx, avy, + avz, body, ms); + // if bns is null, it's locally compress (for rounding down values) + if (!bns) + return; + + bns->addFloat(x).addFloat(y).addFloat(z).addUInt32(compressed_q); + bns->addUInt16(lvx).addUInt16(lvy).addUInt16(lvz) + .addUInt16(avx).addUInt16(avy).addUInt16(avz); } // compress // ------------------------------------------------------------------------ - inline void decompress(const BareNetworkString* bns, btTransform* t, - Vec3* lv, Vec3* av) + inline void decompress(const BareNetworkString* bns, + btRigidBody* body, btMotionState* ms) { - t->setOrigin(bns->getVec3()); - t->setRotation(decompressbtQuaternion(bns->getUInt32())); - short vec[3]; - vec[0] = bns->getUInt16(); - vec[1] = bns->getUInt16(); - vec[2] = bns->getUInt16(); - *lv = Vec3(toFloat32(vec[0]), toFloat32(vec[1]), toFloat32(vec[2])); - vec[0] = bns->getUInt16(); - vec[1] = bns->getUInt16(); - vec[2] = bns->getUInt16(); - *av = Vec3(toFloat32(vec[0]), toFloat32(vec[1]), toFloat32(vec[2])); + float x = bns->getFloat(); + float y = bns->getFloat(); + float z = bns->getFloat(); + uint32_t compressed_q = bns->getUInt32(); + short lvx = bns->getUInt16(); + short lvy = bns->getUInt16(); + short lvz = bns->getUInt16(); + short avx = bns->getUInt16(); + short avy = bns->getUInt16(); + short avz = bns->getUInt16(); + setRoundedDownValues(x, y, z, compressed_q, lvx, lvy, lvz, avx, avy, + avz, body, ms); } // decompress }; diff --git a/src/network/network_config.cpp b/src/network/network_config.cpp index e8f3511e4..cf01be7de 100644 --- a/src/network/network_config.cpp +++ b/src/network/network_config.cpp @@ -20,6 +20,8 @@ #include "config/stk_config.hpp" #include "config/user_config.hpp" #include "input/device_manager.hpp" +#include "modes/world.hpp" +#include "network/rewind_manager.hpp" #include "network/server_config.hpp" #include "network/transport_address.hpp" #include "online/xml_request.hpp" @@ -159,3 +161,12 @@ void NetworkConfig::clearActivePlayersForClient() const input_manager->getDeviceManager()->clearLatestUsedDevice(); } } // clearActivePlayersForClient + +// ---------------------------------------------------------------------------- +/** True when client needs to round the bodies phyiscal info for current + * ticks, server doesn't as it will be done implictly in save state. */ +bool NetworkConfig::roundValuesNow() const +{ + return isNetworking() && !isServer() && RewindManager::get() + ->shouldSaveState(World::getWorld()->getTicksSinceStart()); +} // roundValuesNow diff --git a/src/network/network_config.hpp b/src/network/network_config.hpp index 6dc1c58ab..b2cf7cf2a 100644 --- a/src/network/network_config.hpp +++ b/src/network/network_config.hpp @@ -229,6 +229,8 @@ public: void setStateFrequency(int frequency) { m_state_frequency = frequency; } // ------------------------------------------------------------------------ int getStateFrequency() const { return m_state_frequency; } + // ------------------------------------------------------------------------ + bool roundValuesNow() const; }; // class NetworkConfig #endif // HEADER_NETWORK_CONFIG diff --git a/src/network/network_string.cpp b/src/network/network_string.cpp index 0d2bfee50..31f7e9415 100644 --- a/src/network/network_string.cpp +++ b/src/network/network_string.cpp @@ -37,6 +37,19 @@ void NetworkString::unitTesting() s.setSynchronous(false); assert(!s.isSynchronous()); + // 24bit saving, min -8388608, max 8388607 + int min = -8388608; + BareNetworkString smin; + smin.addInt24(min); + min = smin.getInt24(); + assert(min == -8388608); + + int max = 8388607; + BareNetworkString smax; + smax.addInt24(max); + max = smax.getInt24(); + assert(max == 8388607); + // Check log message format BareNetworkString slog(28); for(unsigned int i=0; i<28; i++) diff --git a/src/network/network_string.hpp b/src/network/network_string.hpp index 8c656fe05..180156912 100644 --- a/src/network/network_string.hpp +++ b/src/network/network_string.hpp @@ -245,6 +245,17 @@ public: return *this; } // addUInt16 + // ------------------------------------------------------------------------ + /** Adds signed 24 bit integer. */ + BareNetworkString& addInt24(const int value) + { + uint32_t combined = (uint32_t)value & 16777215; + m_buffer.push_back((combined >> 16) & 0xff); + m_buffer.push_back((combined >> 8) & 0xff); + m_buffer.push_back(combined & 0xff); + return *this; + } // addInt24 + // ------------------------------------------------------------------------ /** Adds unsigned 32 bit integer. */ BareNetworkString& addUInt32(const uint32_t& value) @@ -328,6 +339,16 @@ public: /** Returns a unsigned 32 bit integer. */ inline uint32_t getUInt32() const { return get(); } // ------------------------------------------------------------------------ + /** Returns a signed 24 bit integer. */ + inline int getInt24() const + { + uint32_t combined = get(); + if (combined & 8388608) + return (16777216 - (int)combined) * -1; + else + return (int)combined; + } + // ------------------------------------------------------------------------ /** Returns a unsigned 32 bit integer. */ inline uint32_t getTime() const { return get(); } // ------------------------------------------------------------------------ diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index 98f029775..fa689afd4 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -20,6 +20,7 @@ #include "config/stk_config.hpp" #include "graphics/central_settings.hpp" +#include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" @@ -28,9 +29,9 @@ #include "io/xml_node.hpp" #include "physics/physics.hpp" #include "physics/triangle_mesh.hpp" -#include "network/protocols/lobby_protocol.hpp" #include "network/compress_network_body.hpp" -#include "network/rewind_manager.hpp" +#include "network/network_config.hpp" +#include "network/protocols/lobby_protocol.hpp" #include "tracks/track.hpp" #include "tracks/track_object.hpp" #include "utils/constants.hpp" @@ -42,6 +43,7 @@ #include using namespace irr; +#include #include #include #include @@ -631,8 +633,11 @@ void PhysicalObject::update(float dt) { if (!m_is_dynamic) return; - m_current_transform = m_body->getWorldTransform(); + // Round down values in network for better synchronization + if (NetworkConfig::get()->roundValuesNow()) + CompressNetworkBody::compress(m_body, m_motion_state); + m_current_transform = m_body->getWorldTransform(); const Vec3 &xyz = m_current_transform.getOrigin(); if(m_reset_when_too_low && xyz.getY()* ru) if (auto sl = LobbyProtocol::get()) has_live_join = sl->hasLiveJoiningRecently(); + BareNetworkString* buffer = new BareNetworkString(); + // This will compress and round down values of body, use the rounded + // down value to test if sending state is needed + // If any client live-joined always send new state for this object + CompressNetworkBody::compress(m_body, m_motion_state, buffer); btTransform cur_transform = m_body->getWorldTransform(); + Vec3 current_lv = m_body->getLinearVelocity(); + Vec3 current_av = m_body->getAngularVelocity(); + if ((cur_transform.getOrigin() - m_last_transform.getOrigin()) .length() < 0.01f && - (m_body->getLinearVelocity() - m_last_lv).length() < 0.01f && - (m_body->getLinearVelocity() - m_last_av).length() < 0.01f && - !has_live_join) + (current_lv - m_last_lv).length() < 0.01f && + (current_av - m_last_av).length() < 0.01f && !has_live_join) + { + delete buffer; return nullptr; + } ru->push_back(getUniqueIdentity()); - BareNetworkString *buffer = new BareNetworkString(); m_last_transform = cur_transform; - m_last_lv = m_body->getLinearVelocity(); - m_last_av = m_body->getAngularVelocity(); - CompressNetworkBody::compress(m_last_transform, m_last_lv, m_last_av, - buffer, m_body, m_motion_state); + m_last_lv = current_lv; + m_last_av = current_av; return buffer; } // saveState @@ -831,16 +843,11 @@ BareNetworkString* PhysicalObject::saveState(std::vector* ru) void PhysicalObject::restoreState(BareNetworkString *buffer, int count) { m_no_server_state = false; - CompressNetworkBody::decompress(buffer, &m_last_transform, &m_last_lv, - &m_last_av); - - m_body->setWorldTransform(m_last_transform); - m_motion_state->setWorldTransform(m_last_transform); - m_body->setInterpolationWorldTransform(m_last_transform); - m_body->setLinearVelocity(m_last_lv); - m_body->setAngularVelocity(m_last_av); - m_body->setInterpolationLinearVelocity(m_last_lv); - m_body->setInterpolationAngularVelocity(m_last_av); + CompressNetworkBody::decompress(buffer, m_body, m_motion_state); + // Save the newly decompressed value for local state restore + m_last_transform = m_body->getWorldTransform(); + m_last_lv = m_body->getLinearVelocity(); + m_last_av = m_body->getAngularVelocity(); } // restoreState // ---------------------------------------------------------------------------- diff --git a/src/physics/physical_object.hpp b/src/physics/physical_object.hpp index 480e5ca5f..25cce5a5a 100644 --- a/src/physics/physical_object.hpp +++ b/src/physics/physical_object.hpp @@ -188,9 +188,13 @@ private: /** Non-null only if the shape is exact */ TriangleMesh *m_triangle_mesh; + /* Last transform and velocities recieved or saved for networking */ btTransform m_last_transform; Vec3 m_last_lv; Vec3 m_last_av; + + /* Used to determine if local state should be used, which is true + * when the object is not moving */ bool m_no_server_state; public: