Merge pull request #12501 from huffman/feat/content-settings

Code review changes
This commit is contained in:
Stephen Birarda 2018-02-26 17:58:08 -07:00 committed by GitHub
commit 2af0e5fc2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 265 additions and 212 deletions

View file

@ -33,7 +33,7 @@
#include <PathUtils.h>
#include <QtCore/QDir>
#include <OctreeUtils.h>
#include <OctreeDataUtils.h>
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<ReceivedMessage> 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();

View file

@ -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<BackupItemInfo> 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();

View file

@ -25,6 +25,8 @@
#include <shared/MiniPromises.h>
#include <PortableHighResolutionClock.h>
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<BackupItemInfo> 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<BackupHandlerPointer> _backupHandlers;
int _persistInterval { 0 };
std::chrono::milliseconds _persistInterval { 0 };
std::atomic<bool> _isRecovering { false };
QString _recoveryFilename { };
int64_t _lastCheck { 0 };
p_high_resolution_clock::time_point _lastCheck;
std::vector<BackupRule> _backupRules;
};

View file

@ -53,7 +53,7 @@
#include <Gzip.h>
#include <OctreeUtils.h>
#include <OctreeDataUtils.h>
Q_LOGGING_CATEGORY(domain_server, "hifi.domain_server")
@ -1744,9 +1744,9 @@ void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessag
QFile f(filePath);
if (f.open(QIODevice::WriteOnly)) {
f.write(data);
OctreeUtils::RawOctreeData octreeData;
if (OctreeUtils::readOctreeDataInfoFromData(data, &octreeData)) {
qCDebug(domain_server) << "Wrote new entities file" << octreeData.id << octreeData.version;
OctreeUtils::RawEntityData entityData;
if (entityData.readOctreeDataInfoFromData(data)) {
qCDebug(domain_server) << "Wrote new entities file" << entityData.id << entityData.version;
} else {
qCDebug(domain_server) << "Failed to read new octree data info";
}
@ -1792,8 +1792,8 @@ void DomainServer::processOctreeDataRequestMessage(QSharedPointer<ReceivedMessag
auto entityFilePath = getEntitiesFilePath();
auto reply = NLPacketList::create(PacketType::OctreeDataFileReply, QByteArray(), true, true);
OctreeUtils::RawOctreeData data;
if (OctreeUtils::readOctreeDataInfoFromFile(entityFilePath, &data)) {
OctreeUtils::RawEntityData data;
if (data.readOctreeDataInfoFromFile(entityFilePath)) {
if (data.id == id && data.version <= version) {
qCDebug(domain_server) << "ES has sufficient octree data, not sending data";
reply->writePrimitive(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);

View file

@ -16,7 +16,7 @@
#include <quazip5/quazip.h>
#include <quazip5/quazipfile.h>
#include <OctreeUtils.h>
#include <OctreeDataUtils.h>
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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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 <Gzip.h>
#include <udt/PacketHeaders.h>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFile>
// 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; }

View file

@ -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 <udt/PacketHeaders.h>
#include <QJsonObject>
#include <QUuid>
#include <QJsonArray>
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

View file

@ -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;

View file

@ -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; }

View file

@ -16,11 +16,6 @@
#include <glm/glm.hpp>
#include <AABox.h>
#include <Gzip.h>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFile>
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;
}

View file

@ -14,36 +14,9 @@
#include "OctreeConstants.h"
#include <QUuid>
#include <QJsonArray>
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,

View file

@ -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);