correctly load AvatarEntities from settings

This commit is contained in:
Andrew Meadows 2018-12-05 14:34:43 -08:00
parent 263d6cb7ad
commit 026c6301a6
6 changed files with 76 additions and 21 deletions

View file

@ -50,6 +50,7 @@
#include <RecordingScriptingInterface.h>
#include <trackers/FaceTracker.h>
#include <RenderableModelEntityItem.h>
#include <VariantMapToScriptValue.h>
#include "MyHead.h"
#include "MySkeletonModel.h"
@ -1437,6 +1438,38 @@ void MyAvatar::setEnableInverseKinematics(bool 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() {
getHead()->setBasePitch(_headPitchSetting.get());
@ -1450,13 +1483,29 @@ void MyAvatar::loadData() {
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
int numEntities = _avatarEntityCountSetting.get(0);
auto entityTree = DependencyManager::get<EntityTreeRenderer>()->getTree();
for (int i = 0; i < numEntities; i++) {
resizeAvatarEntitySettingHandles(i);
QUuid entityID = QUuid::createUuid(); // generate a new ID
QString propertiesString = _avatarEntityDataSettings[i].get();
// TODO: convert propertiesString to EntityItemProperties
//updateAvatarEntity(entityID, properties);
if (numEntities > 0) {
QScriptEngine scriptEngine;
for (int i = 0; i < numEntities; i++) {
resizeAvatarEntitySettingHandles(i);
QUuid entityID = QUuid::createUuid(); // generate a new ID
// 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()

View file

@ -1402,6 +1402,9 @@ public slots:
*/
bool getEnableMeshVisible() const override;
// TODO: make this invokable, probably also move down to AvatarData
void updateAvatarEntity(const QUuid& entityID, const EntityItemProperties& properties);
/**jsdoc
* Set whether or not your avatar mesh is visible.
* @function MyAvatar.setEnableMeshVisible

View file

@ -2019,7 +2019,7 @@ void AvatarData::processTrait(AvatarTraits::TraitType traitType, QByteArray trai
void AvatarData::processTraitInstance(AvatarTraits::TraitType traitType,
AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData) {
if (traitType == AvatarTraits::AvatarEntity) {
updateAvatarEntity(instanceID, traitBinaryData);
storeAvatarEntityDataPayload(instanceID, traitBinaryData);
} else if (traitType == AvatarTraits::Grab) {
updateAvatarGrabData(instanceID, traitBinaryData);
}
@ -2569,8 +2569,9 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
if (attachmentJson.isObject()) {
QVariantMap entityData = attachmentJson.toObject().toVariantMap();
QUuid entityID = entityData.value("id").toUuid();
// ADEBUG TODO: fix this broken path
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;
void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) {
void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) {
_avatarEntitiesLock.withWriteLock([&] {
AvatarEntityMap::iterator itr = _avatarEntityData.find(entityID);
if (itr == _avatarEntityData.end()) {
if (_avatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
_avatarEntityData.insert(entityID, entityData);
_avatarEntityData.insert(entityID, data);
}
} 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) {
bool removedEntity = false;

View file

@ -952,13 +952,14 @@ public:
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload);
/**jsdoc
* @function MyAvatar.updateAvatarEntity
* @param {Uuid} entityID
* @param {string} entityData
*/
Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData);
Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QString& entityPropertiesString);
/**jsdoc
* @function MyAvatar.clearAvatarEntity

View file

@ -39,8 +39,7 @@ void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByte
}
}
void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
EntityTreePointer entityTree,
void EntityEditPacketSender::queueEditAvatarEntityMessage(EntityTreePointer entityTree,
EntityItemID entityItemID,
const EntityItemProperties& properties) {
assert(_myAvatar);
@ -53,6 +52,7 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
qCDebug(entities) << "EntityEditPacketSender::queueEditAvatarEntityMessage can't find entity: " << entityItemID;
return;
}
entity->setLastBroadcast(usecTimestampNow());
// serialize ALL properties in an "AvatarEntity" packet
// rather than just the ones being edited.
@ -65,17 +65,14 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
if (appendState != OctreeElement::COMPLETED) {
// this entity is too big
// this entity's payload is too big
return;
}
packetData.shrinkByteArrays();
_myAvatar->updateAvatarEntity(entityItemID, packetData.getUncompressedByteArray());
entity->setLastBroadcast(usecTimestampNow());
_myAvatar->storeAvatarEntityDataPayload(entity->getID(), packetData.getUncompressedByteArray());
}
void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
EntityTreePointer entityTree,
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";
} else if (properties.getOwningAvatarID() == _myAvatar->getID()) {
// 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 {
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit for another avatar";
}

View file

@ -50,7 +50,7 @@ public slots:
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
private:
void queueEditAvatarEntityMessage(PacketType type, EntityTreePointer entityTree,
void queueEditAvatarEntityMessage(EntityTreePointer entityTree,
EntityItemID entityItemID, const EntityItemProperties& properties);
private: