mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 05:33:55 +02:00
Merge remote-tracking branch 'upstream/master' into demo_movement
This commit is contained in:
commit
0d42920f1b
8 changed files with 127 additions and 22 deletions
assignment-client/src/octree
domain-server/resources
interface/src
libraries
|
@ -1063,6 +1063,12 @@ void OctreeServer::readConfiguration() {
|
|||
_wantBackup = !noBackup;
|
||||
qDebug() << "wantBackup=" << _wantBackup;
|
||||
|
||||
if (!readOptionString("backupDirectoryPath", settingsSectionObject, _backupDirectoryPath)) {
|
||||
_backupDirectoryPath = "";
|
||||
}
|
||||
|
||||
qDebug() << "backupDirectoryPath=" << _backupDirectoryPath;
|
||||
|
||||
readOptionBool(QString("persistFileDownload"), settingsSectionObject, _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 there is, let's copy it over to our target persist directory
|
||||
QDir persistPath { _persistFilePath };
|
||||
QString absoluteFilePath = persistPath.absolutePath();
|
||||
QString persistAbsoluteFilePath = persistPath.absolutePath();
|
||||
|
||||
if (persistPath.isRelative()) {
|
||||
// if the domain settings passed us a relative path, make an absolute path that is relative to the
|
||||
// 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";
|
||||
|
||||
// force the persist file to end with .json.gz
|
||||
if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
|
||||
absoluteFilePath += ENTITY_PERSIST_EXTENSION;
|
||||
if (!persistAbsoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
|
||||
persistAbsoluteFilePath += ENTITY_PERSIST_EXTENSION;
|
||||
} else {
|
||||
// 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";
|
||||
|
||||
static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz";
|
||||
|
@ -1204,7 +1210,7 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
pathToCopyFrom = oldDefaultPersistPath;
|
||||
}
|
||||
|
||||
QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") };
|
||||
QDir persistFileDirectory { QDir::cleanPath(persistAbsoluteFilePath + "/..") };
|
||||
|
||||
if (!persistFileDirectory.exists()) {
|
||||
qDebug() << "Creating data directory " << persistFileDirectory.absolutePath();
|
||||
|
@ -1212,16 +1218,46 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
_persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval,
|
||||
_persistThread = new OctreePersistThread(_tree, persistAbsoluteFilePath, _backupDirectoryPath, _persistInterval,
|
||||
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
|
||||
_persistThread->initialize(true);
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@ protected:
|
|||
|
||||
QString _persistFilePath;
|
||||
QString _persistAsFileType;
|
||||
QString _backupDirectoryPath;
|
||||
int _packetsPerClientPerInterval;
|
||||
int _packetsTotalPerInterval;
|
||||
OctreePointer _tree; // this IS a reaveraging tree
|
||||
|
|
|
@ -1108,6 +1108,14 @@
|
|||
"default": "models.json.gz",
|
||||
"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",
|
||||
"label": "Save Check Interval",
|
||||
|
|
|
@ -1138,10 +1138,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
static int SEND_STATS_INTERVAL_MS = 10000;
|
||||
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
|
||||
QTimer* sendStatsTimer = new QTimer(this);
|
||||
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
|
||||
connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
|
||||
|
||||
QJsonObject properties = {};
|
||||
MemoryInfo memInfo;
|
||||
if (getMemoryInfo(memInfo)) {
|
||||
|
@ -1183,6 +1189,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
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);
|
||||
});
|
||||
sendStatsTimer->start();
|
||||
|
|
|
@ -40,6 +40,12 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
|||
getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::resetActivityTracking() {
|
||||
_activityTracking.addedEntityCount = 0;
|
||||
_activityTracking.deletedEntityCount = 0;
|
||||
_activityTracking.editedEntityCount = 0;
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::canAdjustLocks() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
return nodeList->isAllowedEditor();
|
||||
|
@ -162,6 +168,8 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
|
|||
|
||||
|
||||
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {
|
||||
_activityTracking.addedEntityCount++;
|
||||
|
||||
EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties);
|
||||
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,
|
||||
bool dynamic, const glm::vec3& position, const glm::vec3& gravity) {
|
||||
_activityTracking.addedEntityCount++;
|
||||
|
||||
EntityItemProperties properties;
|
||||
properties.setType(EntityTypes::Model);
|
||||
properties.setName(name);
|
||||
|
@ -295,6 +305,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
|
|||
}
|
||||
|
||||
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
|
||||
_activityTracking.editedEntityCount++;
|
||||
|
||||
EntityItemProperties properties = scriptSideProperties;
|
||||
|
||||
auto dimensions = properties.getDimensions();
|
||||
|
@ -438,6 +450,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
}
|
||||
|
||||
void EntityScriptingInterface::deleteEntity(QUuid id) {
|
||||
_activityTracking.deletedEntityCount++;
|
||||
|
||||
EntityItemID entityID(id);
|
||||
bool shouldDelete = true;
|
||||
|
||||
|
|
|
@ -65,6 +65,13 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende
|
|||
public:
|
||||
EntityScriptingInterface(bool bidOnSimulationOwnership);
|
||||
|
||||
class ActivityTracking {
|
||||
public:
|
||||
int addedEntityCount { 0 };
|
||||
int deletedEntityCount { 0 };
|
||||
int editedEntityCount { 0 };
|
||||
};
|
||||
|
||||
EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); }
|
||||
virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; }
|
||||
virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); }
|
||||
|
@ -73,6 +80,9 @@ public:
|
|||
EntityTreePointer getEntityTree() { return _entityTree; }
|
||||
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine);
|
||||
float calculateCost(float mass, float oldVelocity, float newVelocity);
|
||||
|
||||
void resetActivityTracking();
|
||||
ActivityTracking getActivityTracking() const { return _activityTracking; }
|
||||
public slots:
|
||||
|
||||
// returns true if the DomainServer will allow this Node/Avatar to make changes
|
||||
|
@ -226,6 +236,8 @@ private:
|
|||
float _currentAvatarEnergy = { FLT_MAX };
|
||||
float getCurrentAvatarEnergy() { return _currentAvatarEnergy; }
|
||||
void setCurrentAvatarEnergy(float energy);
|
||||
|
||||
ActivityTracking _activityTracking;
|
||||
|
||||
float costMultiplier = { 0.01f };
|
||||
float getCostMultiplier();
|
||||
|
|
|
@ -34,11 +34,12 @@
|
|||
|
||||
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,
|
||||
QString persistAsFileType) :
|
||||
_tree(tree),
|
||||
_filename(filename),
|
||||
_backupDirectory(backupDirectory),
|
||||
_persistInterval(persistInterval),
|
||||
_initialLoadComplete(false),
|
||||
_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
|
||||
QFileInfo persistFileInfo(_filename);
|
||||
QString path = persistFileInfo.path();
|
||||
QString path = _backupDirectory;
|
||||
QString fileNamePart = persistFileInfo.fileName();
|
||||
|
||||
QStringList filters;
|
||||
|
@ -369,10 +370,12 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
|
|||
if (rule.maxBackupVersions > 0) {
|
||||
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
|
||||
QString backupMaxExtensionN = rule.extensionFormat;
|
||||
backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
|
||||
QString backupMaxFilenameN = _filename + backupMaxExtensionN;
|
||||
QString backupMaxFilenameN = backupFileName + backupMaxExtensionN;
|
||||
QFile backupMaxFileN(backupMaxFilenameN);
|
||||
if (backupMaxFileN.exists()) {
|
||||
int result = remove(qPrintable(backupMaxFilenameN));
|
||||
|
@ -387,8 +390,8 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
|
|||
backupExtensionN.replace(QString("%N"), QString::number(n));
|
||||
backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1));
|
||||
|
||||
QString backupFilenameN = findMostRecentFileExtension(_filename, PERSIST_EXTENSIONS) + backupExtensionN;
|
||||
QString backupFilenameNplusOne = _filename + backupExtensionNplusOne;
|
||||
QString backupFilenameN = findMostRecentFileExtension(backupFileName, PERSIST_EXTENSIONS) + backupExtensionN;
|
||||
QString backupFilenameNplusOne = backupFileName + backupExtensionNplusOne;
|
||||
|
||||
QFile backupFileN(backupFilenameN);
|
||||
|
||||
|
@ -434,21 +437,20 @@ void OctreePersistThread::backup() {
|
|||
|
||||
struct tm* localTime = localtime(&_lastPersistTime);
|
||||
|
||||
QString backupFileName;
|
||||
QString backupFileName = _backupDirectory + "/" + QUrl(_filename).fileName();
|
||||
|
||||
// check to see if they asked for version rolling format
|
||||
if (rule.extensionFormat.contains("%N")) {
|
||||
rollOldBackupVersions(rule); // rename all the old backup files accordingly
|
||||
QString backupExtension = rule.extensionFormat;
|
||||
backupExtension.replace(QString("%N"), QString("1"));
|
||||
backupFileName = _filename + backupExtension;
|
||||
backupFileName += backupExtension;
|
||||
} else {
|
||||
char backupExtension[256];
|
||||
strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime);
|
||||
backupFileName = _filename + backupExtension;
|
||||
backupFileName += backupExtension;
|
||||
}
|
||||
|
||||
|
||||
if (rule.maxBackupVersions > 0) {
|
||||
QFile persistFile(_filename);
|
||||
if (persistFile.exists()) {
|
||||
|
|
|
@ -33,9 +33,9 @@ public:
|
|||
|
||||
static const int DEFAULT_PERSIST_INTERVAL;
|
||||
|
||||
OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL,
|
||||
bool wantBackup = false, const QJsonObject& settings = QJsonObject(),
|
||||
bool debugTimestampNow = false, QString persistAsFileType="svo");
|
||||
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="svo");
|
||||
|
||||
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
||||
quint64 getLoadElapsedTime() const { return _loadTimeUSecs; }
|
||||
|
@ -64,6 +64,7 @@ protected:
|
|||
private:
|
||||
OctreePointer _tree;
|
||||
QString _filename;
|
||||
QString _backupDirectory;
|
||||
int _persistInterval;
|
||||
bool _initialLoadComplete;
|
||||
|
||||
|
|
Loading…
Reference in a new issue