mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-26 03:15:21 +02:00
Merge pull request #5710 from sethalves/fix-stuck-avatars
Fix stuck avatars
This commit is contained in:
commit
41daea7d92
6 changed files with 64 additions and 17 deletions
|
@ -295,7 +295,8 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
avatarPacketList.startSegment();
|
avatarPacketList.startSegment();
|
||||||
|
|
||||||
numAvatarDataBytes += avatarPacketList.write(otherNode->getUUID().toRfc4122());
|
numAvatarDataBytes += avatarPacketList.write(otherNode->getUUID().toRfc4122());
|
||||||
numAvatarDataBytes += avatarPacketList.write(otherAvatar.toByteArray(false));
|
numAvatarDataBytes +=
|
||||||
|
avatarPacketList.write(otherAvatar.toByteArray(false, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO));
|
||||||
|
|
||||||
avatarPacketList.endSegment();
|
avatarPacketList.endSegment();
|
||||||
|
|
||||||
|
@ -364,6 +365,31 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We're done encoding this version of the otherAvatars. Update their "lastSent" joint-states so
|
||||||
|
// that we can notice differences, next time around.
|
||||||
|
nodeList->eachMatchingNode(
|
||||||
|
[&](const SharedNodePointer& otherNode)->bool {
|
||||||
|
if (!otherNode->getLinkedData()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (otherNode->getType() != NodeType::Agent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!otherNode->getActiveSocket()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[&](const SharedNodePointer& otherNode) {
|
||||||
|
AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||||
|
MutexTryLocker lock(otherNodeData->getMutex());
|
||||||
|
if (!lock.isLocked()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
||||||
|
otherAvatar.doneEncoding(false);
|
||||||
|
});
|
||||||
|
|
||||||
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();
|
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,18 +123,18 @@ MyAvatar::~MyAvatar() {
|
||||||
_lookAtTargetAvatar.reset();
|
_lookAtTargetAvatar.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MyAvatar::toByteArray(bool cullSmallChanges) {
|
QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
CameraMode mode = Application::getInstance()->getCamera()->getMode();
|
CameraMode mode = Application::getInstance()->getCamera()->getMode();
|
||||||
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
|
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
|
||||||
// fake the avatar position that is sent up to the AvatarMixer
|
// fake the avatar position that is sent up to the AvatarMixer
|
||||||
glm::vec3 oldPosition = _position;
|
glm::vec3 oldPosition = _position;
|
||||||
_position = getSkeletonPosition();
|
_position = getSkeletonPosition();
|
||||||
QByteArray array = AvatarData::toByteArray(cullSmallChanges);
|
QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll);
|
||||||
// copy the correct position back
|
// copy the correct position back
|
||||||
_position = oldPosition;
|
_position = oldPosition;
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
return AvatarData::toByteArray(cullSmallChanges);
|
return AvatarData::toByteArray(cullSmallChanges, sendAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::reset() {
|
void MyAvatar::reset() {
|
||||||
|
|
|
@ -200,7 +200,7 @@ private:
|
||||||
|
|
||||||
glm::vec3 getWorldBodyPosition() const;
|
glm::vec3 getWorldBodyPosition() const;
|
||||||
glm::quat getWorldBodyOrientation() const;
|
glm::quat getWorldBodyOrientation() const;
|
||||||
QByteArray toByteArray(bool cullSmallChanges);
|
QByteArray toByteArray(bool cullSmallChanges, bool sendAll);
|
||||||
void simulate(float deltaTime);
|
void simulate(float deltaTime);
|
||||||
void updateFromTrackers(float deltaTime);
|
void updateFromTrackers(float deltaTime);
|
||||||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;
|
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;
|
||||||
|
|
|
@ -31,10 +31,6 @@
|
||||||
|
|
||||||
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
||||||
|
|
||||||
// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer
|
|
||||||
const float MIN_ROTATION_DOT = 0.9999999f;
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f);
|
const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f);
|
||||||
|
@ -145,7 +141,7 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) {
|
||||||
_handPosition = glm::inverse(getOrientation()) * (handPosition - _position);
|
_handPosition = glm::inverse(getOrientation()) * (handPosition - _position);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AvatarData::toByteArray(bool cullSmallChanges) {
|
QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
// TODO: DRY this up to a shared method
|
// TODO: DRY this up to a shared method
|
||||||
// that can pack any type given the number of bytes
|
// that can pack any type given the number of bytes
|
||||||
// and return the number of bytes to push the pointer
|
// and return the number of bytes to push the pointer
|
||||||
|
@ -244,11 +240,12 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges) {
|
||||||
|
|
||||||
_lastSentJointData.resize(_jointData.size());
|
_lastSentJointData.resize(_jointData.size());
|
||||||
|
|
||||||
// foreach (const JointData& data, _jointData) {
|
|
||||||
for (int i=0; i < _jointData.size(); i++) {
|
for (int i=0; i < _jointData.size(); i++) {
|
||||||
const JointData& data = _jointData.at(i);
|
const JointData& data = _jointData.at(i);
|
||||||
if (_lastSentJointData[i].rotation != data.rotation) {
|
if (sendAll || _lastSentJointData[i].rotation != data.rotation) {
|
||||||
if (!cullSmallChanges || fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= MIN_ROTATION_DOT) {
|
if (sendAll ||
|
||||||
|
!cullSmallChanges ||
|
||||||
|
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||||
validity |= (1 << validityBit);
|
validity |= (1 << validityBit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +264,6 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges) {
|
||||||
const JointData& data = _jointData[ i ];
|
const JointData& data = _jointData[ i ];
|
||||||
if (validity & (1 << validityBit)) {
|
if (validity & (1 << validityBit)) {
|
||||||
destinationBuffer += packOrientationQuatToBytes(destinationBuffer, data.rotation);
|
destinationBuffer += packOrientationQuatToBytes(destinationBuffer, data.rotation);
|
||||||
_lastSentJointData[i].rotation = data.rotation;
|
|
||||||
}
|
}
|
||||||
if (++validityBit == BITS_IN_BYTE) {
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
validityBit = 0;
|
validityBit = 0;
|
||||||
|
@ -278,6 +274,20 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges) {
|
||||||
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarData::doneEncoding(bool cullSmallChanges) {
|
||||||
|
// The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData.
|
||||||
|
_lastSentJointData.resize(_jointData.size());
|
||||||
|
for (int i = 0; i < _jointData.size(); i ++) {
|
||||||
|
const JointData& data = _jointData[ i ];
|
||||||
|
if (_lastSentJointData[i].rotation != data.rotation) {
|
||||||
|
if (!cullSmallChanges ||
|
||||||
|
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||||
|
_lastSentJointData[i].rotation = data.rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AvatarData::shouldLogError(const quint64& now) {
|
bool AvatarData::shouldLogError(const quint64& now) {
|
||||||
if (now > _errorLogExpiry) {
|
if (now > _errorLogExpiry) {
|
||||||
_errorLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
_errorLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
||||||
|
@ -1083,7 +1093,11 @@ void AvatarData::setJointMappingsFromNetworkReply() {
|
||||||
void AvatarData::sendAvatarDataPacket() {
|
void AvatarData::sendAvatarDataPacket() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
QByteArray avatarByteArray = toByteArray(true);
|
// about 2% of the time, we send a full update (meaning, we transmit all the joint data), even if nothing has changed.
|
||||||
|
// this is to guard against a joint moving once, the packet getting lost, and the joint never moving again.
|
||||||
|
bool sendFullUpdate = randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO;
|
||||||
|
QByteArray avatarByteArray = toByteArray(true, sendFullUpdate);
|
||||||
|
doneEncoding(true);
|
||||||
|
|
||||||
auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size());
|
auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size());
|
||||||
avatarPacket->write(avatarByteArray);
|
avatarPacket->write(avatarByteArray);
|
||||||
|
|
|
@ -111,6 +111,11 @@ const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
||||||
// See also static AvatarData::defaultFullAvatarModelUrl().
|
// See also static AvatarData::defaultFullAvatarModelUrl().
|
||||||
const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
|
const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
|
||||||
|
|
||||||
|
// how often should we send a full report about joint rotations, even if they haven't changed?
|
||||||
|
const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02;
|
||||||
|
// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer
|
||||||
|
const float AVATAR_MIN_ROTATION_DOT = 0.9999999f;
|
||||||
|
|
||||||
|
|
||||||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
||||||
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
||||||
|
@ -171,7 +176,8 @@ public:
|
||||||
glm::vec3 getHandPosition() const;
|
glm::vec3 getHandPosition() const;
|
||||||
void setHandPosition(const glm::vec3& handPosition);
|
void setHandPosition(const glm::vec3& handPosition);
|
||||||
|
|
||||||
virtual QByteArray toByteArray(bool cullSmallChanges);
|
virtual QByteArray toByteArray(bool cullSmallChanges, bool sendAll);
|
||||||
|
virtual void doneEncoding(bool cullSmallChanges);
|
||||||
|
|
||||||
/// \return true if an error should be logged
|
/// \return true if an error should be logged
|
||||||
bool shouldLogError(const quint64& now);
|
bool shouldLogError(const quint64& now);
|
||||||
|
|
|
@ -599,7 +599,8 @@ void ScriptEngine::run() {
|
||||||
/ (1000 * 1000)) + 0.5);
|
/ (1000 * 1000)) + 0.5);
|
||||||
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
|
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
|
||||||
|
|
||||||
QByteArray avatarByteArray = _avatarData->toByteArray(true);
|
QByteArray avatarByteArray = _avatarData->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
|
||||||
|
_avatarData->doneEncoding(true);
|
||||||
auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size());
|
auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size());
|
||||||
|
|
||||||
avatarPacket->write(avatarByteArray);
|
avatarPacket->write(avatarByteArray);
|
||||||
|
|
Loading…
Reference in a new issue