mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 18:55:01 +02:00
Merge pull request #12501 from huffman/feat/content-settings
Code review changes
This commit is contained in:
commit
2af0e5fc2b
14 changed files with 265 additions and 212 deletions
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
128
libraries/octree/src/OctreeDataUtils.cpp
Normal file
128
libraries/octree/src/OctreeDataUtils.cpp
Normal 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; }
|
57
libraries/octree/src/OctreeDataUtils.h
Normal file
57
libraries/octree/src/OctreeDataUtils.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue