Clean up compressing for network body
This commit is contained in:
parent
d00472f868
commit
733794bb3e
@ -41,6 +41,7 @@
|
|||||||
#include "karts/explosion_animation.hpp"
|
#include "karts/explosion_animation.hpp"
|
||||||
#include "modes/linear_world.hpp"
|
#include "modes/linear_world.hpp"
|
||||||
#include "network/compress_network_body.hpp"
|
#include "network/compress_network_body.hpp"
|
||||||
|
#include "network/network_config.hpp"
|
||||||
#include "network/network_string.hpp"
|
#include "network/network_string.hpp"
|
||||||
#include "network/rewind_manager.hpp"
|
#include "network/rewind_manager.hpp"
|
||||||
#include "physics/physics.hpp"
|
#include "physics/physics.hpp"
|
||||||
@ -426,6 +427,10 @@ bool Flyable::updateAndDelete(int ticks)
|
|||||||
return false;
|
return false;
|
||||||
} // if animation
|
} // 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
|
// 32767 for max m_ticks_since_thrown so the last bit for animation save
|
||||||
if (m_ticks_since_thrown < 32767)
|
if (m_ticks_since_thrown < 32767)
|
||||||
m_ticks_since_thrown += ticks;
|
m_ticks_since_thrown += ticks;
|
||||||
@ -654,9 +659,8 @@ BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
|
|||||||
m_animation->saveState(buffer);
|
m_animation->saveState(buffer);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CompressNetworkBody::compress(m_body->getWorldTransform(),
|
CompressNetworkBody::compress(
|
||||||
m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer,
|
m_body.get(), m_motion_state.get(), buffer);
|
||||||
m_body.get(), m_motion_state.get());
|
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
} // saveState
|
} // saveState
|
||||||
@ -684,14 +688,9 @@ void Flyable::restoreState(BareNetworkString *buffer, int count)
|
|||||||
// will set m_animation to null
|
// will set m_animation to null
|
||||||
delete m_animation;
|
delete m_animation;
|
||||||
}
|
}
|
||||||
btTransform t;
|
CompressNetworkBody::decompress(
|
||||||
Vec3 lv, av;
|
buffer, m_body.get(), m_motion_state.get());
|
||||||
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
|
m_transform = m_body->getWorldTransform();
|
||||||
|
|
||||||
m_body->setLinearVelocity(lv);
|
|
||||||
m_body->setAngularVelocity(av);
|
|
||||||
m_body->proceedToTransform(t);
|
|
||||||
setTrans(t);
|
|
||||||
}
|
}
|
||||||
m_ticks_since_thrown = ticks_since_thrown_animation & 32767;
|
m_ticks_since_thrown = ticks_since_thrown_animation & 32767;
|
||||||
m_has_server_state = true;
|
m_has_server_state = true;
|
||||||
|
@ -46,8 +46,6 @@ class Moveable: public NoCopy,
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Vec3 m_velocityLC; /**<Velocity in kart coordinates. */
|
Vec3 m_velocityLC; /**<Velocity in kart coordinates. */
|
||||||
/** The bullet transform of this rigid body. */
|
|
||||||
btTransform m_transform;
|
|
||||||
/** The 'real' heading between -180 to 180 degrees. */
|
/** The 'real' heading between -180 to 180 degrees. */
|
||||||
float m_heading;
|
float m_heading;
|
||||||
/** The pitch between -90 and 90 degrees. */
|
/** The pitch between -90 and 90 degrees. */
|
||||||
@ -55,6 +53,8 @@ private:
|
|||||||
/** The roll between -180 and 180 degrees. */
|
/** The roll between -180 and 180 degrees. */
|
||||||
float m_roll;
|
float m_roll;
|
||||||
protected:
|
protected:
|
||||||
|
/** The bullet transform of this rigid body. */
|
||||||
|
btTransform m_transform;
|
||||||
UserPointer m_user_pointer;
|
UserPointer m_user_pointer;
|
||||||
scene::ISceneNode *m_node;
|
scene::ISceneNode *m_node;
|
||||||
std::unique_ptr<btRigidBody> m_body;
|
std::unique_ptr<btRigidBody> m_body;
|
||||||
|
@ -29,49 +29,68 @@ namespace CompressNetworkBody
|
|||||||
{
|
{
|
||||||
using namespace MiniGLM;
|
using namespace MiniGLM;
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
inline void compress(btTransform t, const Vec3& lv, const Vec3& av,
|
inline void setRoundedDownValues(float x, float y, float z,
|
||||||
BareNetworkString* bns, btRigidBody* body,
|
uint32_t compressed_q,
|
||||||
btMotionState* ms)
|
short lvx, short lvy, short lvz,
|
||||||
|
short avx, short avy, short avz,
|
||||||
|
btRigidBody* body, btMotionState* ms)
|
||||||
{
|
{
|
||||||
bns->add(t.getOrigin());
|
btTransform trans;
|
||||||
uint32_t compressed_q = compressQuaternion(t.getRotation());
|
trans.setOrigin(btVector3(x,y,z));
|
||||||
bns->addUInt32(compressed_q);
|
trans.setRotation(decompressbtQuaternion(compressed_q));
|
||||||
std::array<short, 3> lvs =
|
btVector3 lv(toFloat32(lvx), toFloat32(lvy), toFloat32(lvz));
|
||||||
{{ toFloat16(lv.x()), toFloat16(lv.y()), toFloat16(lv.z()) }};
|
btVector3 av(toFloat32(avx), toFloat32(avy), toFloat32(avz));
|
||||||
bns->addUInt16(lvs[0]).addUInt16(lvs[1]).addUInt16(lvs[2]);
|
|
||||||
std::array<short, 3> avs =
|
|
||||||
{{ toFloat16(av.x()), toFloat16(av.y()), toFloat16(av.z()) }};
|
|
||||||
bns->addUInt16(avs[0]).addUInt16(avs[1]).addUInt16(avs[2]);
|
|
||||||
|
|
||||||
btQuaternion uncompressed_q = decompressbtQuaternion(compressed_q);
|
body->setWorldTransform(trans);
|
||||||
t.setRotation(uncompressed_q);
|
ms->setWorldTransform(trans);
|
||||||
Vec3 uncompressed_lv(toFloat32(lvs[0]), toFloat32(lvs[1]),
|
body->setInterpolationWorldTransform(trans);
|
||||||
toFloat32(lvs[2]));
|
body->setLinearVelocity(lv);
|
||||||
Vec3 uncompressed_av(toFloat32(avs[0]), toFloat32(avs[1]),
|
body->setAngularVelocity(av);
|
||||||
toFloat32(avs[2]));
|
body->setInterpolationLinearVelocity(lv);
|
||||||
body->setWorldTransform(t);
|
body->setInterpolationAngularVelocity(av);
|
||||||
ms->setWorldTransform(t);
|
body->updateInertiaTensor();
|
||||||
body->setInterpolationWorldTransform(t);
|
} // setRoundedDownValues
|
||||||
body->setLinearVelocity(uncompressed_lv);
|
// ------------------------------------------------------------------------
|
||||||
body->setAngularVelocity(uncompressed_av);
|
inline void compress(btRigidBody* body, btMotionState* ms,
|
||||||
body->setInterpolationLinearVelocity(uncompressed_lv);
|
BareNetworkString* bns = NULL)
|
||||||
body->setInterpolationAngularVelocity(uncompressed_av);
|
{
|
||||||
|
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
|
} // compress
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
inline void decompress(const BareNetworkString* bns, btTransform* t,
|
inline void decompress(const BareNetworkString* bns,
|
||||||
Vec3* lv, Vec3* av)
|
btRigidBody* body, btMotionState* ms)
|
||||||
{
|
{
|
||||||
t->setOrigin(bns->getVec3());
|
float x = bns->getFloat();
|
||||||
t->setRotation(decompressbtQuaternion(bns->getUInt32()));
|
float y = bns->getFloat();
|
||||||
short vec[3];
|
float z = bns->getFloat();
|
||||||
vec[0] = bns->getUInt16();
|
uint32_t compressed_q = bns->getUInt32();
|
||||||
vec[1] = bns->getUInt16();
|
short lvx = bns->getUInt16();
|
||||||
vec[2] = bns->getUInt16();
|
short lvy = bns->getUInt16();
|
||||||
*lv = Vec3(toFloat32(vec[0]), toFloat32(vec[1]), toFloat32(vec[2]));
|
short lvz = bns->getUInt16();
|
||||||
vec[0] = bns->getUInt16();
|
short avx = bns->getUInt16();
|
||||||
vec[1] = bns->getUInt16();
|
short avy = bns->getUInt16();
|
||||||
vec[2] = bns->getUInt16();
|
short avz = bns->getUInt16();
|
||||||
*av = Vec3(toFloat32(vec[0]), toFloat32(vec[1]), toFloat32(vec[2]));
|
setRoundedDownValues(x, y, z, compressed_q, lvx, lvy, lvz, avx, avy,
|
||||||
|
avz, body, ms);
|
||||||
} // decompress
|
} // decompress
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include "config/stk_config.hpp"
|
#include "config/stk_config.hpp"
|
||||||
#include "config/user_config.hpp"
|
#include "config/user_config.hpp"
|
||||||
#include "input/device_manager.hpp"
|
#include "input/device_manager.hpp"
|
||||||
|
#include "modes/world.hpp"
|
||||||
|
#include "network/rewind_manager.hpp"
|
||||||
#include "network/server_config.hpp"
|
#include "network/server_config.hpp"
|
||||||
#include "network/transport_address.hpp"
|
#include "network/transport_address.hpp"
|
||||||
#include "online/xml_request.hpp"
|
#include "online/xml_request.hpp"
|
||||||
@ -159,3 +161,12 @@ void NetworkConfig::clearActivePlayersForClient() const
|
|||||||
input_manager->getDeviceManager()->clearLatestUsedDevice();
|
input_manager->getDeviceManager()->clearLatestUsedDevice();
|
||||||
}
|
}
|
||||||
} // clearActivePlayersForClient
|
} // 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
|
||||||
|
@ -229,6 +229,8 @@ public:
|
|||||||
void setStateFrequency(int frequency) { m_state_frequency = frequency; }
|
void setStateFrequency(int frequency) { m_state_frequency = frequency; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
int getStateFrequency() const { return m_state_frequency; }
|
int getStateFrequency() const { return m_state_frequency; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
bool roundValuesNow() const;
|
||||||
}; // class NetworkConfig
|
}; // class NetworkConfig
|
||||||
|
|
||||||
#endif // HEADER_NETWORK_CONFIG
|
#endif // HEADER_NETWORK_CONFIG
|
||||||
|
@ -37,6 +37,19 @@ void NetworkString::unitTesting()
|
|||||||
s.setSynchronous(false);
|
s.setSynchronous(false);
|
||||||
assert(!s.isSynchronous());
|
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
|
// Check log message format
|
||||||
BareNetworkString slog(28);
|
BareNetworkString slog(28);
|
||||||
for(unsigned int i=0; i<28; i++)
|
for(unsigned int i=0; i<28; i++)
|
||||||
|
@ -245,6 +245,17 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
} // addUInt16
|
} // 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. */
|
/** Adds unsigned 32 bit integer. */
|
||||||
BareNetworkString& addUInt32(const uint32_t& value)
|
BareNetworkString& addUInt32(const uint32_t& value)
|
||||||
@ -328,6 +339,16 @@ public:
|
|||||||
/** Returns a unsigned 32 bit integer. */
|
/** Returns a unsigned 32 bit integer. */
|
||||||
inline uint32_t getUInt32() const { return get<uint32_t, 4>(); }
|
inline uint32_t getUInt32() const { return get<uint32_t, 4>(); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
/** Returns a signed 24 bit integer. */
|
||||||
|
inline int getInt24() const
|
||||||
|
{
|
||||||
|
uint32_t combined = get<uint32_t, 3>();
|
||||||
|
if (combined & 8388608)
|
||||||
|
return (16777216 - (int)combined) * -1;
|
||||||
|
else
|
||||||
|
return (int)combined;
|
||||||
|
}
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
/** Returns a unsigned 32 bit integer. */
|
/** Returns a unsigned 32 bit integer. */
|
||||||
inline uint32_t getTime() const { return get<uint32_t, 4>(); }
|
inline uint32_t getTime() const { return get<uint32_t, 4>(); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "config/stk_config.hpp"
|
#include "config/stk_config.hpp"
|
||||||
#include "graphics/central_settings.hpp"
|
#include "graphics/central_settings.hpp"
|
||||||
|
#include "graphics/irr_driver.hpp"
|
||||||
#include "graphics/material.hpp"
|
#include "graphics/material.hpp"
|
||||||
#include "graphics/material_manager.hpp"
|
#include "graphics/material_manager.hpp"
|
||||||
#include "graphics/mesh_tools.hpp"
|
#include "graphics/mesh_tools.hpp"
|
||||||
@ -28,9 +29,9 @@
|
|||||||
#include "io/xml_node.hpp"
|
#include "io/xml_node.hpp"
|
||||||
#include "physics/physics.hpp"
|
#include "physics/physics.hpp"
|
||||||
#include "physics/triangle_mesh.hpp"
|
#include "physics/triangle_mesh.hpp"
|
||||||
#include "network/protocols/lobby_protocol.hpp"
|
|
||||||
#include "network/compress_network_body.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.hpp"
|
||||||
#include "tracks/track_object.hpp"
|
#include "tracks/track_object.hpp"
|
||||||
#include "utils/constants.hpp"
|
#include "utils/constants.hpp"
|
||||||
@ -42,6 +43,7 @@
|
|||||||
#include <ITexture.h>
|
#include <ITexture.h>
|
||||||
using namespace irr;
|
using namespace irr;
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -631,8 +633,11 @@ void PhysicalObject::update(float dt)
|
|||||||
{
|
{
|
||||||
if (!m_is_dynamic) return;
|
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();
|
const Vec3 &xyz = m_current_transform.getOrigin();
|
||||||
if(m_reset_when_too_low && xyz.getY()<m_reset_height)
|
if(m_reset_when_too_low && xyz.getY()<m_reset_height)
|
||||||
{
|
{
|
||||||
@ -809,21 +814,28 @@ BareNetworkString* PhysicalObject::saveState(std::vector<std::string>* ru)
|
|||||||
if (auto sl = LobbyProtocol::get<LobbyProtocol>())
|
if (auto sl = LobbyProtocol::get<LobbyProtocol>())
|
||||||
has_live_join = sl->hasLiveJoiningRecently();
|
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();
|
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())
|
if ((cur_transform.getOrigin() - m_last_transform.getOrigin())
|
||||||
.length() < 0.01f &&
|
.length() < 0.01f &&
|
||||||
(m_body->getLinearVelocity() - m_last_lv).length() < 0.01f &&
|
(current_lv - m_last_lv).length() < 0.01f &&
|
||||||
(m_body->getLinearVelocity() - m_last_av).length() < 0.01f &&
|
(current_av - m_last_av).length() < 0.01f && !has_live_join)
|
||||||
!has_live_join)
|
{
|
||||||
|
delete buffer;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
ru->push_back(getUniqueIdentity());
|
ru->push_back(getUniqueIdentity());
|
||||||
BareNetworkString *buffer = new BareNetworkString();
|
|
||||||
m_last_transform = cur_transform;
|
m_last_transform = cur_transform;
|
||||||
m_last_lv = m_body->getLinearVelocity();
|
m_last_lv = current_lv;
|
||||||
m_last_av = m_body->getAngularVelocity();
|
m_last_av = current_av;
|
||||||
CompressNetworkBody::compress(m_last_transform, m_last_lv, m_last_av,
|
|
||||||
buffer, m_body, m_motion_state);
|
|
||||||
return buffer;
|
return buffer;
|
||||||
} // saveState
|
} // saveState
|
||||||
|
|
||||||
@ -831,16 +843,11 @@ BareNetworkString* PhysicalObject::saveState(std::vector<std::string>* ru)
|
|||||||
void PhysicalObject::restoreState(BareNetworkString *buffer, int count)
|
void PhysicalObject::restoreState(BareNetworkString *buffer, int count)
|
||||||
{
|
{
|
||||||
m_no_server_state = false;
|
m_no_server_state = false;
|
||||||
CompressNetworkBody::decompress(buffer, &m_last_transform, &m_last_lv,
|
CompressNetworkBody::decompress(buffer, m_body, m_motion_state);
|
||||||
&m_last_av);
|
// Save the newly decompressed value for local state restore
|
||||||
|
m_last_transform = m_body->getWorldTransform();
|
||||||
m_body->setWorldTransform(m_last_transform);
|
m_last_lv = m_body->getLinearVelocity();
|
||||||
m_motion_state->setWorldTransform(m_last_transform);
|
m_last_av = m_body->getAngularVelocity();
|
||||||
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);
|
|
||||||
} // restoreState
|
} // restoreState
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -188,9 +188,13 @@ private:
|
|||||||
/** Non-null only if the shape is exact */
|
/** Non-null only if the shape is exact */
|
||||||
TriangleMesh *m_triangle_mesh;
|
TriangleMesh *m_triangle_mesh;
|
||||||
|
|
||||||
|
/* Last transform and velocities recieved or saved for networking */
|
||||||
btTransform m_last_transform;
|
btTransform m_last_transform;
|
||||||
Vec3 m_last_lv;
|
Vec3 m_last_lv;
|
||||||
Vec3 m_last_av;
|
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;
|
bool m_no_server_state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user