correctly load AvatarEntities from settings redux

This commit is contained in:
Andrew Meadows 2018-12-07 08:39:37 -08:00
parent 026c6301a6
commit e37b5b52f0
4 changed files with 139 additions and 56 deletions

View file

@ -1299,19 +1299,25 @@ void MyAvatar::saveData() {
_flyingHMDSetting.set(getFlyingHMDPref());
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
_avatarEntitiesLock.withReadLock([&] {
uint32_t numEntities = _avatarEntityData.size();
uint32_t prevNumEntities = _avatarEntityCountSetting.get(0);
resizeAvatarEntitySettingHandles(std::max<uint32_t>(numEntities, prevNumEntities));
saveAvatarEntityDataToSettings();
}
void MyAvatar::saveAvatarEntityDataToSettings() {
uint32_t numEntities = _avatarEntityData.size();
uint32_t prevNumEntities = _avatarEntityCountSetting.get(0);
resizeAvatarEntitySettingHandles(std::max<uint32_t>(numEntities, prevNumEntities));
if (numEntities > 0) {
_avatarEntitiesLock.withReadLock([&] {
// Note: this roundabout path from AvatarEntityData to JSON string is NOT efficient
QScriptEngine engine;
QScriptValue toStringMethod = engine.evaluate("(function() { return JSON.stringify(this) })");
//QScriptEngine engine;
//QScriptValue toStringMethod = engine.evaluate("(function() { return JSON.stringify(this) })");
AvatarEntityMap::const_iterator itr = _avatarEntityData.begin();
numEntities = 0;
while (itr != _avatarEntityData.end()) {
EntityItemProperties properties;
QByteArray buffer = itr.value();
/* TODO: fix this to read data from elsewhere
if (properties.constructFromBuffer((uint8_t*)buffer.data(), buffer.size())) {
if (properties.getParentID() == getSessionUUID()) {
properties.setParentID(AVATAR_SELF_ID);
@ -1324,24 +1330,27 @@ void MyAvatar::saveData() {
} else {
// buffer is corrupt --> skip it
}
*/
++numEntities;
++itr;
}
_avatarEntityCountSetting.set(numEntities);
});
}
_avatarEntityCountSetting.set(numEntities);
if (numEntities < prevNumEntities) {
uint32_t numEntitiesToRemove = prevNumEntities - numEntities;
for (uint32_t i = 0; i < numEntitiesToRemove; ++i) {
if (_avatarEntityIDSettings.size() > numEntities) {
_avatarEntityIDSettings.back().remove();
_avatarEntityIDSettings.pop_back();
}
if (_avatarEntityDataSettings.size() > numEntities) {
_avatarEntityDataSettings.back().remove();
_avatarEntityDataSettings.pop_back();
}
if (numEntities < prevNumEntities) {
uint32_t numEntitiesToRemove = prevNumEntities - numEntities;
for (uint32_t i = 0; i < numEntitiesToRemove; ++i) {
if (_avatarEntityIDSettings.size() > numEntities) {
_avatarEntityIDSettings.back().remove();
_avatarEntityIDSettings.pop_back();
}
if (_avatarEntityDataSettings.size() > numEntities) {
_avatarEntityDataSettings.back().remove();
_avatarEntityDataSettings.pop_back();
}
}
});
}
}
float loadSetting(Settings& settings, const QString& name, float defaultValue) {
@ -1459,6 +1468,7 @@ void MyAvatar::updateAvatarEntity(const QUuid& entityID, const EntityItemPropert
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
EncodeBitstreamParams params;
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
QUuid parentID = entity->getParentID();
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
if (appendState != OctreeElement::COMPLETED) {
@ -1466,10 +1476,56 @@ void MyAvatar::updateAvatarEntity(const QUuid& entityID, const EntityItemPropert
return;
}
packetData.shrinkByteArrays();
storeAvatarEntityDataPayload(entity->getID(), packetData.getUncompressedByteArray());
//QByteArray tempArray = QByteArray::fromRawData((const char*)packetData.getUncompressedData(), packetData.getUncompressedSize());
QByteArray tempArray((const char*)packetData.getUncompressedData(), packetData.getUncompressedSize());
for (int i = 0; i < 4; ++i) {
tempArray[i] = (uint8_t)(0xff);
}
storeAvatarEntityDataPayload(entity->getID(), tempArray);
}
void MyAvatar::updateAvatarEntities() {
// TODO: modify this info for MyAvatar
// AVATAR ENTITY UPDATE FLOW
// - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity()
// - updateAvatarEntity saves the bytes and flags the trait instance for the entity as updated
// - ClientTraitsHandler::sendChangedTraitsToMixer sends the entity bytes to the mixer which relays them to other interfaces
// - AvatarHashMap::processBulkAvatarTraits on other interfaces calls avatar->processTraitInstace
// - AvatarData::processTraitInstance calls updateAvatarEntity, which sets _avatarEntityDataChanged = true
// - (My)Avatar::simulate notices _avatarEntityDataChanged and here we are...
// AVATAR ENTITY DELETE FLOW
// - EntityScriptingInterface::deleteEntity calls _myAvatar->clearAvatarEntity() for deleted avatar entities
// - clearAvatarEntity removes the avatar entity and flags the trait instance for the entity as deleted
// - ClientTraitsHandler::sendChangedTraitsToMixer sends a deletion to the mixer which relays to other interfaces
// - AvatarHashMap::processBulkAvatarTraits on other interfaces calls avatar->processDeletedTraitInstace
// - AvatarData::processDeletedTraitInstance calls clearAvatarEntity
// - AvatarData::clearAvatarEntity sets _avatarEntityDataChanged = true and adds the ID to the detached list
// - Avatar::simulate notices _avatarEntityDataChanged and here we are...
if (!_avatarEntityDataChanged) {
return;
}
if (getID().isNull() ||
getID() == AVATAR_SELF_ID ||
DependencyManager::get<NodeList>()->getSessionUUID() == QUuid()) {
// wait until MyAvatar and this Node gets an ID before doing this. Otherwise, various things go wrong --
// things get their parent fixed up from AVATAR_SELF_ID to a null uuid which means "no parent".
return;
}
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (!entityTree) {
return;
}
loadAvatarEntityDataFromSettings();
setAvatarEntityDataChanged(false);
}
void MyAvatar::loadData() {
getHead()->setBasePitch(_headPitchSetting.get());
@ -1482,31 +1538,7 @@ void MyAvatar::loadData() {
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
int numEntities = _avatarEntityCountSetting.get(0);
auto entityTree = DependencyManager::get<EntityTreeRenderer>()->getTree();
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);
}
}
loadAvatarEntityDataFromSettings();
// Flying preferences must be loaded before calling setFlyingEnabled()
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
@ -1528,6 +1560,62 @@ void MyAvatar::loadData() {
setEnableDebugDrawPosition(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawPosition));
}
void MyAvatar::loadAvatarEntityDataFromSettings() {
_avatarEntitiesLock.withReadLock([&] {
_avatarEntityData.clear();
});
int numEntities = _avatarEntityCountSetting.get(0);
if (numEntities == 0) {
return;
}
QScriptEngine scriptEngine;
std::vector<EntityItemProperties> entitiesToLoad;
entitiesToLoad.resize(numEntities);
for (int i = 0; i < numEntities; i++) {
resizeAvatarEntitySettingHandles(i);
// 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 = entitiesToLoad[i];
EntityItemPropertiesFromScriptValueIgnoreReadOnly(propertiesScriptValue, properties);
// the ClientOnly property can get stripped out elsewhere so we need to always set it true here
properties.setClientOnly(true);
}
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
if (entityTree) {
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
EncodeBitstreamParams params;
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
for (uint32_t i = 0; i < entitiesToLoad.size(); ++i) {
// try to create the entity
QUuid entityID = QUuid::createUuid(); // generate a new ID
entityTree->withWriteLock([&] {
EntityItemPointer entity = entityTree->addEntity(entityID, entitiesToLoad[i]);
if (entity) {
// use the entity to build the data payload
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
if (appendState == OctreeElement::COMPLETED) {
QByteArray tempArray = QByteArray::fromRawData((const char*)packetData.getUncompressedData(), packetData.getUncompressedSize());
storeAvatarEntityDataPayload(entityID, tempArray);
}
packetData.reset();
}
});
}
}
}
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
Settings settings;
settings.beginGroup("savedAttachmentData");

View file

@ -13,6 +13,7 @@
#define hifi_MyAvatar_h
#include <bitset>
#include <iostream> // adebug
#include <glm/glm.hpp>
@ -577,7 +578,9 @@ public:
// get/set avatar data
void resizeAvatarEntitySettingHandles(unsigned int avatarEntityIndex);
void saveData();
void saveAvatarEntityDataToSettings();
void loadData();
void loadAvatarEntityDataFromSettings();
void saveAttachmentData(const AttachmentData& attachment) const;
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
@ -1184,6 +1187,7 @@ public:
virtual void setAttachmentsVariant(const QVariantList& variant) override;
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
void updateAvatarEntities() override;
/**jsdoc
* Create a new grab.

View file

@ -332,14 +332,6 @@ void Avatar::updateAvatarEntities() {
return;
}
if (getID().isNull() ||
getID() == AVATAR_SELF_ID ||
DependencyManager::get<NodeList>()->getSessionUUID() == QUuid()) {
// wait until MyAvatar and this Node gets an ID before doing this. Otherwise, various things go wrong --
// things get their parent fixed up from AVATAR_SELF_ID to a null uuid which means "no parent".
return;
}
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (!entityTree) {
@ -380,7 +372,6 @@ void Avatar::updateAvatarEntities() {
EntityItemProperties properties;
{
// create a temporary EntityItem to unpack the data
int32_t bytesLeftToRead = data.size();
unsigned char* dataAt = (unsigned char*)(data.data());
properties.constructFromBuffer(dataAt, bytesLeftToRead);

View file

@ -139,7 +139,7 @@ public:
typedef render::Payload<AvatarData> Payload;
void init();
void updateAvatarEntities();
virtual void updateAvatarEntities();
void removeAvatarEntitiesFromTree();
void simulate(float deltaTime, bool inView);
virtual void simulateAttachments(float deltaTime);