diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 05d070606a..0ca2bb9763 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include Q_LOGGING_CATEGORY(octree_server, "hifi.octree-server") @@ -1041,8 +1041,6 @@ void OctreeServer::readConfiguration() { _persistFilePath = getMyDefaultPersistFilename(); } - // If persist filename does not exist, let's see if there is one beside the application binary - // If there is, let's copy it over to our target persist directory QDir persistPath { _persistFilePath }; if (persistPath.isRelative()) { @@ -1159,7 +1157,7 @@ void OctreeServer::domainSettingsRequestComplete() { OctreeUtils::RawOctreeData data; qCDebug(octree_server) << "Reading octree data from" << _persistAbsoluteFilePath; - if (OctreeUtils::readOctreeDataInfoFromFile(_persistAbsoluteFilePath, &data)) { + if (data.readOctreeDataInfoFromFile(_persistAbsoluteFilePath)) { qCDebug(octree_server) << "Current octree data: ID(" << data.id << ") DataVersion(" << data.version << ")"; packet->writePrimitive(true); auto id = data.id.toRfc4122(); @@ -1191,7 +1189,7 @@ void OctreeServer::handleOctreeDataFileReply(QSharedPointer mes OctreeUtils::RawOctreeData data; qCDebug(octree_server) << "Reading octree data from" << _persistAbsoluteFilePath; - if (OctreeUtils::readOctreeDataInfoFromFile(_persistAbsoluteFilePath, &data)) { + if (data.readOctreeDataInfoFromFile(_persistAbsoluteFilePath)) { if (data.id.isNull()) { qCDebug(octree_server) << "Current octree data has a null id, updating"; data.resetIdAndVersion(); diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp index ecb242f7f8..85040d8c35 100644 --- a/domain-server/src/DomainContentBackupManager.cpp +++ b/domain-server/src/DomainContentBackupManager.cpp @@ -38,7 +38,7 @@ #include "DomainServer.h" -const int DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds +const std::chrono::seconds DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL { 30 }; // Backup format looks like: daily_backup-TIMESTAMP.zip static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" }; @@ -53,12 +53,11 @@ void DomainContentBackupManager::addBackupHandler(BackupHandlerPointer handler) DomainContentBackupManager::DomainContentBackupManager(const QString& backupDirectory, const QVariantList& backupRules, - int persistInterval, - bool debugTimestampNow) - : _backupDirectory(backupDirectory), - _persistInterval(persistInterval), - _lastCheck(usecTimestampNow()) + std::chrono::milliseconds persistInterval, + bool debugTimestampNow) : + _backupDirectory(backupDirectory), _persistInterval(persistInterval), _lastCheck(p_high_resolution_clock::now()) { + setObjectName("DomainContentBackupManager"); // Make sure the backup directory exists. @@ -76,7 +75,9 @@ void DomainContentBackupManager::parseBackupRules(const QVariantList& backupRule int interval = map["backupInterval"].toInt(); int count = map["maxBackupVersions"].toInt(); auto name = map["Name"].toString(); - auto format = name.replace(" ", "_").toLower(); + auto format = name.toLower(); + QRegExp matchDisallowedCharacters { "[^a-zA-Z0-9\\-_]+" }; + format.replace(matchDisallowedCharacters, "_"); qCDebug(domain_server) << " Name:" << name; qCDebug(domain_server) << " format:" << format; @@ -121,7 +122,32 @@ int64_t DomainContentBackupManager::getMostRecentBackupTimeInSecs(const QString& } void DomainContentBackupManager::setup() { - load(); + auto backups = getAllBackups(); + for (auto& backup : backups) { + QFile backupFile { backup.absolutePath }; + if (!backupFile.open(QIODevice::ReadOnly)) { + qCritical() << "Could not open file:" << backup.absolutePath; + qCritical() << " ERROR:" << backupFile.errorString(); + continue; + } + + QuaZip zip { &backupFile }; + if (!zip.open(QuaZip::mdUnzip)) { + qCritical() << "Could not open backup archive:" << backup.absolutePath; + qCritical() << " ERROR:" << zip.getZipError(); + continue; + } + + for (auto& handler : _backupHandlers) { + handler->loadBackup(backup.id, zip); + } + + zip.close(); + } + + for (auto& handler : _backupHandlers) { + handler->loadingComplete(); + } } bool DomainContentBackupManager::process() { @@ -130,10 +156,6 @@ bool DomainContentBackupManager::process() { constexpr int64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP)); - int64_t now = usecTimestampNow(); - int64_t sinceLastSave = now - _lastCheck; - int64_t intervalToCheck = _persistInterval * MSECS_TO_USECS; - if (_isRecovering) { bool isStillRecovering = any_of(begin(_backupHandlers), end(_backupHandlers), [](const BackupHandlerPointer& handler) { return handler->getRecoveryStatus().first; @@ -146,7 +168,9 @@ bool DomainContentBackupManager::process() { } } - if (sinceLastSave > intervalToCheck) { + auto now = p_high_resolution_clock::now(); + auto sinceLastSave = now - _lastCheck; + if (sinceLastSave > _persistInterval) { _lastCheck = now; if (!_isRecovering) { @@ -279,7 +303,8 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, bool success { false }; QDir backupDir { _backupDirectory }; - QFile backupFile { backupDir.filePath(backupName) }; + auto backupFilePath { backupDir.filePath(backupName) }; + QFile backupFile { backupFilePath }; if (backupFile.open(QIODevice::ReadOnly)) { QuaZip zip { &backupFile }; @@ -288,7 +313,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, backupFile.close(); } else { success = false; - qWarning() << "Invalid id: " << backupName; + qWarning() << "Failed to open backup file for reading: " << backupFilePath; } promise->resolve({ @@ -339,19 +364,10 @@ std::vector DomainContentBackupManager::getAllBackups() { auto dateTime = backupNameFormat.cap(3); auto createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT); if (!createdAt.isValid()) { + qDebug().nospace() << "Skipping backup (" << fileName << ") with invalid timestamp: " << dateTime; continue; } - bool isAvailable { true }; - float availabilityProgress { 0.0f }; - for (auto& handler : _backupHandlers) { - bool handlerIsAvailable { true }; - float progress { 0.0f }; - std::tie(handlerIsAvailable, progress) = handler->isAvailable(fileName); - isAvailable &= handlerIsAvailable; - availabilityProgress += progress / _backupHandlers.size(); - } - backups.emplace_back(fileInfo.fileName(), name, fileInfo.absoluteFilePath(), createdAt, type == MANUAL_BACKUP_PREFIX); } @@ -448,35 +464,6 @@ void DomainContentBackupManager::removeOldBackupVersions(const BackupRule& rule) } } -void DomainContentBackupManager::load() { - auto backups = getAllBackups(); - for (auto& backup : backups) { - QFile backupFile { backup.absolutePath }; - if (!backupFile.open(QIODevice::ReadOnly)) { - qCritical() << "Could not open file:" << backup.absolutePath; - qCritical() << " ERROR:" << backupFile.errorString(); - continue; - } - - QuaZip zip { &backupFile }; - if (!zip.open(QuaZip::mdUnzip)) { - qCritical() << "Could not open backup archive:" << backup.absolutePath; - qCritical() << " ERROR:" << zip.getZipError(); - continue; - } - - for (auto& handler : _backupHandlers) { - handler->loadBackup(backup.id, zip); - } - - zip.close(); - } - - for (auto& handler : _backupHandlers) { - handler->loadingComplete(); - } -} - void DomainContentBackupManager::backup() { auto nowDateTime = QDateTime::currentDateTime(); auto nowSeconds = nowDateTime.toSecsSinceEpoch(); diff --git a/domain-server/src/DomainContentBackupManager.h b/domain-server/src/DomainContentBackupManager.h index 75f0f1341c..fbc8084ac6 100644 --- a/domain-server/src/DomainContentBackupManager.h +++ b/domain-server/src/DomainContentBackupManager.h @@ -25,6 +25,8 @@ #include +#include + struct BackupItemInfo { BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) : id(pId), name(pName), absolutePath(pAbsolutePath), createdAt(pCreatedAt), isManualBackup(pIsManualBackup) { }; @@ -48,11 +50,11 @@ public: qint64 lastBackupSeconds; }; - static const int DEFAULT_PERSIST_INTERVAL; + static const std::chrono::seconds DEFAULT_PERSIST_INTERVAL; DomainContentBackupManager(const QString& rootBackupDirectory, const QVariantList& settings, - int persistInterval = DEFAULT_PERSIST_INTERVAL, + std::chrono::milliseconds persistInterval = DEFAULT_PERSIST_INTERVAL, bool debugTimestampNow = false); std::vector getAllBackups(); @@ -78,7 +80,6 @@ protected: virtual bool process() override; virtual void shutdown() override; - void load(); void backup(); void removeOldBackupVersions(const BackupRule& rule); void refreshBackupRules(); @@ -93,12 +94,12 @@ protected: private: const QString _backupDirectory; std::vector _backupHandlers; - int _persistInterval { 0 }; + std::chrono::milliseconds _persistInterval { 0 }; std::atomic _isRecovering { false }; QString _recoveryFilename { }; - int64_t _lastCheck { 0 }; + p_high_resolution_clock::time_point _lastCheck; std::vector _backupRules; }; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0aace84aef..d2ef1a4156 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -53,7 +53,7 @@ #include -#include +#include Q_LOGGING_CATEGORY(domain_server, "hifi.domain_server") @@ -1744,9 +1744,9 @@ void DomainServer::processOctreeDataPersistMessage(QSharedPointerwritePrimitive(false); @@ -3343,8 +3343,8 @@ void DomainServer::setupGroupCacheRefresh() { void DomainServer::maybeHandleReplacementEntityFile() { const auto replacementFilePath = getEntitiesReplacementFilePath(); - OctreeUtils::RawOctreeData data; - if (!OctreeUtils::readOctreeDataInfoFromFile(replacementFilePath, &data)) { + OctreeUtils::RawEntityData data; + if (!data.readOctreeDataInfoFromFile(replacementFilePath)) { qCWarning(domain_server) << "Replacement file could not be read, it either doesn't exist or is invalid."; } else { qCDebug(domain_server) << "Replacing existing entity date with replacement file"; @@ -3353,8 +3353,7 @@ void DomainServer::maybeHandleReplacementEntityFile() { if (!replacementFile.remove()) { // If we can't remove the replacement file, we are at risk of getting into a state where // we continually replace the primary entity file with the replacement entity file. - qCWarning(domain_server) - << "Unable to remove replacement file, bailing"; + qCWarning(domain_server) << "Unable to remove replacement file, bailing"; } else { data.resetIdAndVersion(); auto gzippedData = data.toGzippedByteArray(); @@ -3381,8 +3380,8 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { jsonOctree = compressedOctree; } - OctreeUtils::RawOctreeData data; - if (OctreeUtils::readOctreeDataInfoFromData(jsonOctree, &data)) { + OctreeUtils::RawEntityData data; + if (data.readOctreeDataInfoFromData(jsonOctree)) { data.resetIdAndVersion(); gzip(data.toByteArray(), compressedOctree); diff --git a/domain-server/src/EntitiesBackupHandler.cpp b/domain-server/src/EntitiesBackupHandler.cpp index e15e8c5419..599a730107 100644 --- a/domain-server/src/EntitiesBackupHandler.cpp +++ b/domain-server/src/EntitiesBackupHandler.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include EntitiesBackupHandler::EntitiesBackupHandler(QString entitiesFilePath, QString entitiesReplacementFilePath) : _entitiesFilePath(entitiesFilePath), @@ -31,8 +31,16 @@ void EntitiesBackupHandler::createBackup(const QString& backupName, QuaZip& zip) if (entitiesFile.open(QIODevice::ReadOnly)) { QuaZipFile zipFile { &zip }; - zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ENTITIES_BACKUP_FILENAME, _entitiesFilePath)); - zipFile.write(entitiesFile.readAll()); + if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ENTITIES_BACKUP_FILENAME, _entitiesFilePath))) { + qCritical().nospace() << "Failed to open " << ENTITIES_BACKUP_FILENAME << " for writing in zip"; + return; + } + auto entityData = entitiesFile.readAll(); + if (zipFile.write(entityData) != entityData.size()) { + qCritical() << "Failed to write entities file to backup"; + zipFile.close(); + return; + } zipFile.close(); if (zipFile.getZipError() != UNZ_OK) { qCritical().nospace() << "Failed to zip " << ENTITIES_BACKUP_FILENAME << ": " << zipFile.getZipError(); @@ -54,8 +62,8 @@ void EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip zipFile.close(); - OctreeUtils::RawOctreeData data; - if (!OctreeUtils::readOctreeDataInfoFromData(rawData, &data)) { + OctreeUtils::RawEntityData data; + if (!data.readOctreeDataInfoFromData(rawData)) { qCritical() << "Unable to parse octree data during backup recovery"; return; } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d62cbad765..334299185e 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1816,8 +1816,6 @@ bool Octree::toGzippedJSON(QByteArray* data, const OctreeElementPointer& element if (!gzip(jsonData, *data, -1)) { qCritical("Unable to gzip data while saving to json."); return false; - } else { - qDebug() <<"Did gzip!"; } return true; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 8954e53f8b..cb281593b1 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,6 +28,7 @@ #include "OctreeElementBag.h" #include "OctreePacketData.h" #include "OctreeSceneStats.h" +#include "OctreeUtils.h" class ReadBitstreamToTreeParams; class Octree; @@ -328,7 +329,7 @@ public: virtual void dumpTree() { } virtual void pruneTree() { } - void setEntityVersionInfo(QUuid id, int64_t dataVersion) { + void setOctreeVersionInfo(QUuid id, int64_t dataVersion) { _persistID = id; _persistDataVersion = dataVersion; } diff --git a/libraries/octree/src/OctreeDataUtils.cpp b/libraries/octree/src/OctreeDataUtils.cpp new file mode 100644 index 0000000000..9c965a128b --- /dev/null +++ b/libraries/octree/src/OctreeDataUtils.cpp @@ -0,0 +1,128 @@ +// +// OctreeDataUtils.cpp +// libraries/octree/src +// +// Created by Ryan Huffman 2018-02-26 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +#include "OctreeDataUtils.h" + +#include +#include + +#include +#include +#include +#include + +// Reads octree file and parses it into a QJsonDocument. Handles both gzipped and non-gzipped files. +// Returns true if the file was successfully opened and parsed, otherwise false. +// Example failures: file does not exist, gzipped file cannot be unzipped, invalid JSON. +bool readOctreeFile(QString path, QJsonDocument* doc) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + qCritical() << "Cannot open json file for reading: " << path; + return false; + } + + QByteArray data = file.readAll(); + QByteArray jsonData; + + if (!gunzip(data, jsonData)) { + jsonData = data; + } + + *doc = QJsonDocument::fromJson(jsonData); + return !doc->isNull(); +} + +bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromJSON(QJsonObject root) { + if (root.contains("Id") && root.contains("DataVersion")) { + id = root["Id"].toVariant().toUuid(); + version = root["DataVersion"].toInt(); + } + readSubclassData(root); + return true; +} + +bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromData(QByteArray data) { + QByteArray jsonData; + if (gunzip(data, jsonData)) { + data = jsonData; + } + + auto doc = QJsonDocument::fromJson(data); + if (doc.isNull()) { + return false; + } + + auto root = doc.object(); + return readOctreeDataInfoFromJSON(root); +} + +// Reads octree file and parses it into a RawOctreeData object. +// Returns false if readOctreeFile fails. +bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromFile(QString path) { + QJsonDocument doc; + if (!readOctreeFile(path, &doc)) { + return false; + } + + auto root = doc.object(); + return readOctreeDataInfoFromJSON(root); +} + +QByteArray OctreeUtils::RawOctreeData::toByteArray() { + const auto protocolVersion = (int)versionForPacketType((PacketTypeEnum::Value)dataPacketType()); + QJsonObject obj { + { "DataVersion", QJsonValue((qint64)version) }, + { "Id", QJsonValue(id.toString()) }, + { "Version", protocolVersion }, + }; + + writeSubclassData(obj); + + QJsonDocument doc; + doc.setObject(obj); + + return doc.toJson(); +} + +QByteArray OctreeUtils::RawOctreeData::toGzippedByteArray() { + auto data = toByteArray(); + QByteArray gzData; + + if (!gzip(data, gzData, -1)) { + qCritical("Unable to gzip data while converting json."); + return QByteArray(); + } + + return gzData; +} + +PacketType OctreeUtils::RawOctreeData::dataPacketType() const { + Q_ASSERT(false); + qCritical() << "Attemping to read packet type for incomplete base type 'RawOctreeData'"; + return (PacketType)0; +} + +void OctreeUtils::RawOctreeData::resetIdAndVersion() { + id = QUuid::createUuid(); + version = OctreeUtils::INITIAL_VERSION; + qDebug() << "Reset octree data to: " << id << version; +} + +void OctreeUtils::RawEntityData::readSubclassData(QJsonObject root) { + if (root.contains("Entities")) { + entityData = root["Entities"].toArray(); + } +} + +void OctreeUtils::RawEntityData::writeSubclassData(QJsonObject root) const { + root["Entities"] = entityData; +} + +PacketType OctreeUtils::RawEntityData::dataPacketType() const { return PacketType::EntityData; } \ No newline at end of file diff --git a/libraries/octree/src/OctreeDataUtils.h b/libraries/octree/src/OctreeDataUtils.h new file mode 100644 index 0000000000..ba70f3d079 --- /dev/null +++ b/libraries/octree/src/OctreeDataUtils.h @@ -0,0 +1,57 @@ +// +// OctreeDataUtils.h +// libraries/octree/src +// +// Created by Ryan Huffman 2018-02-26 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +#ifndef hifi_OctreeDataUtils_h +#define hifi_OctreeDataUtils_h + +#include + +#include +#include +#include + +namespace OctreeUtils { + +using Version = int64_t; +constexpr Version INITIAL_VERSION = 0; + +//using PacketType = uint8_t; + +// RawOctreeData is an intermediate format between JSON and a fully deserialized Octree. +class RawOctreeData { +public: + QUuid id { QUuid() }; + Version version { -1 }; + + virtual PacketType dataPacketType() const; + + virtual void readSubclassData(QJsonObject root) { } + virtual void writeSubclassData(QJsonObject root) const { } + + void resetIdAndVersion(); + QByteArray toByteArray(); + QByteArray toGzippedByteArray(); + + bool readOctreeDataInfoFromData(QByteArray data); + bool readOctreeDataInfoFromFile(QString path); + bool readOctreeDataInfoFromJSON(QJsonObject root); +}; + +class RawEntityData : public RawOctreeData { + PacketType dataPacketType() const override; + void readSubclassData(QJsonObject root) override; + void writeSubclassData(QJsonObject root) const override; + + QJsonArray entityData; +}; + +} + +#endif // hifi_OctreeDataUtils_h \ No newline at end of file diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index a669b7d3bb..23d6b6c2aa 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -32,6 +32,7 @@ #include "OctreeLogging.h" #include "OctreePersistThread.h" #include "OctreeUtils.h" +#include "OctreeDataUtils.h" const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds @@ -176,9 +177,9 @@ bool OctreePersistThread::process() { } OctreeUtils::RawOctreeData data; - if (OctreeUtils::readOctreeDataInfoFromFile(_filename, &data)) { + if (data.readOctreeDataInfoFromFile(_filename)) { qDebug() << "Setting entity version info to: " << data.id << data.version; - _tree->setEntityVersionInfo(data.id, data.version); + _tree->setOctreeVersionInfo(data.id, data.version); } bool persistentFileRead; diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index 3fdad2c3f7..bde207001f 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -35,7 +35,7 @@ public: OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory, int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false, const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, - QString persistAsFileType="json.gz", const QByteArray& replacementData = QByteArray()); + QString persistAsFileType = "json.gz", const QByteArray& replacementData = QByteArray()); bool isInitialLoadComplete() const { return _initialLoadComplete; } quint64 getLoadElapsedTime() const { return _loadTimeUSecs; } diff --git a/libraries/octree/src/OctreeUtils.cpp b/libraries/octree/src/OctreeUtils.cpp index 739c2661b3..8980504431 100644 --- a/libraries/octree/src/OctreeUtils.cpp +++ b/libraries/octree/src/OctreeUtils.cpp @@ -16,11 +16,6 @@ #include #include -#include - -#include -#include -#include float calculateRenderAccuracy(const glm::vec3& position, const AABox& bounds, @@ -78,95 +73,4 @@ float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust // Smallest visible element is 1cm const float smallestSize = 0.01f; return (smallestSize * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale); -} - -// Reads octree file and parses it into a QJsonDocument. Handles both gzipped and non-gzipped files. -// Returns true if the file was successfully opened and parsed, otherwise false. -// Example failures: file does not exist, gzipped file cannot be unzipped, invalid JSON. -bool OctreeUtils::readOctreeFile(QString path, QJsonDocument* doc) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Cannot open json file for reading: " << path; - return false; - } - - QByteArray data = file.readAll(); - QByteArray jsonData; - - if (!gunzip(data, jsonData)) { - jsonData = data; - } - - *doc = QJsonDocument::fromJson(jsonData); - return !doc->isNull(); -} - -bool readOctreeDataInfoFromJSON(QJsonObject root, OctreeUtils::RawOctreeData* octreeData) { - if (root.contains("Id") && root.contains("DataVersion")) { - octreeData->id = root["Id"].toVariant().toUuid(); - octreeData->version = root["DataVersion"].toInt(); - } - if (root.contains("Entities")) { - octreeData->octreeData = root["Entities"].toArray(); - } - return true; -} - -bool OctreeUtils::readOctreeDataInfoFromData(QByteArray data, OctreeUtils::RawOctreeData* octreeData) { - QByteArray jsonData; - if (gunzip(data, jsonData)) { - data = jsonData; - } - - auto doc = QJsonDocument::fromJson(data); - if (doc.isNull()) { - return false; - } - - auto root = doc.object(); - return readOctreeDataInfoFromJSON(root, octreeData); -} - -// Reads octree file and parses it into a RawOctreeData object. -// Returns false if readOctreeFile fails. -bool OctreeUtils::readOctreeDataInfoFromFile(QString path, OctreeUtils::RawOctreeData* octreeData) { - QJsonDocument doc; - if (!OctreeUtils::readOctreeFile(path, &doc)) { - return false; - } - - auto root = doc.object(); - return readOctreeDataInfoFromJSON(root, octreeData); -} - -QByteArray OctreeUtils::RawOctreeData::toByteArray() { - QJsonObject obj { - { "DataVersion", QJsonValue((qint64)version) }, - { "Id", QJsonValue(id.toString()) }, - { "Version", QJsonValue(5) }, - { "Entities", octreeData } - }; - - QJsonDocument doc; - doc.setObject(obj); - - return doc.toJson(); -} - -QByteArray OctreeUtils::RawOctreeData::toGzippedByteArray() { - auto data = toByteArray(); - QByteArray gzData; - - if (!gzip(data, gzData, -1)) { - qCritical("Unable to gzip data while converting json."); - return QByteArray(); - } - - return gzData; -} - -void OctreeUtils::RawOctreeData::resetIdAndVersion() { - id = QUuid::createUuid(); - version = OctreeUtils::INITIAL_VERSION; - qDebug() << "Reset octree data to: " << id << version; } \ No newline at end of file diff --git a/libraries/octree/src/OctreeUtils.h b/libraries/octree/src/OctreeUtils.h index 6fb0e62bcb..d5008376ea 100644 --- a/libraries/octree/src/OctreeUtils.h +++ b/libraries/octree/src/OctreeUtils.h @@ -14,36 +14,9 @@ #include "OctreeConstants.h" -#include -#include - class AABox; class QJsonDocument; -namespace OctreeUtils { - -using Version = int64_t; -constexpr Version INITIAL_VERSION = 0; - -// RawOctreeData is an intermediate format between JSON and a fully deserialized Octree. -class RawOctreeData { -public: - QUuid id { QUuid() }; - Version version { -1 }; - - QJsonArray octreeData; - - void resetIdAndVersion(); - QByteArray toByteArray(); - QByteArray toGzippedByteArray(); -}; - -bool readOctreeFile(QString path, QJsonDocument* doc); -bool readOctreeDataInfoFromData(QByteArray data, RawOctreeData* octreeData); -bool readOctreeDataInfoFromFile(QString path, RawOctreeData* octreeData); - -} - /// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple /// level it returns 0.0f for things that are so small for the current settings that they could not be visible. float calculateRenderAccuracy(const glm::vec3& position, diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 50655820af..230b9590f1 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -37,8 +37,6 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { // match the thread name to our object name _thread->setObjectName(objectName()); - // when the worker thread is started, call our engine's run.. - connect(_thread, &QThread::started, this, &GenericThread::started); connect(_thread, &QThread::started, this, &GenericThread::threadRoutine); connect(_thread, &QThread::finished, this, &GenericThread::finished);