Merge remote-tracking branch 'upstream/master' into demo_movement

This commit is contained in:
James B. Pollack 2016-08-19 16:45:44 -07:00
commit 0d42920f1b
8 changed files with 127 additions and 22 deletions

View file

@ -1063,6 +1063,12 @@ void OctreeServer::readConfiguration() {
_wantBackup = !noBackup; _wantBackup = !noBackup;
qDebug() << "wantBackup=" << _wantBackup; qDebug() << "wantBackup=" << _wantBackup;
if (!readOptionString("backupDirectoryPath", settingsSectionObject, _backupDirectoryPath)) {
_backupDirectoryPath = "";
}
qDebug() << "backupDirectoryPath=" << _backupDirectoryPath;
readOptionBool(QString("persistFileDownload"), settingsSectionObject, _persistFileDownload); readOptionBool(QString("persistFileDownload"), settingsSectionObject, _persistFileDownload);
qDebug() << "persistFileDownload=" << _persistFileDownload; qDebug() << "persistFileDownload=" << _persistFileDownload;
@ -1160,25 +1166,25 @@ void OctreeServer::domainSettingsRequestComplete() {
// If persist filename does not exist, let's see if there is one beside the application binary // 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 // If there is, let's copy it over to our target persist directory
QDir persistPath { _persistFilePath }; QDir persistPath { _persistFilePath };
QString absoluteFilePath = persistPath.absolutePath(); QString persistAbsoluteFilePath = persistPath.absolutePath();
if (persistPath.isRelative()) { if (persistPath.isRelative()) {
// if the domain settings passed us a relative path, make an absolute path that is relative to the // if the domain settings passed us a relative path, make an absolute path that is relative to the
// default data directory // default data directory
absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); persistAbsoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath);
} }
static const QString ENTITY_PERSIST_EXTENSION = ".json.gz"; static const QString ENTITY_PERSIST_EXTENSION = ".json.gz";
// force the persist file to end with .json.gz // force the persist file to end with .json.gz
if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) { if (!persistAbsoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
absoluteFilePath += ENTITY_PERSIST_EXTENSION; persistAbsoluteFilePath += ENTITY_PERSIST_EXTENSION;
} else { } else {
// make sure the casing of .json.gz is correct // make sure the casing of .json.gz is correct
absoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive); persistAbsoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive);
} }
if (!QFile::exists(absoluteFilePath)) { if (!QFile::exists(persistAbsoluteFilePath)) {
qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; qDebug() << "Persist file does not exist, checking for existence of persist file next to application";
static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz"; static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz";
@ -1204,7 +1210,7 @@ void OctreeServer::domainSettingsRequestComplete() {
pathToCopyFrom = oldDefaultPersistPath; pathToCopyFrom = oldDefaultPersistPath;
} }
QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") }; QDir persistFileDirectory { QDir::cleanPath(persistAbsoluteFilePath + "/..") };
if (!persistFileDirectory.exists()) { if (!persistFileDirectory.exists()) {
qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); qDebug() << "Creating data directory " << persistFileDirectory.absolutePath();
@ -1212,16 +1218,46 @@ void OctreeServer::domainSettingsRequestComplete() {
} }
if (shouldCopy) { if (shouldCopy) {
qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << absoluteFilePath; qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistAbsoluteFilePath;
QFile::copy(pathToCopyFrom, absoluteFilePath); QFile::copy(pathToCopyFrom, persistAbsoluteFilePath);
} else { } else {
qDebug() << "No existing persist file found"; qDebug() << "No existing persist file found";
} }
} }
auto persistFileDirectory = QFileInfo(persistAbsoluteFilePath).absolutePath();
if (_backupDirectoryPath.isEmpty()) {
// Use the persist file's directory to store backups
_backupDirectoryPath = persistFileDirectory;
} else {
// The backup directory has been set.
// If relative, make it relative to the entities directory in the application data directory
// If absolute, no resolution is necessary
QDir backupDirectory { _backupDirectoryPath };
QString absoluteBackupDirectory;
if (backupDirectory.isRelative()) {
absoluteBackupDirectory = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_backupDirectoryPath);
absoluteBackupDirectory = QDir(absoluteBackupDirectory).absolutePath();
} else {
absoluteBackupDirectory = backupDirectory.absolutePath();
}
backupDirectory = QDir(absoluteBackupDirectory);
if (!backupDirectory.exists()) {
if (backupDirectory.mkpath(".")) {
qDebug() << "Created backup directory";
} else {
qDebug() << "ERROR creating backup directory, using persist file directory";
_backupDirectoryPath = persistFileDirectory;
}
} else {
_backupDirectoryPath = absoluteBackupDirectory;
}
}
qDebug() << "Backups will be stored in: " << _backupDirectoryPath;
// now set up PersistThread // now set up PersistThread
_persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval, _persistThread = new OctreePersistThread(_tree, persistAbsoluteFilePath, _backupDirectoryPath, _persistInterval,
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType); _wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
_persistThread->initialize(true); _persistThread->initialize(true);
} }

View file

@ -172,6 +172,7 @@ protected:
QString _persistFilePath; QString _persistFilePath;
QString _persistAsFileType; QString _persistAsFileType;
QString _backupDirectoryPath;
int _packetsPerClientPerInterval; int _packetsPerClientPerInterval;
int _packetsTotalPerInterval; int _packetsTotalPerInterval;
OctreePointer _tree; // this IS a reaveraging tree OctreePointer _tree; // this IS a reaveraging tree

View file

@ -1108,6 +1108,14 @@
"default": "models.json.gz", "default": "models.json.gz",
"advanced": true "advanced": true
}, },
{
"name": "backupDirectoryPath",
"label": "Entities Backup Directory Path",
"help": "The path to the directory to store backups in.<br/>If this path is relative it will be relative to the application data directory.",
"placeholder": "",
"default": "",
"advanced": true
},
{ {
"name": "persistInterval", "name": "persistInterval",
"label": "Save Check Interval", "label": "Save Check Interval",

View file

@ -1138,10 +1138,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
static int SEND_STATS_INTERVAL_MS = 10000; static int SEND_STATS_INTERVAL_MS = 10000;
static int NEARBY_AVATAR_RADIUS_METERS = 10; static int NEARBY_AVATAR_RADIUS_METERS = 10;
static glm::vec3 lastAvatarPosition = getMyAvatar()->getPosition();
static glm::mat4 lastHMDHeadPose = getHMDSensorPose();
static controller::Pose lastLeftHandPose = getMyAvatar()->getLeftHandPose();
static controller::Pose lastRightHandPose = getMyAvatar()->getRightHandPose();
// Periodically send fps as a user activity event // Periodically send fps as a user activity event
QTimer* sendStatsTimer = new QTimer(this); QTimer* sendStatsTimer = new QTimer(this);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
connect(sendStatsTimer, &QTimer::timeout, this, [this]() { connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
QJsonObject properties = {}; QJsonObject properties = {};
MemoryInfo memInfo; MemoryInfo memInfo;
if (getMemoryInfo(memInfo)) { if (getMemoryInfo(memInfo)) {
@ -1183,6 +1189,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false; properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
glm::vec3 avatarPosition = getMyAvatar()->getPosition();
properties["avatar_has_moved"] = lastAvatarPosition != avatarPosition;
lastAvatarPosition = avatarPosition;
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entityActivityTracking = entityScriptingInterface->getActivityTracking();
entityScriptingInterface->resetActivityTracking();
properties["added_entity_cnt"] = entityActivityTracking.addedEntityCount;
properties["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount;
properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount;
auto hmdHeadPose = getHMDSensorPose();
properties["hmd_head_pose_changed"] = isHMDMode() && (hmdHeadPose != lastHMDHeadPose);
lastHMDHeadPose = hmdHeadPose;
auto leftHandPose = getMyAvatar()->getLeftHandPose();
auto rightHandPose = getMyAvatar()->getRightHandPose();
// controller::Pose considers two poses to be different if either are invalid. In our case, we actually
// want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first.
properties["hand_pose_changed"] =
((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose))
|| ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose));
lastLeftHandPose = leftHandPose;
lastRightHandPose = rightHandPose;
UserActivityLogger::getInstance().logAction("stats", properties); UserActivityLogger::getInstance().logAction("stats", properties);
}); });
sendStatsTimer->start(); sendStatsTimer->start();

View file

@ -40,6 +40,12 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties); getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);
} }
void EntityScriptingInterface::resetActivityTracking() {
_activityTracking.addedEntityCount = 0;
_activityTracking.deletedEntityCount = 0;
_activityTracking.editedEntityCount = 0;
}
bool EntityScriptingInterface::canAdjustLocks() { bool EntityScriptingInterface::canAdjustLocks() {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
return nodeList->isAllowedEditor(); return nodeList->isAllowedEditor();
@ -162,6 +168,8 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) { QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {
_activityTracking.addedEntityCount++;
EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties); EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties);
propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());
@ -232,6 +240,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType, QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType,
bool dynamic, const glm::vec3& position, const glm::vec3& gravity) { bool dynamic, const glm::vec3& position, const glm::vec3& gravity) {
_activityTracking.addedEntityCount++;
EntityItemProperties properties; EntityItemProperties properties;
properties.setType(EntityTypes::Model); properties.setType(EntityTypes::Model);
properties.setName(name); properties.setName(name);
@ -295,6 +305,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
} }
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
_activityTracking.editedEntityCount++;
EntityItemProperties properties = scriptSideProperties; EntityItemProperties properties = scriptSideProperties;
auto dimensions = properties.getDimensions(); auto dimensions = properties.getDimensions();
@ -438,6 +450,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
} }
void EntityScriptingInterface::deleteEntity(QUuid id) { void EntityScriptingInterface::deleteEntity(QUuid id) {
_activityTracking.deletedEntityCount++;
EntityItemID entityID(id); EntityItemID entityID(id);
bool shouldDelete = true; bool shouldDelete = true;

View file

@ -65,6 +65,13 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende
public: public:
EntityScriptingInterface(bool bidOnSimulationOwnership); EntityScriptingInterface(bool bidOnSimulationOwnership);
class ActivityTracking {
public:
int addedEntityCount { 0 };
int deletedEntityCount { 0 };
int editedEntityCount { 0 };
};
EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); } EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); }
virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; } virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; }
virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); } virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); }
@ -73,6 +80,9 @@ public:
EntityTreePointer getEntityTree() { return _entityTree; } EntityTreePointer getEntityTree() { return _entityTree; }
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine); void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine);
float calculateCost(float mass, float oldVelocity, float newVelocity); float calculateCost(float mass, float oldVelocity, float newVelocity);
void resetActivityTracking();
ActivityTracking getActivityTracking() const { return _activityTracking; }
public slots: public slots:
// returns true if the DomainServer will allow this Node/Avatar to make changes // returns true if the DomainServer will allow this Node/Avatar to make changes
@ -226,6 +236,8 @@ private:
float _currentAvatarEnergy = { FLT_MAX }; float _currentAvatarEnergy = { FLT_MAX };
float getCurrentAvatarEnergy() { return _currentAvatarEnergy; } float getCurrentAvatarEnergy() { return _currentAvatarEnergy; }
void setCurrentAvatarEnergy(float energy); void setCurrentAvatarEnergy(float energy);
ActivityTracking _activityTracking;
float costMultiplier = { 0.01f }; float costMultiplier = { 0.01f };
float getCostMultiplier(); float getCostMultiplier();

View file

@ -34,11 +34,12 @@
const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
OctreePersistThread::OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval, OctreePersistThread::OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory, int persistInterval,
bool wantBackup, const QJsonObject& settings, bool debugTimestampNow, bool wantBackup, const QJsonObject& settings, bool debugTimestampNow,
QString persistAsFileType) : QString persistAsFileType) :
_tree(tree), _tree(tree),
_filename(filename), _filename(filename),
_backupDirectory(backupDirectory),
_persistInterval(persistInterval), _persistInterval(persistInterval),
_initialLoadComplete(false), _initialLoadComplete(false),
_loadTimeUSecs(0), _loadTimeUSecs(0),
@ -316,7 +317,7 @@ bool OctreePersistThread::getMostRecentBackup(const QString& format,
// Based on our backup file name, determine the path and file name pattern for backup files // Based on our backup file name, determine the path and file name pattern for backup files
QFileInfo persistFileInfo(_filename); QFileInfo persistFileInfo(_filename);
QString path = persistFileInfo.path(); QString path = _backupDirectory;
QString fileNamePart = persistFileInfo.fileName(); QString fileNamePart = persistFileInfo.fileName();
QStringList filters; QStringList filters;
@ -369,10 +370,12 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
if (rule.maxBackupVersions > 0) { if (rule.maxBackupVersions > 0) {
qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "..."; qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";
QString backupFileName = _backupDirectory + "/" + QUrl(_filename).fileName();
// Delete maximum rolling file because rename() fails on Windows if target exists // Delete maximum rolling file because rename() fails on Windows if target exists
QString backupMaxExtensionN = rule.extensionFormat; QString backupMaxExtensionN = rule.extensionFormat;
backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions)); backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
QString backupMaxFilenameN = _filename + backupMaxExtensionN; QString backupMaxFilenameN = backupFileName + backupMaxExtensionN;
QFile backupMaxFileN(backupMaxFilenameN); QFile backupMaxFileN(backupMaxFilenameN);
if (backupMaxFileN.exists()) { if (backupMaxFileN.exists()) {
int result = remove(qPrintable(backupMaxFilenameN)); int result = remove(qPrintable(backupMaxFilenameN));
@ -387,8 +390,8 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
backupExtensionN.replace(QString("%N"), QString::number(n)); backupExtensionN.replace(QString("%N"), QString::number(n));
backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1)); backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1));
QString backupFilenameN = findMostRecentFileExtension(_filename, PERSIST_EXTENSIONS) + backupExtensionN; QString backupFilenameN = findMostRecentFileExtension(backupFileName, PERSIST_EXTENSIONS) + backupExtensionN;
QString backupFilenameNplusOne = _filename + backupExtensionNplusOne; QString backupFilenameNplusOne = backupFileName + backupExtensionNplusOne;
QFile backupFileN(backupFilenameN); QFile backupFileN(backupFilenameN);
@ -434,21 +437,20 @@ void OctreePersistThread::backup() {
struct tm* localTime = localtime(&_lastPersistTime); struct tm* localTime = localtime(&_lastPersistTime);
QString backupFileName; QString backupFileName = _backupDirectory + "/" + QUrl(_filename).fileName();
// check to see if they asked for version rolling format // check to see if they asked for version rolling format
if (rule.extensionFormat.contains("%N")) { if (rule.extensionFormat.contains("%N")) {
rollOldBackupVersions(rule); // rename all the old backup files accordingly rollOldBackupVersions(rule); // rename all the old backup files accordingly
QString backupExtension = rule.extensionFormat; QString backupExtension = rule.extensionFormat;
backupExtension.replace(QString("%N"), QString("1")); backupExtension.replace(QString("%N"), QString("1"));
backupFileName = _filename + backupExtension; backupFileName += backupExtension;
} else { } else {
char backupExtension[256]; char backupExtension[256];
strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime); strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime);
backupFileName = _filename + backupExtension; backupFileName += backupExtension;
} }
if (rule.maxBackupVersions > 0) { if (rule.maxBackupVersions > 0) {
QFile persistFile(_filename); QFile persistFile(_filename);
if (persistFile.exists()) { if (persistFile.exists()) {

View file

@ -33,9 +33,9 @@ public:
static const int DEFAULT_PERSIST_INTERVAL; static const int DEFAULT_PERSIST_INTERVAL;
OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory,
bool wantBackup = false, const QJsonObject& settings = QJsonObject(), int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false,
bool debugTimestampNow = false, QString persistAsFileType="svo"); const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, QString persistAsFileType="svo");
bool isInitialLoadComplete() const { return _initialLoadComplete; } bool isInitialLoadComplete() const { return _initialLoadComplete; }
quint64 getLoadElapsedTime() const { return _loadTimeUSecs; } quint64 getLoadElapsedTime() const { return _loadTimeUSecs; }
@ -64,6 +64,7 @@ protected:
private: private:
OctreePointer _tree; OctreePointer _tree;
QString _filename; QString _filename;
QString _backupDirectory;
int _persistInterval; int _persistInterval;
bool _initialLoadComplete; bool _initialLoadComplete;