mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 11:41:17 +02:00
correctly load AvatarEntities from settings
This commit is contained in:
parent
263d6cb7ad
commit
026c6301a6
6 changed files with 76 additions and 21 deletions
|
@ -50,6 +50,7 @@
|
||||||
#include <RecordingScriptingInterface.h>
|
#include <RecordingScriptingInterface.h>
|
||||||
#include <trackers/FaceTracker.h>
|
#include <trackers/FaceTracker.h>
|
||||||
#include <RenderableModelEntityItem.h>
|
#include <RenderableModelEntityItem.h>
|
||||||
|
#include <VariantMapToScriptValue.h>
|
||||||
|
|
||||||
#include "MyHead.h"
|
#include "MyHead.h"
|
||||||
#include "MySkeletonModel.h"
|
#include "MySkeletonModel.h"
|
||||||
|
@ -1437,6 +1438,38 @@ void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
||||||
_skeletonModel->getRig().setEnableInverseKinematics(isEnabled);
|
_skeletonModel->getRig().setEnableInverseKinematics(isEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::updateAvatarEntity(const QUuid& entityID, const EntityItemProperties& properties) {
|
||||||
|
auto entityTreeRenderer = qApp->getEntities();
|
||||||
|
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
|
||||||
|
EntityItemPointer entity;
|
||||||
|
if (entityTree) {
|
||||||
|
entity = entityTree->findEntityByID(entityID);
|
||||||
|
if (!entity) {
|
||||||
|
entity = entityTree->addEntity(entityID, properties);
|
||||||
|
if (!entity) {
|
||||||
|
// unable to create entity
|
||||||
|
// TODO? handle this case?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: propagate changes to entity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
|
||||||
|
EncodeBitstreamParams params;
|
||||||
|
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
|
||||||
|
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
|
||||||
|
|
||||||
|
if (appendState != OctreeElement::COMPLETED) {
|
||||||
|
// this entity's data is too big
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
packetData.shrinkByteArrays();
|
||||||
|
storeAvatarEntityDataPayload(entity->getID(), packetData.getUncompressedByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::loadData() {
|
void MyAvatar::loadData() {
|
||||||
getHead()->setBasePitch(_headPitchSetting.get());
|
getHead()->setBasePitch(_headPitchSetting.get());
|
||||||
|
|
||||||
|
@ -1450,13 +1483,29 @@ void MyAvatar::loadData() {
|
||||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||||
|
|
||||||
int numEntities = _avatarEntityCountSetting.get(0);
|
int numEntities = _avatarEntityCountSetting.get(0);
|
||||||
|
auto entityTree = DependencyManager::get<EntityTreeRenderer>()->getTree();
|
||||||
|
|
||||||
for (int i = 0; i < numEntities; i++) {
|
if (numEntities > 0) {
|
||||||
resizeAvatarEntitySettingHandles(i);
|
QScriptEngine scriptEngine;
|
||||||
QUuid entityID = QUuid::createUuid(); // generate a new ID
|
for (int i = 0; i < numEntities; i++) {
|
||||||
QString propertiesString = _avatarEntityDataSettings[i].get();
|
resizeAvatarEntitySettingHandles(i);
|
||||||
// TODO: convert propertiesString to EntityItemProperties
|
QUuid entityID = QUuid::createUuid(); // generate a new ID
|
||||||
//updateAvatarEntity(entityID, properties);
|
|
||||||
|
// NOTE: this path from EntityItemProperties JSON string to EntityItemProperties is NOT efficient
|
||||||
|
QString propertiesString = _avatarEntityDataSettings[i].get();
|
||||||
|
QJsonDocument propertiesDoc = QJsonDocument::fromJson(propertiesString.toUtf8());
|
||||||
|
QJsonObject propertiesObj = propertiesDoc.object();
|
||||||
|
QVariant propertiesVariant(propertiesObj);
|
||||||
|
QVariantMap propertiesMap = propertiesVariant.toMap();
|
||||||
|
QScriptValue propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine);
|
||||||
|
EntityItemProperties properties;
|
||||||
|
EntityItemPropertiesFromScriptValueIgnoreReadOnly(propertiesScriptValue, properties);
|
||||||
|
|
||||||
|
// the ClientOnly property can get stripped out elsewhere so we need to always set it true here
|
||||||
|
properties.setClientOnly(true);
|
||||||
|
|
||||||
|
updateAvatarEntity(entityID, properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||||
|
|
|
@ -1402,6 +1402,9 @@ public slots:
|
||||||
*/
|
*/
|
||||||
bool getEnableMeshVisible() const override;
|
bool getEnableMeshVisible() const override;
|
||||||
|
|
||||||
|
// TODO: make this invokable, probably also move down to AvatarData
|
||||||
|
void updateAvatarEntity(const QUuid& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Set whether or not your avatar mesh is visible.
|
* Set whether or not your avatar mesh is visible.
|
||||||
* @function MyAvatar.setEnableMeshVisible
|
* @function MyAvatar.setEnableMeshVisible
|
||||||
|
|
|
@ -2019,7 +2019,7 @@ void AvatarData::processTrait(AvatarTraits::TraitType traitType, QByteArray trai
|
||||||
void AvatarData::processTraitInstance(AvatarTraits::TraitType traitType,
|
void AvatarData::processTraitInstance(AvatarTraits::TraitType traitType,
|
||||||
AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData) {
|
AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData) {
|
||||||
if (traitType == AvatarTraits::AvatarEntity) {
|
if (traitType == AvatarTraits::AvatarEntity) {
|
||||||
updateAvatarEntity(instanceID, traitBinaryData);
|
storeAvatarEntityDataPayload(instanceID, traitBinaryData);
|
||||||
} else if (traitType == AvatarTraits::Grab) {
|
} else if (traitType == AvatarTraits::Grab) {
|
||||||
updateAvatarGrabData(instanceID, traitBinaryData);
|
updateAvatarGrabData(instanceID, traitBinaryData);
|
||||||
}
|
}
|
||||||
|
@ -2569,8 +2569,9 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
|
||||||
if (attachmentJson.isObject()) {
|
if (attachmentJson.isObject()) {
|
||||||
QVariantMap entityData = attachmentJson.toObject().toVariantMap();
|
QVariantMap entityData = attachmentJson.toObject().toVariantMap();
|
||||||
QUuid entityID = entityData.value("id").toUuid();
|
QUuid entityID = entityData.value("id").toUuid();
|
||||||
|
// ADEBUG TODO: fix this broken path
|
||||||
QByteArray properties = QByteArray::fromBase64(entityData.value("properties").toByteArray());
|
QByteArray properties = QByteArray::fromBase64(entityData.value("properties").toByteArray());
|
||||||
updateAvatarEntity(entityID, properties);
|
storeAvatarEntityDataPayload(entityID, properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2754,15 +2755,15 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
|
||||||
|
|
||||||
const int MAX_NUM_AVATAR_ENTITIES = 42;
|
const int MAX_NUM_AVATAR_ENTITIES = 42;
|
||||||
|
|
||||||
void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) {
|
void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) {
|
||||||
_avatarEntitiesLock.withWriteLock([&] {
|
_avatarEntitiesLock.withWriteLock([&] {
|
||||||
AvatarEntityMap::iterator itr = _avatarEntityData.find(entityID);
|
AvatarEntityMap::iterator itr = _avatarEntityData.find(entityID);
|
||||||
if (itr == _avatarEntityData.end()) {
|
if (itr == _avatarEntityData.end()) {
|
||||||
if (_avatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
|
if (_avatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
|
||||||
_avatarEntityData.insert(entityID, entityData);
|
_avatarEntityData.insert(entityID, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
itr.value() = entityData;
|
itr.value() = data;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2775,6 +2776,10 @@ void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& ent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarData::updateAvatarEntity(const QUuid& entityID, const QString& entityPropertiesString) {
|
||||||
|
// TODO: implement this as API exposed to JS
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree) {
|
void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree) {
|
||||||
|
|
||||||
bool removedEntity = false;
|
bool removedEntity = false;
|
||||||
|
|
|
@ -952,13 +952,14 @@ public:
|
||||||
// FIXME: Can this name be improved? Can it be deprecated?
|
// FIXME: Can this name be improved? Can it be deprecated?
|
||||||
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
|
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
|
||||||
|
|
||||||
|
void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.updateAvatarEntity
|
* @function MyAvatar.updateAvatarEntity
|
||||||
* @param {Uuid} entityID
|
* @param {Uuid} entityID
|
||||||
* @param {string} entityData
|
* @param {string} entityData
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData);
|
Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QString& entityPropertiesString);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.clearAvatarEntity
|
* @function MyAvatar.clearAvatarEntity
|
||||||
|
|
|
@ -39,8 +39,7 @@ void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
|
void EntityEditPacketSender::queueEditAvatarEntityMessage(EntityTreePointer entityTree,
|
||||||
EntityTreePointer entityTree,
|
|
||||||
EntityItemID entityItemID,
|
EntityItemID entityItemID,
|
||||||
const EntityItemProperties& properties) {
|
const EntityItemProperties& properties) {
|
||||||
assert(_myAvatar);
|
assert(_myAvatar);
|
||||||
|
@ -53,6 +52,7 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
|
||||||
qCDebug(entities) << "EntityEditPacketSender::queueEditAvatarEntityMessage can't find entity: " << entityItemID;
|
qCDebug(entities) << "EntityEditPacketSender::queueEditAvatarEntityMessage can't find entity: " << entityItemID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
entity->setLastBroadcast(usecTimestampNow());
|
||||||
|
|
||||||
// serialize ALL properties in an "AvatarEntity" packet
|
// serialize ALL properties in an "AvatarEntity" packet
|
||||||
// rather than just the ones being edited.
|
// rather than just the ones being edited.
|
||||||
|
@ -65,17 +65,14 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
|
||||||
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
|
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
|
||||||
|
|
||||||
if (appendState != OctreeElement::COMPLETED) {
|
if (appendState != OctreeElement::COMPLETED) {
|
||||||
// this entity is too big
|
// this entity's payload is too big
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
packetData.shrinkByteArrays();
|
packetData.shrinkByteArrays();
|
||||||
_myAvatar->updateAvatarEntity(entityItemID, packetData.getUncompressedByteArray());
|
_myAvatar->storeAvatarEntityDataPayload(entity->getID(), packetData.getUncompressedByteArray());
|
||||||
|
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
||||||
EntityTreePointer entityTree,
|
EntityTreePointer entityTree,
|
||||||
EntityItemID entityItemID,
|
EntityItemID entityItemID,
|
||||||
|
@ -85,7 +82,7 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
||||||
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit with no myAvatar";
|
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit with no myAvatar";
|
||||||
} else if (properties.getOwningAvatarID() == _myAvatar->getID()) {
|
} else if (properties.getOwningAvatarID() == _myAvatar->getID()) {
|
||||||
// this is an avatar-based entity --> update our avatar-data rather than sending to the entity-server
|
// this is an avatar-based entity --> update our avatar-data rather than sending to the entity-server
|
||||||
queueEditAvatarEntityMessage(type, entityTree, entityItemID, properties);
|
queueEditAvatarEntityMessage(entityTree, entityItemID, properties);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit for another avatar";
|
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit for another avatar";
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public slots:
|
||||||
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void queueEditAvatarEntityMessage(PacketType type, EntityTreePointer entityTree,
|
void queueEditAvatarEntityMessage(EntityTreePointer entityTree,
|
||||||
EntityItemID entityItemID, const EntityItemProperties& properties);
|
EntityItemID entityItemID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue