mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 18:24:08 +02:00
correctly load AvatarEntities from settings redux
This commit is contained in:
parent
026c6301a6
commit
e37b5b52f0
4 changed files with 139 additions and 56 deletions
|
@ -1299,19 +1299,25 @@ void MyAvatar::saveData() {
|
||||||
_flyingHMDSetting.set(getFlyingHMDPref());
|
_flyingHMDSetting.set(getFlyingHMDPref());
|
||||||
|
|
||||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
_avatarEntitiesLock.withReadLock([&] {
|
saveAvatarEntityDataToSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::saveAvatarEntityDataToSettings() {
|
||||||
uint32_t numEntities = _avatarEntityData.size();
|
uint32_t numEntities = _avatarEntityData.size();
|
||||||
uint32_t prevNumEntities = _avatarEntityCountSetting.get(0);
|
uint32_t prevNumEntities = _avatarEntityCountSetting.get(0);
|
||||||
resizeAvatarEntitySettingHandles(std::max<uint32_t>(numEntities, prevNumEntities));
|
resizeAvatarEntitySettingHandles(std::max<uint32_t>(numEntities, prevNumEntities));
|
||||||
|
if (numEntities > 0) {
|
||||||
|
_avatarEntitiesLock.withReadLock([&] {
|
||||||
|
|
||||||
// Note: this roundabout path from AvatarEntityData to JSON string is NOT efficient
|
// Note: this roundabout path from AvatarEntityData to JSON string is NOT efficient
|
||||||
QScriptEngine engine;
|
//QScriptEngine engine;
|
||||||
QScriptValue toStringMethod = engine.evaluate("(function() { return JSON.stringify(this) })");
|
//QScriptValue toStringMethod = engine.evaluate("(function() { return JSON.stringify(this) })");
|
||||||
AvatarEntityMap::const_iterator itr = _avatarEntityData.begin();
|
AvatarEntityMap::const_iterator itr = _avatarEntityData.begin();
|
||||||
numEntities = 0;
|
numEntities = 0;
|
||||||
while (itr != _avatarEntityData.end()) {
|
while (itr != _avatarEntityData.end()) {
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
QByteArray buffer = itr.value();
|
QByteArray buffer = itr.value();
|
||||||
|
/* TODO: fix this to read data from elsewhere
|
||||||
if (properties.constructFromBuffer((uint8_t*)buffer.data(), buffer.size())) {
|
if (properties.constructFromBuffer((uint8_t*)buffer.data(), buffer.size())) {
|
||||||
if (properties.getParentID() == getSessionUUID()) {
|
if (properties.getParentID() == getSessionUUID()) {
|
||||||
properties.setParentID(AVATAR_SELF_ID);
|
properties.setParentID(AVATAR_SELF_ID);
|
||||||
|
@ -1324,8 +1330,12 @@ void MyAvatar::saveData() {
|
||||||
} else {
|
} else {
|
||||||
// buffer is corrupt --> skip it
|
// buffer is corrupt --> skip it
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
++numEntities;
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
_avatarEntityCountSetting.set(numEntities);
|
_avatarEntityCountSetting.set(numEntities);
|
||||||
|
|
||||||
if (numEntities < prevNumEntities) {
|
if (numEntities < prevNumEntities) {
|
||||||
|
@ -1341,7 +1351,6 @@ void MyAvatar::saveData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float loadSetting(Settings& settings, const QString& name, float defaultValue) {
|
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);
|
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
|
||||||
EncodeBitstreamParams params;
|
EncodeBitstreamParams params;
|
||||||
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
|
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
|
||||||
|
QUuid parentID = entity->getParentID();
|
||||||
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
|
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
|
||||||
|
|
||||||
if (appendState != OctreeElement::COMPLETED) {
|
if (appendState != OctreeElement::COMPLETED) {
|
||||||
|
@ -1466,9 +1476,55 @@ void MyAvatar::updateAvatarEntity(const QUuid& entityID, const EntityItemPropert
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
packetData.shrinkByteArrays();
|
//QByteArray tempArray = QByteArray::fromRawData((const char*)packetData.getUncompressedData(), packetData.getUncompressedSize());
|
||||||
storeAvatarEntityDataPayload(entity->getID(), packetData.getUncompressedByteArray());
|
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() {
|
void MyAvatar::loadData() {
|
||||||
getHead()->setBasePitch(_headPitchSetting.get());
|
getHead()->setBasePitch(_headPitchSetting.get());
|
||||||
|
@ -1482,31 +1538,7 @@ void MyAvatar::loadData() {
|
||||||
|
|
||||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||||
|
|
||||||
int numEntities = _avatarEntityCountSetting.get(0);
|
loadAvatarEntityDataFromSettings();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||||
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
||||||
|
@ -1528,6 +1560,62 @@ void MyAvatar::loadData() {
|
||||||
setEnableDebugDrawPosition(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawPosition));
|
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 {
|
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.beginGroup("savedAttachmentData");
|
settings.beginGroup("savedAttachmentData");
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_MyAvatar_h
|
#define hifi_MyAvatar_h
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <iostream> // adebug
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
@ -577,7 +578,9 @@ public:
|
||||||
// get/set avatar data
|
// get/set avatar data
|
||||||
void resizeAvatarEntitySettingHandles(unsigned int avatarEntityIndex);
|
void resizeAvatarEntitySettingHandles(unsigned int avatarEntityIndex);
|
||||||
void saveData();
|
void saveData();
|
||||||
|
void saveAvatarEntityDataToSettings();
|
||||||
void loadData();
|
void loadData();
|
||||||
|
void loadAvatarEntityDataFromSettings();
|
||||||
|
|
||||||
void saveAttachmentData(const AttachmentData& attachment) const;
|
void saveAttachmentData(const AttachmentData& attachment) const;
|
||||||
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
|
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
|
||||||
|
@ -1184,6 +1187,7 @@ public:
|
||||||
virtual void setAttachmentsVariant(const QVariantList& variant) override;
|
virtual void setAttachmentsVariant(const QVariantList& variant) override;
|
||||||
|
|
||||||
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
|
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
|
||||||
|
void updateAvatarEntities() override;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Create a new grab.
|
* Create a new grab.
|
||||||
|
|
|
@ -332,14 +332,6 @@ void Avatar::updateAvatarEntities() {
|
||||||
return;
|
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>();
|
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||||
if (!entityTree) {
|
if (!entityTree) {
|
||||||
|
@ -380,7 +372,6 @@ void Avatar::updateAvatarEntities() {
|
||||||
|
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
{
|
{
|
||||||
// create a temporary EntityItem to unpack the data
|
|
||||||
int32_t bytesLeftToRead = data.size();
|
int32_t bytesLeftToRead = data.size();
|
||||||
unsigned char* dataAt = (unsigned char*)(data.data());
|
unsigned char* dataAt = (unsigned char*)(data.data());
|
||||||
properties.constructFromBuffer(dataAt, bytesLeftToRead);
|
properties.constructFromBuffer(dataAt, bytesLeftToRead);
|
||||||
|
|
|
@ -139,7 +139,7 @@ public:
|
||||||
typedef render::Payload<AvatarData> Payload;
|
typedef render::Payload<AvatarData> Payload;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void updateAvatarEntities();
|
virtual void updateAvatarEntities();
|
||||||
void removeAvatarEntitiesFromTree();
|
void removeAvatarEntitiesFromTree();
|
||||||
void simulate(float deltaTime, bool inView);
|
void simulate(float deltaTime, bool inView);
|
||||||
virtual void simulateAttachments(float deltaTime);
|
virtual void simulateAttachments(float deltaTime);
|
||||||
|
|
Loading…
Reference in a new issue