From 6d251c4cd3e661242962b7a0ea399eba2c1a62ec Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 3 May 2018 17:46:50 -0700 Subject: [PATCH 01/69] Bringing the work and refinment done in workload branch to master branch --- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/LightClusters.h | 2 +- .../render-utils/src/SubsurfaceScattering.h | 2 +- libraries/render/src/render/Item.h | 1 + libraries/task/src/task/Config.h | 35 ++++++++++++--- libraries/task/src/task/Task.h | 45 +++++++++++++++++-- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 3643e608ed..b3a93ab1de 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -181,7 +181,7 @@ class DebugAmbientOcclusionConfig : public render::Job::Config { Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: - DebugAmbientOcclusionConfig() : render::Job::Config(true) {} + DebugAmbientOcclusionConfig() : render::Job::Config(false) {} bool showCursorPixel{ false }; glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f }; diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index f495dabebb..fa054c304a 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -195,7 +195,7 @@ class DebugLightClustersConfig : public render::Job::Config { Q_PROPERTY(bool doDrawClusterFromDepth MEMBER doDrawClusterFromDepth NOTIFY dirty) Q_PROPERTY(bool doDrawContent MEMBER doDrawContent NOTIFY dirty) public: - DebugLightClustersConfig() : render::Job::Config(true){} + DebugLightClustersConfig() : render::Job::Config(false){} bool doDrawGrid{ false }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.h b/libraries/render-utils/src/SubsurfaceScattering.h index 30021fae40..780ce34d7f 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.h +++ b/libraries/render-utils/src/SubsurfaceScattering.h @@ -149,7 +149,7 @@ class DebugSubsurfaceScatteringConfig : public render::Job::Config { Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: - DebugSubsurfaceScatteringConfig() : render::Job::Config(true) {} + DebugSubsurfaceScatteringConfig() : render::Job::Config(false) {} bool showProfile{ false }; bool showLUT{ false }; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index e4dcc7ee03..b8a3fbf0f8 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -122,6 +122,7 @@ public: Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } + Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index 36dfb35f25..4ba1934643 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -12,6 +12,8 @@ #ifndef hifi_task_Config_h #define hifi_task_Config_h +#include + #include #include #include @@ -108,11 +110,19 @@ public: Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); } Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); } + Q_INVOKABLE QObject* getConfig(const QString& name) { return nullptr; } + // Running Time measurement // The new stats signal is emitted once per run time of a job when stats (cpu runtime) are updated - void setCPURunTime(double mstime) { _msCPURunTime = mstime; emit newStats(); } + void setCPURunTime(const std::chrono::nanoseconds& runtime) { _msCPURunTime = std::chrono::duration(runtime).count(); emit newStats(); } double getCPURunTime() const { return _msCPURunTime; } + // Describe the node graph data connections of the associated Job/Task + Q_INVOKABLE virtual bool isTask() const { return false; } + Q_INVOKABLE virtual QObjectList getSubConfigs() const { return QObjectList(); } + Q_INVOKABLE virtual int getNumSubs() const { return 0; } + Q_INVOKABLE virtual QObject* getSubConfig(int i) const { return nullptr; } + public slots: void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); } @@ -122,6 +132,8 @@ signals: void dirtyEnabled(); }; +using QConfigPointer = std::shared_ptr; + class TConfigProxy { public: using Config = JobConfig; @@ -134,11 +146,9 @@ public: using Persistent = PersistentConfig; - TaskConfig() = default ; + TaskConfig() = default; TaskConfig(bool enabled) : JobConfig(enabled) {} - - // Get a sub job config through task.getConfig(path) // where path can be: // - search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root) @@ -170,6 +180,21 @@ public: return root->findChild(tokens.front()); } + Q_INVOKABLE bool isTask() const override { return true; } + Q_INVOKABLE QObjectList getSubConfigs() const override { + auto list = findChildren(QRegExp(".*"), Qt::FindDirectChildrenOnly); + QObjectList returned; + for (int i = 0; i < list.size(); i++) { + returned.push_back(list[i]); + } + return returned; + } + Q_INVOKABLE int getNumSubs() const override { return getSubConfigs().size(); } + Q_INVOKABLE QObject* getSubConfig(int i) const override { + auto subs = getSubConfigs(); + return ((i < 0 || i >= subs.size()) ? nullptr : subs[i]); + } + void connectChildConfig(QConfigPointer childConfig, const std::string& name); void transferChildrenConfigs(QConfigPointer source); @@ -179,8 +204,6 @@ public slots: void refresh(); }; -using QConfigPointer = std::shared_ptr; - } #endif // hifi_task_Config_h diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 022dd99200..93dfdd85f4 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -80,10 +80,11 @@ public: virtual const Varying getInput() const { return Varying(); } virtual const Varying getOutput() const { return Varying(); } + virtual Varying& editInput() = 0; virtual QConfigPointer& getConfiguration() { return _config; } virtual void applyConfiguration() = 0; - void setCPURunTime(double mstime) { std::static_pointer_cast(_config)->setCPURunTime(mstime); } + void setCPURunTime(const std::chrono::nanoseconds& runtime) { std::static_pointer_cast(_config)->setCPURunTime(runtime); } QConfigPointer _config; protected: @@ -143,6 +144,10 @@ public: const Varying getInput() const override { return _input; } const Varying getOutput() const override { return _output; } + Varying& editInput() override { return _input; } + + template void feedInput(const I& in) { _concept->editInput().template edit() = in; } + template void feedInput(int index, const S& inS) { (_concept->editInput().template editN(index)).template edit() = inS; } template Model(const std::string& name, const Varying& input, QConfigPointer config, A&&... args) : @@ -201,11 +206,12 @@ public: PerformanceTimer perfTimer(getName().c_str()); // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str()); - auto start = usecTimestampNow(); + + auto startTime = std::chrono::high_resolution_clock::now(); _concept->run(jobContext); - _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); + _concept->setCPURunTime((std::chrono::high_resolution_clock::now() - startTime)); } protected: @@ -242,6 +248,8 @@ public: const Varying getInput() const override { return _input; } const Varying getOutput() const override { return _output; } + Varying& editInput() override { return _input; } + typename Jobs::iterator editJob(std::string name) { typename Jobs::iterator jobIt; for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { @@ -370,8 +378,36 @@ public: protected: }; -} +template +class Engine : public Task { +public: + using Context = JC; + using ContextPointer = std::shared_ptr; + using Config = TaskConfig; + using TaskType = Task; + using ConceptPointer = typename TaskType::ConceptPointer; + + Engine(ConceptPointer concept) : TaskType(concept) {} + ~Engine() = default; + + void reset(const ContextPointer& context) { _context = context; } + + void run() { + if (_context) { + run(_context); + } + } + +protected: + void run(const ContextPointer& jobContext) override { + TaskType::run(_context); + } + + ContextPointer _context; +}; + +} #define Task_DeclareTypeAliases(ContextType) \ using JobConfig = task::JobConfig; \ @@ -379,6 +415,7 @@ protected: template using PersistentConfig = task::PersistentConfig; \ using Job = task::Job; \ using Task = task::Task; \ + using _Engine = task::Engine; \ using Varying = task::Varying; \ template < typename T0, typename T1 > using VaryingSet2 = task::VaryingSet2; \ template < typename T0, typename T1, typename T2 > using VaryingSet3 = task::VaryingSet3; \ From e1d063e90880f1e885b29c2612fabb5172a9de70 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 4 May 2018 00:01:48 -0700 Subject: [PATCH 02/69] Adding the scripts for Jet --- scripts/developer/utilities/lib/jet/jet.js | 73 +++++++++++++++++++ .../utilities/lib/jet/qml/TaskList.qml | 48 ++++++++++++ .../developer/utilities/lib/jet/qml/qmldir | 1 + .../render/configSlider/ConfigSlider.qml | 40 ++++++---- .../utilities/render/deferredLighting.qml | 10 +++ 5 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 scripts/developer/utilities/lib/jet/jet.js create mode 100644 scripts/developer/utilities/lib/jet/qml/TaskList.qml create mode 100644 scripts/developer/utilities/lib/jet/qml/qmldir diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js new file mode 100644 index 0000000000..39da9b6d90 --- /dev/null +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -0,0 +1,73 @@ +// +// Job Engine & Task... +// jet.js +// +// Created by Sam Gateau, 2018/03/28 +// 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 +// +"use strict"; + + // traverse task tree +function task_traverse(root, functor, depth) { + // if (root.isTask()) { + depth++; + for (var i = 0; i Date: Fri, 4 May 2018 17:58:21 -0700 Subject: [PATCH 03/69] Templatizing the timeProfiler for the task --- libraries/render/src/render/Engine.h | 6 +- libraries/task/src/task/Task.cpp | 4 +- libraries/task/src/task/Task.h | 63 ++++++++++--------- .../utilities/render/deferredLighting.qml | 16 ++--- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 0271c71529..f444416a3f 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -25,7 +25,7 @@ namespace render { class RenderContext : public task::JobContext { public: - RenderContext() : task::JobContext(trace_render()) {} + RenderContext() : task::JobContext() {} virtual ~RenderContext() {} RenderArgs* args; @@ -33,7 +33,9 @@ namespace render { }; using RenderContextPointer = std::shared_ptr; - Task_DeclareTypeAliases(RenderContext) + Task_DeclareCategoryTimeProfilerClass(RenderTimeProfiler, trace_render); + + Task_DeclareTypeAliases(RenderContext, RenderTimeProfiler) // Versions of the COnfig integrating a gpu & batch timer class GPUJobConfig : public JobConfig { diff --git a/libraries/task/src/task/Task.cpp b/libraries/task/src/task/Task.cpp index 621d77d7bf..9123ef8b04 100644 --- a/libraries/task/src/task/Task.cpp +++ b/libraries/task/src/task/Task.cpp @@ -12,9 +12,7 @@ using namespace task; -JobContext::JobContext(const QLoggingCategory& category) : - profileCategory(category) { - assert(&category); +JobContext::JobContext() { } JobContext::~JobContext() { diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 93dfdd85f4..c9a3285443 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -15,20 +15,15 @@ #include "Config.h" #include "Varying.h" -#include "SettingHandle.h" - -#include -#include - namespace task { class JobConcept; -template class JobT; -template class TaskT; +template class JobT; +template class TaskT; class JobNoIO {}; // Task Flow control class is a simple per value object used to communicate flow control commands trhough the graph of tasks. -// From within the Job::Run function, you can access it from the JobCOntext and issue commands which will be picked up by the Task calling for the Job run. +// From within the Job::Run function, you can access it from the JobContext and issue commands which will be picked up by the Task calling for the Job run. // This is first introduced to provide a way to abort all the work from within a task job. see the "abortTask" call class TaskFlow { public: @@ -55,11 +50,10 @@ protected: // The JobContext can be derived to add more global state to it that Jobs can access class JobContext { public: - JobContext(const QLoggingCategory& category); + JobContext(); virtual ~JobContext(); std::shared_ptr jobConfig { nullptr }; - const QLoggingCategory& profileCategory; // Task flow control TaskFlow taskFlow{}; @@ -115,10 +109,11 @@ template void jobRun(T& data, const JC& jo data.run(jobContext, input, output); } -template +template class Job { public: using Context = JC; + using TimeProfiler = TP; using ContextPointer = std::shared_ptr; using Config = JobConfig; using None = JobNoIO; @@ -165,7 +160,7 @@ public: void applyConfiguration() override { - Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); + TimeProfiler probe(("configure::" + JobConcept::getName())); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); } @@ -203,14 +198,9 @@ public: } virtual void run(const ContextPointer& jobContext) { - PerformanceTimer perfTimer(getName().c_str()); - // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually - Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str()); - + TimeProfiler probe(getName()); auto startTime = std::chrono::high_resolution_clock::now(); - _concept->run(jobContext); - _concept->setCPURunTime((std::chrono::high_resolution_clock::now() - startTime)); } @@ -226,13 +216,14 @@ protected: // The build method is where child Jobs can be added internally to the task // where the input of the task can be setup to feed the child jobs // and where the output of the task is defined -template -class Task : public Job { +template +class Task : public Job { public: using Context = JC; + using TimeProfiler = TP; using ContextPointer = std::shared_ptr; using Config = TaskConfig; - using JobType = Job; + using JobType = Job; using None = typename JobType::None; using Concept = typename JobType::Concept; using ConceptPointer = typename JobType::ConceptPointer; @@ -303,7 +294,7 @@ public: auto model = std::make_shared(name, input, std::make_shared()); { - Duration profileRange(trace_render(), ("build::" + model->getName()).c_str()); + TimeProfiler probe("build::" + model->getName()); model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); } // Recreate the Config to use the templated type @@ -338,7 +329,7 @@ public: } void applyConfiguration() override { - Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); + TimeProfiler probe("configure::" + JobConcept::getName()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); for (auto& job : TaskConcept::_jobs) { job.applyConfiguration(); @@ -379,13 +370,13 @@ public: protected: }; -template -class Engine : public Task { +template +class Engine : public Task { public: using Context = JC; using ContextPointer = std::shared_ptr; using Config = TaskConfig; - using TaskType = Task; + using TaskType = Task; using ConceptPointer = typename TaskType::ConceptPointer; Engine(ConceptPointer concept) : TaskType(concept) {} @@ -409,13 +400,13 @@ protected: } -#define Task_DeclareTypeAliases(ContextType) \ +#define Task_DeclareTypeAliases(ContextType, TimeProfiler) \ using JobConfig = task::JobConfig; \ using TaskConfig = task::TaskConfig; \ template using PersistentConfig = task::PersistentConfig; \ - using Job = task::Job; \ - using Task = task::Task; \ - using _Engine = task::Engine; \ + using Job = task::Job; \ + using Task = task::Task; \ + using _Engine = task::Engine; \ using Varying = task::Varying; \ template < typename T0, typename T1 > using VaryingSet2 = task::VaryingSet2; \ template < typename T0, typename T1, typename T2 > using VaryingSet3 = task::VaryingSet3; \ @@ -426,4 +417,16 @@ protected: template < typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7 > using VaryingSet8 = task::VaryingSet8; \ template < class T, int NUM > using VaryingArray = task::VaryingArray; + + +#include +#include + +#define Task_DeclareCategoryTimeProfilerClass(className, category) \ + class className : public PerformanceTimer { \ + public: \ + className(const std::string& label) : PerformanceTimer(label.c_str()), profileRange(category(), label.c_str()) {} \ + Duration profileRange; \ + }; + #endif // hifi_task_Task_h diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 160ec26be0..dc81df48cb 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -37,9 +37,9 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - spacing: 20 + spacing: 5 Column { - spacing: 10 + spacing: 5 // padding: 10 Repeater { model: [ @@ -61,7 +61,7 @@ Rectangle { Column { - spacing: 10 + spacing: 5 Repeater { model: [ "Obscurance:LightingModel:enableObscurance", @@ -81,7 +81,7 @@ Rectangle { } Column { - spacing: 10 + spacing: 5 Repeater { model: [ "Ambient:LightingModel:enableAmbientLight", @@ -105,7 +105,7 @@ Rectangle { Column { anchors.left: parent.left anchors.right: parent.right - spacing: 10 + spacing: 5 Repeater { model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0" ] @@ -211,9 +211,9 @@ Rectangle { Separator {} Row { - spacing: 10 + spacing: 5 Column { - spacing: 10 + spacing: 5 HifiControls.CheckBox { boxSize: 20 @@ -254,7 +254,7 @@ Rectangle { } Column { - spacing: 10 + spacing: 5 HifiControls.CheckBox { boxSize: 20 text: "Metas" From 859b187db6e3badd5477ea7dc409252fe04e2534 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 8 May 2018 18:17:52 -0700 Subject: [PATCH 04/69] Separate panel for inspecting the engine --- scripts/developer/utilities/lib/jet/jet.js | 15 +++--- .../utilities/lib/jet/qml/TaskList.qml | 7 +-- .../utilities/render/deferredLighting.qml | 15 +++--- .../utilities/render/engineInspector.js | 13 +++++ .../utilities/render/engineInspector.qml | 30 +++++++++++ scripts/developer/utilities/render/luci.js | 53 +++++++++++++++---- 6 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 scripts/developer/utilities/render/engineInspector.js create mode 100644 scripts/developer/utilities/render/engineInspector.qml diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index 39da9b6d90..c326a3a73e 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -46,19 +46,20 @@ function job_propKeys(job) { } // Use this function to create a functor that will print the content of the Job visited calling the specified 'printout' function -function job_print_functor(printout, maxDepth) { +function job_print_functor(printout, showProps, maxDepth) { if (maxDepth === undefined) maxDepth = 100 return function (job, depth, index) { var tab = " " var depthTab = ""; for (var d = 0; d < depth; d++) { depthTab += tab } - printout(depthTab + index + " " + job.objectName + " " + (job.enabled ? "on" : "off")) - var keys = job_propKeys(job); - for (var p=0; p < keys.length;p++) { - var prop = job[keys[p]] - printout(depthTab + tab + tab + typeof prop + " " + keys[p] + " " + prop); + printout(depthTab + index + " " + job.objectName + " " + (job.enabled ? "on " : "off ") + job.cpuRunTime + "ms") + if (showProps) { + var keys = job_propKeys(job); + for (var p=0; p < keys.length;p++) { + var prop = job[keys[p]] + printout(depthTab + tab + tab + typeof prop + " " + keys[p] + " " + prop); + } } - return true // return depth < maxDepth; } diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index fa004627a7..bd4b1e6c79 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -32,14 +32,9 @@ Rectangle { Component.onCompleted: { var message = "" - var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }); + var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); Jet.task_traverseTree(rootConfig, functor); textArea.append(message); - } - function fromScript(mope) { - var message ='Received \n'; - message += mope; - textArea.append(message); } function clearWindow() { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index dc81df48cb..d68b19c513 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -14,7 +14,6 @@ import QtQuick.Layouts 1.3 import "qrc:///qml/styles-uit" import "qrc:///qml/controls-uit" as HifiControls import "configSlider" -import "../lib/jet/qml" as Jet Rectangle { HifiConstants { id: hifi;} @@ -276,14 +275,12 @@ Rectangle { } } Separator {} - - Jet.TaskList { - rootConfig: Render - anchors.left: parent.left - anchors.right: parent.right - - height: 200 + HifiControls.Button { + text: "Engine" + // activeFocusOnPress: false + onClicked: { + sendToScript({method: "openEngineView"}); + } } } - //} } diff --git a/scripts/developer/utilities/render/engineInspector.js b/scripts/developer/utilities/render/engineInspector.js new file mode 100644 index 0000000000..dcf13157b5 --- /dev/null +++ b/scripts/developer/utilities/render/engineInspector.js @@ -0,0 +1,13 @@ + function openEngineTaskView() { + // Set up the qml ui + var qml = Script.resolvePath('engineInspector.qml'); + var window = new OverlayWindow({ + title: 'Render Engine', + source: qml, + width: 300, + height: 400 + }); + window.setPosition(200, 50); + //window.closed.connect(function() { Script.stop(); }); + } + openEngineTaskView(); \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml new file mode 100644 index 0000000000..6461e5d834 --- /dev/null +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -0,0 +1,30 @@ +// +// deferredLighting.qml +// +// Created by Sam Gateau on 6/6/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + +import "../lib/jet/qml" as Jet + +Item { + HifiConstants { id: hifi;} + id: render; + anchors.fill: parent + + property var mainViewTask: Render.getConfig("RenderMainView") + + Jet.TaskList { + rootConfig: Render + anchors.fill: render + } +} \ No newline at end of file diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index 6482c884ff..005d96780a 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -64,9 +64,6 @@ button.editProperties({isActive: onLuciScreen}); wireEventBridge(onLuciScreen); } - - function fromQml(message) { - } button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); @@ -82,14 +79,6 @@ Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); - Script.scriptEnding.connect(function () { - if (onLuciScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - tablet.removeButton(button); - }); function setDebugCursor(x, y) { nx = (x / Window.innerWidth); @@ -98,4 +87,46 @@ Render.getConfig("RenderMainView").getConfig("Antialiasing").debugCursorTexcoord = { x: nx, y: ny }; } + + function fromQml(message) { + switch (message.method) { + case "openEngineView": + openEngineTaskView(); + break; + } + } + + + var engineInspectorView = null + function openEngineTaskView() { + if (engineInspectorView == null) { + var qml = Script.resolvePath('engineInspector.qml'); + var window = new OverlayWindow({ + title: 'Render Engine', + source: qml, + width: 300, + height: 400 + }); + window.setPosition(200, 50); + engineInspectorView = window + window.closed.connect(function() { engineInspectorView = null; }); + } else { + engineInspectorView.setPosition(200, 50); + } + } + + + + Script.scriptEnding.connect(function () { + if (onLuciScreen) { + tablet.gotoHomeScreen(); + } + button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); + tablet.removeButton(button); + + if (engineInspectorView !== null) { + engineInspectorView.close() + } + }); }()); \ No newline at end of file From 3241c182714c2f2bf221d1f910dab38049644406 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:10:40 -0700 Subject: [PATCH 05/69] first pass cloneables WIP --- .../src/entities/EntityServer.cpp | 1 + .../entities/src/EntityEditPacketSender.cpp | 14 ++- .../entities/src/EntityEditPacketSender.h | 1 + libraries/entities/src/EntityItem.cpp | 98 ++++++++++++++++++ libraries/entities/src/EntityItem.h | 23 +++++ .../entities/src/EntityItemProperties.cpp | 97 ++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 7 ++ .../src/EntityItemPropertiesDefaults.h | 5 + libraries/entities/src/EntityPropertyFlags.h | 5 + .../entities/src/EntityScriptingInterface.cpp | 73 +++++++++----- .../entities/src/EntityScriptingInterface.h | 3 + libraries/entities/src/EntityTree.cpp | 99 +++++++++++++++---- libraries/entities/src/EntityTree.h | 1 + libraries/gpu/src/gpu/Buffer.cpp | 2 +- .../networking/src/udt/PacketHeaders.cpp | 3 +- libraries/networking/src/udt/PacketHeaders.h | 4 +- scripts/system/html/js/entityProperties.js | 75 ++------------ scripts/system/libraries/cloneEntityUtils.js | 60 +++-------- .../libraries/controllerDispatcherUtils.js | 3 +- 19 files changed, 410 insertions(+), 164 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index c108dad6cf..3ca8c1ecd1 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -44,6 +44,7 @@ EntityServer::EntityServer(ReceivedMessage& message) : auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, + PacketType::EntityClone, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics, diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index d89dd4f9d0..0ae4f7ac2b 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -34,7 +34,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer EntityItem::getMaterial } return toReturn; } + +bool EntityItem::getCloneable() const { + bool result; + withReadLock([&] { + result = _cloneable; + }); + return result; +} + +void EntityItem::setCloneable(bool value) { + withWriteLock([&] { + _cloneable = value; + }); +} + +float EntityItem::getCloneableLifetime() const { + float result; + withReadLock([&] { + result = _cloneableLifetime; + }); + return result; +} + +void EntityItem::setCloneableLifetime(float value) { + withWriteLock([&] { + _cloneableLifetime = value; + }); +} + +float EntityItem::getCloneableLimit() const { + float result; + withReadLock([&] { + result = _cloneableLimit; + }); + return result; +} + +void EntityItem::setCloneableLimit(float value) { + withWriteLock([&] { + _cloneableLimit = value; + }); +} + +bool EntityItem::getCloneableDynamic() const { + bool result; + withReadLock([&] { + result = _cloneableDynamic; + }); + return result; +} + +void EntityItem::setCloneableDynamic(const bool value) { + withWriteLock([&] { + _cloneableDynamic = value; + }); +} + +bool EntityItem::addCloneID(const QUuid& cloneID) { + if (!_cloneIDs.contains(cloneID)) { + _cloneIDs.append(cloneID); + return true; + } + return false; +} + +bool EntityItem::removeCloneID(const QUuid& cloneID) { + int index = _cloneIDs.indexOf(cloneID); + if (index > 0) { + _cloneIDs.removeAt(index); + return true; + } + return false; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a88250a133..95cc5f96e1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -341,6 +341,15 @@ public: quint32 getStaticCertificateVersion() const; void setStaticCertificateVersion(const quint32&); + bool getCloneable() const; + void setCloneable(bool value); + float getCloneableLifetime() const; + void setCloneableLifetime(float value); + float getCloneableLimit() const; + void setCloneableLimit(float value); + bool getCloneableDynamic() const; + void setCloneableDynamic(const bool value); + // TODO: get rid of users of getRadius()... float getRadius() const; @@ -494,6 +503,12 @@ public: void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } + bool addCloneID(const QUuid& cloneID); + bool removeCloneID(const QUuid& cloneID); + const QList& getCloneIDs() const { return _cloneIDs; } + void setCloneParent(const QUuid& cloneParentID) { _cloneParentID = cloneParentID; } + const QUuid& getCloneParent() const { return _cloneParentID; } + signals: void requestRenderUpdate(); @@ -648,6 +663,14 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera + bool _cloneable; + float _cloneableLifetime; + float _cloneableLimit; + bool _cloneableDynamic; + + QList _cloneIDs; + QUuid _cloneParentID; + private: std::unordered_map _materials; std::mutex _materialsLock; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4d7c114176..93c2eb885e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -436,6 +436,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_DPI, dpi); CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE, cloneable); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIMIT, cloneableLimit); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); changedProperties += _ambientLight.getChangedProperties(); @@ -1430,6 +1435,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); // Gettable but not settable except at entity creation COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIMIT, cloneableLimit); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + // Rendering info if (!skipDefaults && !strictSemantics) { QScriptValue renderInfo = engine->newObject(); @@ -1642,6 +1652,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneable, bool, setCloneable); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLifetime, float, setCloneableLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLimit, float, setCloneableLimit); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableDynamic, bool, setCloneableDynamic); + _lastEdited = usecTimestampNow(); } @@ -2017,6 +2032,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_DPI, DPI, dpi, uint16_t); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE, Cloneable, cloneable, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2331,6 +2351,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, properties.getEntityInstanceNumber()); APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, properties.getCertificateID()); APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion()); + + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, properties.getCloneable()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, properties.getCloneableLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, properties.getCloneableLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, properties.getCloneableDynamic()); } if (propertyCount > 0) { @@ -2701,6 +2726,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_ID, QString, setCertificateID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE, bool, setCloneable); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + return valid; } @@ -2780,6 +2810,54 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt return true; } +bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { + + char* copyAt = buffer.data(); + int outputLength = 0; + + if (buffer.size() < (int)(sizeof(NUM_BYTES_RFC4122_UUID) * 2)) { + qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; + return false; + } + + memcpy(copyAt, entityIDToClone.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; + + memcpy(copyAt, newEntityID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; + + buffer.resize(outputLength); + + return true; +} + +bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { + + const unsigned char* packetData = (const unsigned char*)buffer.constData(); + const unsigned char* dataAt = packetData; + size_t packetLength = buffer.size(); + processedBytes = 0; + + if (NUM_BYTES_RFC4122_UUID * 2 > packetLength) { + qCDebug(entities) << "EntityItemProperties::processEraseMessageDetails().... bailing because not enough bytes in buffer"; + return false; // bail to prevent buffer overflow + } + + QByteArray encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + entityIDToClone = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + newEntityID = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + return true; +} + void EntityItemProperties::markAllChanged() { _lastEditedByChanged = true; _simulationOwnerChanged = true; @@ -2941,6 +3019,11 @@ void EntityItemProperties::markAllChanged() { _dpiChanged = true; _relayParentJointsChanged = true; + + _cloneableChanged = true; + _cloneableLifetimeChanged = true; + _cloneableLimitChanged = true; + _cloneableDynamicChanged = true; } // The minimum bounding box for the entity. @@ -3373,6 +3456,20 @@ QList EntityItemProperties::listChangedProperties() { out += "isUVModeStretch"; } + if (cloneableChanged()) { + out += "cloneable"; + } + if (cloneableLifetimeChanged()) { + out += "cloneableLifetime"; + } + if (cloneableLimitChanged()) { + out += "cloneableLimit"; + } + if (cloneableDynamicChanged()) { + out += "cloneableDynamic"; + } + + getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 39ea2e0bdd..3ae2186cab 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -272,6 +272,11 @@ public: DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); + DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); + DEFINE_PROPERTY(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float, ENTITY_ITEM_CLONEABLE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float, ENTITY_ITEM_CLONEABLE_LIMIT); + DEFINE_PROPERTY(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool, ENTITY_ITEM_CLONEABLE_DYNAMIC); + static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); @@ -294,6 +299,8 @@ public: QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties); static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); + static bool encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer); + static bool decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID); static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, EntityItemID& entityID, EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index d2ddd687dd..6e46453bda 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -97,4 +97,9 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; +const bool ENTITY_ITEM_CLONEABLE = false; +const float ENTITY_ITEM_CLONEABLE_LIFETIME = 300.0f; +const int ENTITY_ITEM_CLONEABLE_LIMIT = 0; +const bool ENTITY_ITEM_CLONEABLE_DYNAMIC = false; + #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 99a5f287ea..f698739e01 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -242,6 +242,11 @@ enum EntityPropertyList { PROP_MATERIAL_MAPPING_ROT, PROP_MATERIAL_DATA, + PROP_CLONEABLE, + PROP_CLONEABLE_LIFETIME, + PROP_CLONEABLE_LIMIT, + PROP_CLONEABLE_DYNAMIC, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7c16214a78..132fec2c51 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -258,33 +258,9 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); - EntityItemID id = EntityItemID(QUuid::createUuid()); - + EntityItemID id; // If we have a local entity tree set, then also update it. - bool success = true; - if (_entityTree) { - _entityTree->withWriteLock([&] { - EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); - if (entity) { - if (propertiesWithSimID.queryAACubeRelatedPropertyChanged()) { - // due to parenting, the server may not know where something is in world-space, so include the bounding cube. - bool success; - AACube queryAACube = entity->getQueryAACube(success); - if (success) { - propertiesWithSimID.setQueryAACube(queryAACube); - } - } - - entity->setLastBroadcast(usecTimestampNow()); - // since we're creating this object we will immediately volunteer to own its simulation - entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY); - propertiesWithSimID.setLastEdited(entity->getLastEdited()); - } else { - qCDebug(entities) << "script failed to add new Entity to local Octree"; - success = false; - } - }); - } + bool success = addLocalEntityCopy(propertiesWithSimID, id); // queue the packet if (success) { @@ -295,6 +271,39 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } } +bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properties, EntityItemID& id) { + bool success = true; + + id = EntityItemID(QUuid::createUuid()); + + if (_entityTree) { + _entityTree->withWriteLock([&] { + EntityItemPointer entity = _entityTree->addEntity(id, properties); + if (entity) { + if (properties.queryAACubeRelatedPropertyChanged()) { + // due to parenting, the server may not know where something is in world-space, so include the bounding cube. + bool success; + AACube queryAACube = entity->getQueryAACube(success); + if (success) { + properties.setQueryAACube(queryAACube); + } + } + + entity->setLastBroadcast(usecTimestampNow()); + // since we're creating this object we will immediately volunteer to own its simulation + entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY); + properties.setLastEdited(entity->getLastEdited()); + } + else { + qCDebug(entities) << "script failed to add new Entity to local Octree"; + success = false; + } + }); + } + + return success; +} + QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity) { @@ -320,6 +329,18 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin return addEntity(properties); } +QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { + EntityItemID newEntityID; + EntityItemProperties properties = getEntityProperties(entityIDToClone); + if (addLocalEntityCopy(properties, newEntityID)) { + qCDebug(entities) << "DBACK POOPY cloneEntity addLocalEntityCopy" << newEntityID; + getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); + return newEntityID; + } else { + return QUuid(); + } +} + EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { EntityPropertyFlags noSpecificProperties; return getEntityProperties(identity, noSpecificProperties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8adb5138f2..6935c9e8c4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -224,6 +224,8 @@ public slots: Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity); + Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone); + /**jsdoc * Get the properties of an entity. * @function Entities.getEntityProperties @@ -1875,6 +1877,7 @@ private: bool polyVoxWorker(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); + bool addLocalEntityCopy(EntityItemProperties& propertiesWithSimID, EntityItemID& id); EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID, EntityTypes::EntityType entityType = EntityTypes::Unknown); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3149527216..1e8055ff46 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -228,6 +228,7 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const { // we handle these types of "edit" packets switch (packetType) { case PacketType::EntityAdd: + case PacketType::EntityClone: case PacketType::EntityEdit: case PacketType::EntityErase: case PacketType::EntityPhysics: @@ -592,6 +593,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } + removeCloneIDFromCloneParent(entityID); unhookChildAvatar(entityID); emit deletingEntity(entityID); emit deletingEntityPointer(existingEntity.get()); @@ -625,6 +627,19 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { }); } +void EntityTree::removeCloneIDFromCloneParent(const EntityItemID& entityID) { + EntityItemPointer entity = findEntityByEntityItemID(entityID); + if (entity) { + const QUuid& cloneParentID = entity->getCloneParent(); + if (!cloneParentID.isNull()) { + EntityItemPointer cloneParent = findEntityByID(cloneParentID); + if (cloneParent) { + cloneParent->removeCloneID(entityID); + } + } + } +} + void EntityTree::deleteEntities(QSet entityIDs, bool force, bool ignoreWarnings) { // NOTE: callers must lock the tree before using this method DeleteEntityOperator theOperator(getThisPointer()); @@ -653,6 +668,7 @@ void EntityTree::deleteEntities(QSet entityIDs, bool force, bool i } // tell our delete operator about this entityID + removeCloneIDFromCloneParent(entityID); unhookChildAvatar(entityID); theOperator.addEntityIDToDeleteList(entityID); emit deletingEntity(entityID); @@ -1392,6 +1408,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c int processedBytes = 0; bool isAdd = false; + bool isClone = false; // we handle these types of "edit" packets switch (message.getType()) { case PacketType::EntityErase: { @@ -1400,8 +1417,10 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c break; } + case PacketType::EntityClone: + isClone = true; // fall through to next case case PacketType::EntityAdd: - isAdd = true; // fall through to next case + isAdd = true; // fall through to next case // FALLTHRU case PacketType::EntityPhysics: case PacketType::EntityEdit: { @@ -1422,8 +1441,21 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c EntityItemProperties properties; startDecode = usecTimestampNow(); - bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength, processedBytes, - entityItemID, properties); + bool validEditPacket = false; + EntityItemID entityIDToClone; + EntityItemPointer entityToClone; + if (isClone) { + QByteArray buffer = QByteArray::fromRawData(reinterpret_cast(editData), maxLength); + validEditPacket = EntityItemProperties::decodeCloneEntityMessage(buffer, processedBytes, entityIDToClone, entityItemID); + entityToClone = findEntityByEntityItemID(entityIDToClone); + if (entityToClone) { + properties = entityToClone->getProperties(); + } + } + else { + validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength, processedBytes, entityItemID, properties); + } + endDecode = usecTimestampNow(); EntityItemPointer existingEntity; @@ -1491,24 +1523,26 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } - if ((isAdd || properties.lifetimeChanged()) && - ((!senderNode->getCanRez() && senderNode->getCanRezTmp()) || - (!senderNode->getCanRezCertified() && senderNode->getCanRezTmpCertified()))) { - // this node is only allowed to rez temporary entities. if need be, cap the lifetime. - if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME || - properties.getLifetime() > _maxTmpEntityLifetime) { - properties.setLifetime(_maxTmpEntityLifetime); + if (!isClone) { + if ((isAdd || properties.lifetimeChanged()) && + ((!senderNode->getCanRez() && senderNode->getCanRezTmp()) || + (!senderNode->getCanRezCertified() && senderNode->getCanRezTmpCertified()))) { + // this node is only allowed to rez temporary entities. if need be, cap the lifetime. + if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME || + properties.getLifetime() > _maxTmpEntityLifetime) { + properties.setLifetime(_maxTmpEntityLifetime); + bumpTimestamp(properties); + } + } + + if (isAdd && properties.getLocked() && !senderNode->isAllowedEditor()) { + // if a node can't change locks, don't allow it to create an already-locked entity -- automatically + // clear the locked property and allow the unlocked entity to be created. + properties.setLocked(false); bumpTimestamp(properties); } } - if (isAdd && properties.getLocked() && !senderNode->isAllowedEditor()) { - // if a node can't change locks, don't allow it to create an already-locked entity -- automatically - // clear the locked property and allow the unlocked entity to be created. - properties.setLocked(false); - bumpTimestamp(properties); - } - // If we got a valid edit packet, then it could be a new entity or it could be an update to // an existing entity... handle appropriately if (validEditPacket) { @@ -1566,17 +1600,39 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } else if (isAdd) { bool failedAdd = !allowed; bool isCertified = !properties.getCertificateID().isEmpty(); + bool isCloneable = properties.getCloneable(); + int cloneLimit = properties.getCloneableLimit(); if (!allowed) { qCDebug(entities) << "Filtered entity add. ID:" << entityItemID; - } else if (!isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { + } else if (!isClone && !isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { failedAdd = true; qCDebug(entities) << "User without 'uncertified rez rights' [" << senderNode->getUUID() << "] attempted to add an uncertified entity with ID:" << entityItemID; - } else if (isCertified && !senderNode->getCanRezCertified() && !senderNode->getCanRezTmpCertified()) { + } else if (!isClone && isCertified && !senderNode->getCanRezCertified() && !senderNode->getCanRezTmpCertified()) { failedAdd = true; qCDebug(entities) << "User without 'certified rez rights' [" << senderNode->getUUID() << "] attempted to add a certified entity with ID:" << entityItemID; + } else if (isClone && isCertified) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone certified entity from entity ID:" << entityIDToClone; + } else if (isClone && !isCloneable) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone non-cloneable entity from entity ID:" << entityIDToClone; + } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { + if (isClone) { + properties.setName(properties.getName() + "-clone-" + entityIDToClone.toString()); + properties.setLocked(false); + properties.setLifetime(properties.getCloneableLifetime()); + properties.setDynamic(properties.getCloneableDynamic()); + properties.setCloneable(ENTITY_ITEM_CLONEABLE); + properties.setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); + properties.setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); + properties.setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); + } + // this is a new entity... assign a new entityID properties.setCreated(properties.getLastEdited()); properties.setLastEditedBy(senderNode->getUUID()); @@ -1600,6 +1656,11 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); + if (isClone) { + entityToClone->addCloneID(newEntity->getEntityItemID()); + newEntity->setCloneParent(entityIDToClone); + qCDebug(entities) << "DBACK POOPY addedEntity clone " << newEntity->getEntityItemID(); + } startLogging = usecTimestampNow(); if (wantEditLogging()) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index ee9fb10554..0d7cc54df7 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -117,6 +117,7 @@ public: // check if the avatar is a child of this entity, If so set the avatar parentID to null void unhookChildAvatar(const EntityItemID entityID); + void removeCloneIDFromCloneParent(const EntityItemID& entityID); void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true); void deleteEntities(QSet entityIDs, bool force = false, bool ignoreWarnings = true); diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index ebb768e597..fe3570e7f7 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -99,7 +99,7 @@ Buffer::Update::Update(const Buffer& parent) : buffer(parent) { void Buffer::Update::apply() const { // Make sure we're loaded in order buffer._applyUpdateCount++; - assert(buffer._applyUpdateCount == updateNumber); + //assert(buffer._applyUpdateCount == updateNumber); const auto pageSize = buffer._pages._pageSize; buffer._renderSysmem.resize(size); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 70880833bf..e84f3ffe7a 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -29,10 +29,11 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::DomainList: return static_cast(DomainListVersion::GetMachineFingerprintFromUUIDSupport); case PacketType::EntityAdd: + case PacketType::EntityClone: case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::MaterialData); + return static_cast(EntityVersion::CloneableData); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7d374f3625..5cb2d49a53 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -75,6 +75,7 @@ public: EntityData, EntityQuery, EntityAdd, + EntityClone, EntityErase, EntityEdit, DomainServerConnectionToken, @@ -232,7 +233,8 @@ enum class EntityVersion : PacketVersion { SoftEntities, MaterialEntities, ShadowControl, - MaterialData + MaterialData, + CloneableData }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 4b6329db44..f0bcdad708 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1040,12 +1040,12 @@ function loaded() { elWantsTrigger.checked = false; elIgnoreIK.checked = true; - elCloneable.checked = false; - elCloneableDynamic.checked = false; + elCloneable.checked = properties.cloneable; + elCloneableDynamic.checked = properties.cloneableDynamic; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; - elCloneableLimit.value = 0; - elCloneableLifetime.value = 300; - + elCloneableLimit.value = properties.cloneableLimit; + elCloneableLifetime.value = properties.cloneableLifetime; + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1069,27 +1069,6 @@ function loaded() { } else { elIgnoreIK.checked = true; } - if ("cloneable" in grabbableData) { - elCloneable.checked = grabbableData.cloneable; - elCloneableGroup.style.display = elCloneable.checked ? "block" : "none"; - elCloneableDynamic.checked = - grabbableData.cloneDynamic ? grabbableData.cloneDynamic : properties.dynamic; - if (elCloneable.checked) { - if ("cloneLifetime" in grabbableData) { - elCloneableLifetime.value = - grabbableData.cloneLifetime ? grabbableData.cloneLifetime : 300; - } - if ("cloneLimit" in grabbableData) { - elCloneableLimit.value = grabbableData.cloneLimit ? grabbableData.cloneLimit : 0; - } - if ("cloneAvatarEntity" in grabbableData) { - elCloneableAvatarEntity.checked = - grabbableData.cloneAvatarEntity ? grabbableData.cloneAvatarEntity : false; - } - } - } else { - elCloneable.checked = false; - } } } catch (e) { // TODO: What should go here? @@ -1460,45 +1439,11 @@ function loaded() { } userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); }); - elCloneableDynamic.addEventListener('change', function(event) { - userDataChanger("grabbableKey", "cloneDynamic", event.target, elUserData, -1); - }); - - elCloneableAvatarEntity.addEventListener('change', function(event) { - userDataChanger("grabbableKey", "cloneAvatarEntity", event.target, elUserData, -1); - }); - - elCloneable.addEventListener('change', function (event) { - var checked = event.target.checked; - if (checked) { - multiDataUpdater("grabbableKey", { - cloneLifetime: elCloneableLifetime, - cloneLimit: elCloneableLimit, - cloneDynamic: elCloneableDynamic, - cloneAvatarEntity: elCloneableAvatarEntity, - cloneable: event.target, - grabbable: null - }, elUserData, {}); - elCloneableGroup.style.display = "block"; - updateProperty('dynamic', false); - } else { - multiDataUpdater("grabbableKey", { - cloneLifetime: null, - cloneLimit: null, - cloneDynamic: null, - cloneAvatarEntity: null, - cloneable: false - }, elUserData, {}); - elCloneableGroup.style.display = "none"; - } - }); - - var numberListener = function (event) { - userDataChanger("grabbableKey", - event.target.getAttribute("data-user-data-type"), parseInt(event.target.value), elUserData, false); - }; - elCloneableLifetime.addEventListener('change', numberListener); - elCloneableLimit.addEventListener('change', numberListener); + + elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index 63b161eb80..bd33d32342 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -33,8 +33,7 @@ if (typeof Object.assign !== 'function') { entityIsCloneable = function(props) { if (props) { - var grabbableData = getGrabbableData(props); - return grabbableData.cloneable; + return props.cloneable; } return false; }; @@ -42,56 +41,19 @@ entityIsCloneable = function(props) { propsAreCloneDynamic = function(props) { var cloneable = entityIsCloneable(props); if (cloneable) { - var grabInfo = getGrabbableData(props); - if (grabInfo.cloneDynamic) { - return true; - } + return props.cloneableDynamic; } return false; }; - cloneEntity = function(props, worldEntityProps) { - // we need all the properties, for this - var cloneableProps = Entities.getEntityProperties(props.id); - - var count = 0; - worldEntityProps.forEach(function(itemWE) { - if (itemWE.name.indexOf('-clone-' + cloneableProps.id) !== -1) { - count++; - } - }); - - var grabInfo = getGrabbableData(cloneableProps); - var limit = grabInfo.cloneLimit ? grabInfo.cloneLimit : 0; - if (count >= limit && limit !== 0) { - return null; - } - - cloneableProps.name = cloneableProps.name + '-clone-' + cloneableProps.id; - var lifetime = grabInfo.cloneLifetime ? grabInfo.cloneLifetime : 300; - var dynamic = grabInfo.cloneDynamic ? grabInfo.cloneDynamic : false; - var triggerable = grabInfo.triggerable ? grabInfo.triggerable : false; - var avatarEntity = grabInfo.cloneAvatarEntity ? grabInfo.cloneAvatarEntity : false; - var cUserData = Object.assign({}, JSON.parse(cloneableProps.userData)); - var cProperties = Object.assign({}, cloneableProps); - - - delete cUserData.grabbableKey.cloneLifetime; - delete cUserData.grabbableKey.cloneable; - delete cUserData.grabbableKey.cloneDynamic; - delete cUserData.grabbableKey.cloneLimit; - delete cUserData.grabbableKey.cloneAvatarEntity; - delete cProperties.id; - - - cProperties.dynamic = dynamic; - cProperties.locked = false; - cUserData.grabbableKey.triggerable = triggerable; - cUserData.grabbableKey.grabbable = true; - cProperties.lifetime = lifetime; - cProperties.userData = JSON.stringify(cUserData); - - var cloneID = Entities.addEntity(cProperties, avatarEntity); - return cloneID; + var entityToClone = props.id; + var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; + // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits + // will now be handled by the server where the entity add will fail if limit reached + if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { + var cloneID = Entities.cloneEntity(entityToClone); + return cloneID; + } + return null; }; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 71dc5e4273..f3f0e8dd01 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -125,7 +125,8 @@ DISPATCHER_PROPERTIES = [ "dimensions", "userData", "type", - "href" + "href", + "cloneable" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step From dea588ae4ac1968b0e3f5c070f9c99096fbc2b96 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:12:04 -0700 Subject: [PATCH 06/69] remove prints --- libraries/entities/src/EntityScriptingInterface.cpp | 1 - libraries/entities/src/EntityTree.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 132fec2c51..7b7f35aa09 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,6 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); if (addLocalEntityCopy(properties, newEntityID)) { - qCDebug(entities) << "DBACK POOPY cloneEntity addLocalEntityCopy" << newEntityID; getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; } else { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1e8055ff46..20b3f81f42 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1659,7 +1659,6 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (isClone) { entityToClone->addCloneID(newEntity->getEntityItemID()); newEntity->setCloneParent(entityIDToClone); - qCDebug(entities) << "DBACK POOPY addedEntity clone " << newEntity->getEntityItemID(); } startLogging = usecTimestampNow(); From 1aa653c5db6cf05fbb94517c857e4b3958e8563a Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:20:07 -0700 Subject: [PATCH 07/69] tabs --- scripts/system/html/js/entityProperties.js | 12 ++++++------ scripts/system/libraries/cloneEntityUtils.js | 16 ++++++++-------- .../libraries/controllerDispatcherUtils.js | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index f0bcdad708..c81e51d674 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1045,7 +1045,7 @@ function loaded() { elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneableLimit; elCloneableLifetime.value = properties.cloneableLifetime; - + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1439,11 +1439,11 @@ function loaded() { } userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); }); - - elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); - elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); - elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); - elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); + + elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index bd33d32342..358bc4a75f 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -47,13 +47,13 @@ propsAreCloneDynamic = function(props) { }; cloneEntity = function(props, worldEntityProps) { - var entityToClone = props.id; + var entityToClone = props.id; var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; - // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits - // will now be handled by the server where the entity add will fail if limit reached - if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { - var cloneID = Entities.cloneEntity(entityToClone); - return cloneID; - } - return null; + // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits + // will now be handled by the server where the entity add will fail if limit reached + if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { + var cloneID = Entities.cloneEntity(entityToClone); + return cloneID; + } + return null; }; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index f3f0e8dd01..43945c6145 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -126,7 +126,7 @@ DISPATCHER_PROPERTIES = [ "userData", "type", "href", - "cloneable" + "cloneable" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step From f08f77098dc22b8d3e40f199d63184fbec9e144d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 9 May 2018 18:28:47 -0700 Subject: [PATCH 08/69] Adding a true ListView for the engine --- scripts/developer/utilities/lib/jet/jet.js | 9 +++ .../utilities/lib/jet/qml/TaskList.qml | 4 +- .../utilities/lib/jet/qml/TaskListView.qml | 67 +++++++++++++++++++ .../developer/utilities/lib/jet/qml/qmldir | 3 +- .../utilities/render/engineInspector.qml | 4 +- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 scripts/developer/utilities/lib/jet/qml/TaskListView.qml diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index c326a3a73e..5bebb99068 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -45,6 +45,15 @@ function job_propKeys(job) { return propKeys; } +// Use this function to create a functor that will fill the specifed array with one entry name per task and job and it s rank +function job_list_functor(jobList, maxDepth) { + if (maxDepth === undefined) maxDepth = 100 + return function (job, depth, index) { + jobList.push(job.objectName); + return depth < maxDepth; + } +} + // Use this function to create a functor that will print the content of the Job visited calling the specified 'printout' function function job_print_functor(printout, showProps, maxDepth) { if (maxDepth === undefined) maxDepth = 100 diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index bd4b1e6c79..b801b9171d 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -17,7 +17,9 @@ import "qrc:///qml/controls-uit" as HifiControls import "../jet.js" as Jet -Rectangle { +Rectangle { + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; id: root // width: parent ? parent.width : 200 // height: parent ? parent.height : 400 diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml new file mode 100644 index 0000000000..f8775d56b9 --- /dev/null +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -0,0 +1,67 @@ +// +// jet/TaskListView.qml +// +// Created by Sam Gateau, 2018/05/09 +// 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 +// + +import QtQuick 2.7 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + +import "../jet.js" as Jet + +Rectangle { + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; + id: root + + // width: parent ? parent.width : 200 + // height: parent ? parent.height : 400 + property var rootConfig : Workload + property var myArray : [] + + Component.onCompleted: { + var message = "" + var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); + + functor = Jet.job_list_functor(root.myArray); + + Jet.task_traverseTree(rootConfig, functor); + //print(JSON.stringify(root.myArray)) + // theView.model = root.myArray.length + for (var i = 0; i < root.myArray.length; i++) { + jobsModel.append({"on": true, "name": root.myArray[i]}) + } + // theView.model = root.myArray + } + + function getJobName(i) { + return root.myArray[i]; + } + + ListModel { + id: jobsModel + } + + Component { + id: itemDelegate + //HifiControls.Label { text: "I am item number: " + index } + HifiControls.CheckBox { text: name + index; + checked: true; } + } + + ListView { + id: theView + anchors.fill: parent + model: jobsModel + delegate: itemDelegate + } + +} \ No newline at end of file diff --git a/scripts/developer/utilities/lib/jet/qml/qmldir b/scripts/developer/utilities/lib/jet/qml/qmldir index f926d8cc67..3134545625 100644 --- a/scripts/developer/utilities/lib/jet/qml/qmldir +++ b/scripts/developer/utilities/lib/jet/qml/qmldir @@ -1 +1,2 @@ -TaskList 1.0 TaskList.qml \ No newline at end of file +TaskList 1.0 TaskList.qml +TaskViewList 1.0 TaskViewList.qml \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml index 6461e5d834..1b9941e64e 100644 --- a/scripts/developer/utilities/render/engineInspector.qml +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -20,10 +20,10 @@ Item { HifiConstants { id: hifi;} id: render; anchors.fill: parent - + property var mainViewTask: Render.getConfig("RenderMainView") - Jet.TaskList { + Jet.TaskListView { rootConfig: Render anchors.fill: render } From 5aab88be06edf0b56fe4b9c6dd690e73ded6b529 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 19:10:56 -0700 Subject: [PATCH 09/69] assert --- libraries/gpu/src/gpu/Buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index fe3570e7f7..ebb768e597 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -99,7 +99,7 @@ Buffer::Update::Update(const Buffer& parent) : buffer(parent) { void Buffer::Update::apply() const { // Make sure we're loaded in order buffer._applyUpdateCount++; - //assert(buffer._applyUpdateCount == updateNumber); + assert(buffer._applyUpdateCount == updateNumber); const auto pageSize = buffer._pages._pageSize; buffer._renderSysmem.resize(size); From bf85034f3618d267f0187fe82ea05dbc6236a450 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 10 May 2018 02:08:19 -0700 Subject: [PATCH 10/69] Tree view comming together for the engine! --- scripts/developer/utilities/lib/jet/jet.js | 6 +- .../utilities/lib/jet/qml/TaskListView.qml | 90 +++++++++++++++---- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index 5bebb99068..18027ea4bd 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -12,15 +12,15 @@ // traverse task tree function task_traverse(root, functor, depth) { - // if (root.isTask()) { + if (root.isTask()) { depth++; for (var i = 0; i 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + node.append(newItem) + jobTreePath.push(0); + } else if (jobTreePath.length >= depth) { + var node = jobsRoot; + for (var n = 0; n < (depth - 1); n++) { + newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + node.append(newItem) + jobTreePath[depth-1] = index; + while (jobTreePath.length > depth) { + jobTreePath.pop(); + } + } + } + return true; + } Jet.task_traverseTree(rootConfig, functor); - //print(JSON.stringify(root.myArray)) - // theView.model = root.myArray.length - for (var i = 0; i < root.myArray.length; i++) { - jobsModel.append({"on": true, "name": root.myArray[i]}) - } - // theView.model = root.myArray - } - - function getJobName(i) { - return root.myArray[i]; } ListModel { @@ -51,17 +77,47 @@ Rectangle { } Component { - id: itemDelegate - //HifiControls.Label { text: "I am item number: " + index } - HifiControls.CheckBox { text: name + index; - checked: true; } + id: objRecursiveDelegate + Column { + id: objRecursiveColumn + clip: true + visible: model.init + + MouseArea { + width: objRow.implicitWidth + height: objRow.implicitHeight + onDoubleClicked: { + for(var i = 1; i < parent.children.length - 1; ++i) { + parent.children[i].visible = !parent.children[i].visible + } + } + Row { + id: objRow + Item { + height: 1 + width: model.level * 15 + } + HifiControls.CheckBox { + property var config: root.rootConfig.getConfig(model.path + "." + model.name); + text: (objRecursiveColumn.children.length > 2 ? + objRecursiveColumn.children[1].visible ? + qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(3) + checked: config.enabled + } + } + } + Repeater { + model: subNode + delegate: objRecursiveDelegate + } + } } ListView { id: theView anchors.fill: parent model: jobsModel - delegate: itemDelegate + delegate: objRecursiveDelegate } } \ No newline at end of file From 02be965271154c9b29dbdb3e60aaffdfe14431bf Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 10 May 2018 18:10:01 -0700 Subject: [PATCH 11/69] more stuff fixed --- .../src/procedural/ProceduralSkybox.cpp | 7 +++++- libraries/render/src/render/Engine.cpp | 3 +-- libraries/render/src/render/Engine.h | 14 ++++++----- libraries/task/src/task/Task.h | 2 +- .../utilities/lib/jet/qml/TaskListView.qml | 24 +++++++++---------- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 0c6501928b..806302d7ef 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -21,6 +21,7 @@ ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() { _procedural._vertexSource = skybox_vert::getSource(); _procedural._opaquefragmentSource = skybox_frag::getSource(); + _procedural._transparentfragmentSource = skybox_frag::getSource(); // Adjust the pipeline state for background using the stencil test _procedural.setDoesFade(false); // Must match PrepareStencil::STENCIL_BACKGROUND @@ -60,9 +61,13 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); + +// procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(), glm::vec4(glm::vec3(1.0f), 0.9)); + auto textureSlot = procedural.getOpaqueShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getOpaqueShader()->getUniformBuffers().findLocation("skyboxBuffer"); + skybox.prepare(batch, textureSlot, bufferSlot); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index b0842d63cd..de282bed9f 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -36,8 +36,7 @@ public: } }; -Engine::Engine() : Task(EngineTask::JobModel::create("Engine")), - _renderContext(std::make_shared()) +Engine::Engine() : _Engine(EngineTask::JobModel::create("Engine"), std::make_shared()) { } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index f444416a3f..7a5f7b7ce8 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -82,7 +82,9 @@ namespace render { // The render engine holds all render tasks, and is itself a render task. // State flows through tasks to jobs via the render and scene contexts - // the engine should not be known from its jobs. - class Engine : public Task { + class Engine : public _Engine { + + //class Engine : public Task { public: Engine(); @@ -93,19 +95,19 @@ namespace render { void load(); // Register the scene - void registerScene(const ScenePointer& scene) { _renderContext->_scene = scene; } + void registerScene(const ScenePointer& scene) { _context->_scene = scene; } // acces the RenderContext - RenderContextPointer getRenderContext() const { return _renderContext; } + RenderContextPointer getRenderContext() const { return _context; } // Render a frame // Must have a scene registered and a context set - void run() { assert(_renderContext); Task::run(_renderContext); } + // void run() { assert(_renderContext); Task::run(_renderContext); } protected: - RenderContextPointer _renderContext; + // RenderContextPointer _renderContext; - void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); } + // void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); } }; using EnginePointer = std::shared_ptr; diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index c9a3285443..ef1ca60d57 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -379,7 +379,7 @@ public: using TaskType = Task; using ConceptPointer = typename TaskType::ConceptPointer; - Engine(ConceptPointer concept) : TaskType(concept) {} + Engine(const ConceptPointer& concept, const ContextPointer& context) : TaskType(concept), _context(context) {} ~Engine() = default; void reset(const ContextPointer& context) { _context = context; } diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml index 998abdef0e..eff456d838 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -20,7 +20,7 @@ import "../jet.js" as Jet Rectangle { HifiConstants { id: hifi;} color: hifi.colors.baseGray; - id: root + id: root; // width: parent ? parent.width : 200 // height: parent ? parent.height : 400 @@ -29,11 +29,7 @@ Rectangle { Component.onCompleted: { var message = "" - // functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); - - // functor = Jet.job_list_functor(root.myArray); - - var maxDepth = 4; + var maxDepth = 3; var jobTreePath = [] var jobsRoot; @@ -72,6 +68,7 @@ Rectangle { Jet.task_traverseTree(rootConfig, functor); } + ListModel { id: jobsModel } @@ -101,7 +98,7 @@ Rectangle { property var config: root.rootConfig.getConfig(model.path + "." + model.name); text: (objRecursiveColumn.children.length > 2 ? objRecursiveColumn.children[1].visible ? - qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(3) + qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(2) checked: config.enabled } } @@ -113,11 +110,12 @@ Rectangle { } } - ListView { - id: theView - anchors.fill: parent - model: jobsModel - delegate: objRecursiveDelegate + Original.ScrollView { + anchors.fill: parent + ListView { + id: theView + model: jobsModel + delegate: objRecursiveDelegate + } } - } \ No newline at end of file From a57c280813afc5478148db440e3ab1812a5efac0 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 11 May 2018 17:54:08 -0700 Subject: [PATCH 12/69] convertToCloneProperties --- libraries/entities/src/EntityEditPacketSender.cpp | 4 ---- libraries/entities/src/EntityItemProperties.cpp | 11 +++++++++++ libraries/entities/src/EntityItemProperties.h | 2 ++ libraries/entities/src/EntityScriptingInterface.cpp | 1 + libraries/entities/src/EntityTree.cpp | 9 +-------- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index a33f9763e7..c2323b0a20 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -156,10 +156,6 @@ void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityI } void EntityEditPacketSender::queueCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID) { - if (!_shouldSend) { - return; // bail early - } - QByteArray bufferOut(NLPacket::maxPayloadSize(PacketType::EntityClone), 0); if (EntityItemProperties::encodeCloneEntityMessage(entityIDToClone, newEntityID, bufferOut)) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 93c2eb885e..7c799a64e1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3633,3 +3633,14 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash. return verifySignature(EntityItem::_marketplacePublicKey, getStaticCertificateHash(), QByteArray::fromBase64(getCertificateID().toUtf8())); } + +void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { + setName(getName() + "-clone-" + entityIDToClone.toString()); + setLocked(false); + setLifetime(getCloneableLifetime()); + setDynamic(getCloneableDynamic()); + setCloneable(ENTITY_ITEM_CLONEABLE); + setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); + setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); + setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3ae2186cab..12d4bdf919 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -376,6 +376,8 @@ public: bool verifyStaticCertificateProperties(); static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature); + void convertToCloneProperties(const EntityItemID& entityIDToClone); + protected: QString getCollisionMaskAsString() const; void setCollisionMaskFromString(const QString& maskString); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7b7f35aa09..71e7d1c7c0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -332,6 +332,7 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); + properties.convertToCloneProperties(entityIDToClone); if (addLocalEntityCopy(properties, newEntityID)) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 20b3f81f42..bcea89232e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1623,14 +1623,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { if (isClone) { - properties.setName(properties.getName() + "-clone-" + entityIDToClone.toString()); - properties.setLocked(false); - properties.setLifetime(properties.getCloneableLifetime()); - properties.setDynamic(properties.getCloneableDynamic()); - properties.setCloneable(ENTITY_ITEM_CLONEABLE); - properties.setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); - properties.setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); - properties.setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); + properties.convertToCloneProperties(entityIDToClone); } // this is a new entity... assign a new entityID From f74e21902995af02fc39885eb2386868d38136ef Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 15 May 2018 17:24:14 -0700 Subject: [PATCH 13/69] rename properties, add clone avatar entity, remove worldEntityProps arg, fix clone ID cleanup on delete --- libraries/entities/src/EntityItem.cpp | 94 +++++++++++++------ libraries/entities/src/EntityItem.h | 28 +++--- .../entities/src/EntityItemProperties.cpp | 90 +++++++++++------- libraries/entities/src/EntityItemProperties.h | 8 +- .../src/EntityItemPropertiesDefaults.h | 8 +- libraries/entities/src/EntityPropertyFlags.h | 8 +- .../entities/src/EntityScriptingInterface.cpp | 3 +- libraries/entities/src/EntityTree.cpp | 38 +++++--- libraries/entities/src/EntityTree.h | 2 +- .../controllerModules/equipEntity.js | 3 +- .../controllerModules/nearActionGrabEntity.js | 3 +- .../controllerModules/nearParentGrabEntity.js | 3 +- scripts/system/html/js/entityProperties.js | 14 +-- scripts/system/libraries/cloneEntityUtils.js | 4 +- 14 files changed, 192 insertions(+), 114 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9d7e536f25..1e95e999b1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -125,9 +125,11 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_LAST_EDITED_BY; requestedProperties += PROP_CLONEABLE; - requestedProperties += PROP_CLONEABLE_LIFETIME; - requestedProperties += PROP_CLONEABLE_LIMIT; - requestedProperties += PROP_CLONEABLE_DYNAMIC; + requestedProperties += PROP_CLONE_LIFETIME; + requestedProperties += PROP_CLONE_LIMIT; + requestedProperties += PROP_CLONE_DYNAMIC; + requestedProperties += PROP_CLONE_AVATAR_ENTITY; + requestedProperties += PROP_CLONE_ORIGIN_ID; return requestedProperties; } @@ -294,9 +296,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, getLastEditedBy()); APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, getCloneableLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, getCloneableLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, getCloneableDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, getCloneLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, getCloneLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, getCloneDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, getCloneAvatarEntity()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -859,9 +863,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); READ_ENTITY_PROPERTY(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + READ_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, float, setCloneLifetime); + READ_ENTITY_PROPERTY(PROP_CLONE_LIMIT, float, setCloneLimit); + READ_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); + READ_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); + READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1291,9 +1297,11 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(lastEditedBy, getLastEditedBy); COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneable, getCloneable); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableLifetime, getCloneableLifetime); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableLimit, getCloneableLimit); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableDynamic, getCloneableDynamic); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLifetime, getCloneLifetime); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLimit, getCloneLimit); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneDynamic, getCloneDynamic); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneAvatarEntity, getCloneAvatarEntity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneOriginID, getCloneOriginID); properties._defaultSettings = false; @@ -1403,9 +1411,11 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy); SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneable, setCloneable); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableLifetime, setCloneableLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableLimit, setCloneableLimit); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableDynamic, setCloneableDynamic); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLifetime, setCloneLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLimit, setCloneLimit); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneDynamic, setCloneDynamic); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneAvatarEntity, setCloneAvatarEntity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneOriginID, setCloneOriginID); if (updateQueryAACube()) { somethingChanged = true; @@ -3015,45 +3025,73 @@ void EntityItem::setCloneable(bool value) { }); } -float EntityItem::getCloneableLifetime() const { +float EntityItem::getCloneLifetime() const { float result; withReadLock([&] { - result = _cloneableLifetime; + result = _cloneLifetime; }); return result; } -void EntityItem::setCloneableLifetime(float value) { +void EntityItem::setCloneLifetime(float value) { withWriteLock([&] { - _cloneableLifetime = value; + _cloneLifetime = value; }); } -float EntityItem::getCloneableLimit() const { +float EntityItem::getCloneLimit() const { float result; withReadLock([&] { - result = _cloneableLimit; + result = _cloneLimit; }); return result; } -void EntityItem::setCloneableLimit(float value) { +void EntityItem::setCloneLimit(float value) { withWriteLock([&] { - _cloneableLimit = value; + _cloneLimit = value; }); } -bool EntityItem::getCloneableDynamic() const { +bool EntityItem::getCloneDynamic() const { bool result; withReadLock([&] { - result = _cloneableDynamic; + result = _cloneDynamic; }); return result; } -void EntityItem::setCloneableDynamic(const bool value) { +void EntityItem::setCloneDynamic(const bool value) { withWriteLock([&] { - _cloneableDynamic = value; + _cloneDynamic = value; + }); +} + +bool EntityItem::getCloneAvatarEntity() const { + bool result; + withReadLock([&] { + result = _cloneAvatarEntity; + }); + return result; +} + +void EntityItem::setCloneAvatarEntity(const bool value) { + withWriteLock([&] { + _cloneAvatarEntity = value; + }); +} + +const QUuid EntityItem::getCloneOriginID() const { + QUuid result; + withReadLock([&] { + result = _cloneOriginID; + }); + return result; +} + +void EntityItem::setCloneOriginID(const QUuid& value) { + withWriteLock([&] { + _cloneOriginID = value; }); } @@ -3072,4 +3110,4 @@ bool EntityItem::removeCloneID(const QUuid& cloneID) { return true; } return false; -} \ No newline at end of file +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 95cc5f96e1..f314cd1418 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -343,12 +343,16 @@ public: bool getCloneable() const; void setCloneable(bool value); - float getCloneableLifetime() const; - void setCloneableLifetime(float value); - float getCloneableLimit() const; - void setCloneableLimit(float value); - bool getCloneableDynamic() const; - void setCloneableDynamic(const bool value); + float getCloneLifetime() const; + void setCloneLifetime(float value); + float getCloneLimit() const; + void setCloneLimit(float value); + bool getCloneDynamic() const; + void setCloneDynamic(const bool value); + bool getCloneAvatarEntity() const; + void setCloneAvatarEntity(const bool value); + const QUuid getCloneOriginID() const; + void setCloneOriginID(const QUuid& value); // TODO: get rid of users of getRadius()... float getRadius() const; @@ -506,8 +510,6 @@ public: bool addCloneID(const QUuid& cloneID); bool removeCloneID(const QUuid& cloneID); const QList& getCloneIDs() const { return _cloneIDs; } - void setCloneParent(const QUuid& cloneParentID) { _cloneParentID = cloneParentID; } - const QUuid& getCloneParent() const { return _cloneParentID; } signals: void requestRenderUpdate(); @@ -664,12 +666,12 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera bool _cloneable; - float _cloneableLifetime; - float _cloneableLimit; - bool _cloneableDynamic; - + float _cloneLifetime; + float _cloneLimit; + bool _cloneDynamic; + bool _cloneAvatarEntity; + QUuid _cloneOriginID; QList _cloneIDs; - QUuid _cloneParentID; private: std::unordered_map _materials; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7c799a64e1..11ef5a4a84 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -437,9 +437,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); CHECK_PROPERTY_CHANGE(PROP_CLONEABLE, cloneable); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIMIT, cloneableLimit); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + CHECK_PROPERTY_CHANGE(PROP_CLONE_LIFETIME, cloneLifetime); + CHECK_PROPERTY_CHANGE(PROP_CLONE_LIMIT, cloneLimit); + CHECK_PROPERTY_CHANGE(PROP_CLONE_DYNAMIC, cloneDynamic); + CHECK_PROPERTY_CHANGE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); + CHECK_PROPERTY_CHANGE(PROP_CLONE_ORIGIN_ID, cloneOriginID); changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); @@ -1436,9 +1438,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIMIT, cloneableLimit); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIFETIME, cloneLifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIMIT, cloneLimit); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_DYNAMIC, cloneDynamic); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID); // Rendering info if (!skipDefaults && !strictSemantics) { @@ -1653,9 +1657,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI); COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneable, bool, setCloneable); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLifetime, float, setCloneableLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLimit, float, setCloneableLimit); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableDynamic, bool, setCloneableDynamic); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLifetime, float, setCloneLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLimit, float, setCloneLimit); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneDynamic, bool, setCloneDynamic); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneAvatarEntity, bool, setCloneAvatarEntity); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneOriginID, QUuid, setCloneOriginID); _lastEdited = usecTimestampNow(); } @@ -2033,9 +2039,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_DPI, DPI, dpi, uint16_t); ADD_PROPERTY_TO_MAP(PROP_CLONEABLE, Cloneable, cloneable, bool); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float); + ADD_PROPERTY_TO_MAP(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float); + ADD_PROPERTY_TO_MAP(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid); // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2353,9 +2361,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion()); APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, properties.getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, properties.getCloneableLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, properties.getCloneableLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, properties.getCloneableDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, properties.getCloneLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, properties.getCloneLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, properties.getCloneDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, properties.getCloneAvatarEntity()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, properties.getCloneOriginID()); } if (propertyCount > 0) { @@ -2727,9 +2737,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIFETIME, float, setCloneLifetime); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIMIT, float, setCloneLimit); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); return valid; } @@ -2815,7 +2827,7 @@ bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityID char* copyAt = buffer.data(); int outputLength = 0; - if (buffer.size() < (int)(sizeof(NUM_BYTES_RFC4122_UUID) * 2)) { + if (buffer.size() < (int)(NUM_BYTES_RFC4122_UUID * 2)) { qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; return false; } @@ -3021,9 +3033,11 @@ void EntityItemProperties::markAllChanged() { _relayParentJointsChanged = true; _cloneableChanged = true; - _cloneableLifetimeChanged = true; - _cloneableLimitChanged = true; - _cloneableDynamicChanged = true; + _cloneLifetimeChanged = true; + _cloneLimitChanged = true; + _cloneDynamicChanged = true; + _cloneAvatarEntityChanged = true; + _cloneOriginIDChanged = true; } // The minimum bounding box for the entity. @@ -3459,14 +3473,20 @@ QList EntityItemProperties::listChangedProperties() { if (cloneableChanged()) { out += "cloneable"; } - if (cloneableLifetimeChanged()) { - out += "cloneableLifetime"; + if (cloneLifetimeChanged()) { + out += "cloneLifetime"; } - if (cloneableLimitChanged()) { - out += "cloneableLimit"; + if (cloneLimitChanged()) { + out += "cloneLimit"; } - if (cloneableDynamicChanged()) { - out += "cloneableDynamic"; + if (cloneDynamicChanged()) { + out += "cloneDynamic"; + } + if (cloneAvatarEntityChanged()) { + out += "cloneAvatarEntity"; + } + if (cloneOriginIDChanged()) { + out += "cloneOriginID"; } @@ -3637,10 +3657,12 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { setName(getName() + "-clone-" + entityIDToClone.toString()); setLocked(false); - setLifetime(getCloneableLifetime()); - setDynamic(getCloneableDynamic()); + setLifetime(getCloneLifetime()); + setDynamic(getCloneDynamic()); + setClientOnly(getCloneAvatarEntity()); setCloneable(ENTITY_ITEM_CLONEABLE); - setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); - setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); - setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); -} \ No newline at end of file + setCloneLifetime(ENTITY_ITEM_CLONE_LIFETIME); + setCloneLimit(ENTITY_ITEM_CLONE_LIMIT); + setCloneDynamic(ENTITY_ITEM_CLONE_DYNAMIC); + setCloneAvatarEntity(ENTITY_ITEM_CLONE_AVATAR_ENTITY); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 12d4bdf919..a34058c010 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -273,9 +273,11 @@ public: DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); - DEFINE_PROPERTY(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float, ENTITY_ITEM_CLONEABLE_LIFETIME); - DEFINE_PROPERTY(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float, ENTITY_ITEM_CLONEABLE_LIMIT); - DEFINE_PROPERTY(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool, ENTITY_ITEM_CLONEABLE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_CLONE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_CLONE_LIMIT); + DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_CLONE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_CLONE_AVATAR_ENTITY); + DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_CLONE_ORIGIN_ID); static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 6e46453bda..1a31bddebe 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -98,8 +98,10 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; const bool ENTITY_ITEM_CLONEABLE = false; -const float ENTITY_ITEM_CLONEABLE_LIFETIME = 300.0f; -const int ENTITY_ITEM_CLONEABLE_LIMIT = 0; -const bool ENTITY_ITEM_CLONEABLE_DYNAMIC = false; +const float ENTITY_ITEM_CLONE_LIFETIME = 300.0f; +const int ENTITY_ITEM_CLONE_LIMIT = 0; +const bool ENTITY_ITEM_CLONE_DYNAMIC = false; +const bool ENTITY_ITEM_CLONE_AVATAR_ENTITY = false; +const QUuid ENTITY_ITEM_CLONE_ORIGIN_ID = QUuid(); #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index f698739e01..85ab28afdc 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -243,9 +243,11 @@ enum EntityPropertyList { PROP_MATERIAL_DATA, PROP_CLONEABLE, - PROP_CLONEABLE_LIFETIME, - PROP_CLONEABLE_LIMIT, - PROP_CLONEABLE_DYNAMIC, + PROP_CLONE_LIFETIME, + PROP_CLONE_LIMIT, + PROP_CLONE_DYNAMIC, + PROP_CLONE_AVATAR_ENTITY, + PROP_CLONE_ORIGIN_ID, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 71e7d1c7c0..f47a353ae8 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,8 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); - if (addLocalEntityCopy(properties, newEntityID)) { + bool success = addLocalEntityCopy(properties, newEntityID); + if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; } else { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bcea89232e..647edaccc0 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -593,7 +593,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } - removeCloneIDFromCloneParent(entityID); + cleanupCloneIDs(entityID); unhookChildAvatar(entityID); emit deletingEntity(entityID); emit deletingEntityPointer(existingEntity.get()); @@ -627,14 +627,23 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { }); } -void EntityTree::removeCloneIDFromCloneParent(const EntityItemID& entityID) { +void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); if (entity) { - const QUuid& cloneParentID = entity->getCloneParent(); - if (!cloneParentID.isNull()) { - EntityItemPointer cloneParent = findEntityByID(cloneParentID); - if (cloneParent) { - cloneParent->removeCloneID(entityID); + // remove clone ID from it's clone origin's clone ID list if clone origin exists + const QUuid cloneOriginID = entity->getCloneOriginID(); + if (!cloneOriginID.isNull()) { + EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID); + if (cloneOrigin) { + cloneOrigin->removeCloneID(entityID); + } + } + // clear the clone origin ID on any clones that this entity had + const QList& cloneIDs = entity->getCloneIDs(); + foreach(const QUuid& cloneChildID, cloneIDs) { + EntityItemPointer cloneChild = findEntityByEntityItemID(cloneChildID); + if (cloneChild) { + cloneChild->setCloneOriginID(QUuid()); } } } @@ -668,7 +677,7 @@ void EntityTree::deleteEntities(QSet entityIDs, bool force, bool i } // tell our delete operator about this entityID - removeCloneIDFromCloneParent(entityID); + cleanupCloneIDs(entityID); unhookChildAvatar(entityID); theOperator.addEntityIDToDeleteList(entityID); emit deletingEntity(entityID); @@ -1601,7 +1610,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c bool failedAdd = !allowed; bool isCertified = !properties.getCertificateID().isEmpty(); bool isCloneable = properties.getCloneable(); - int cloneLimit = properties.getCloneableLimit(); + int cloneLimit = properties.getCloneLimit(); if (!allowed) { qCDebug(entities) << "Filtered entity add. ID:" << entityItemID; } else if (!isClone && !isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { @@ -1646,14 +1655,15 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } } + if (newEntity && isClone) { + entityToClone->addCloneID(newEntity->getEntityItemID()); + newEntity->setCloneOriginID(entityIDToClone); + } + if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); - if (isClone) { - entityToClone->addCloneID(newEntity->getEntityItemID()); - newEntity->setCloneParent(entityIDToClone); - } - + startLogging = usecTimestampNow(); if (wantEditLogging()) { qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:" diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 0d7cc54df7..aa6e382112 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -117,7 +117,7 @@ public: // check if the avatar is a child of this entity, If so set the avatar parentID to null void unhookChildAvatar(const EntityItemID entityID); - void removeCloneIDFromCloneParent(const EntityItemID& entityID); + void cleanupCloneIDs(const EntityItemID& entityID); void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true); void deleteEntities(QSet entityIDs, bool force = false, bool ignoreWarnings = true); diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 1fce772ec8..b6cad6841d 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -413,8 +413,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.cloneHotspot = function(props, controllerData) { if (entityIsCloneable(props)) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(props, worldEntityProps); + var cloneID = cloneEntity(props); return cloneID; } diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index a4e439fe2f..5e06ed762d 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -235,8 +235,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); // switch to grabbing var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(targetProps, worldEntityProps); + var cloneID = cloneEntity(targetProps); var cloneProps = Entities.getEntityProperties(cloneID); this.targetEntityID = cloneID; this.startNearGrabAction(controllerData, cloneProps); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index d454d20a02..cda0a683c7 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -342,8 +342,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(targetProps, worldEntityProps); + var cloneID = cloneEntity(targetProps); var cloneProps = Entities.getEntityProperties(cloneID); this.grabbing = true; this.targetEntityID = cloneID; diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index c81e51d674..10e7b4b60e 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1041,10 +1041,11 @@ function loaded() { elIgnoreIK.checked = true; elCloneable.checked = properties.cloneable; - elCloneableDynamic.checked = properties.cloneableDynamic; + elCloneableDynamic.checked = properties.cloneDynamic; + elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; - elCloneableLimit.value = properties.cloneableLimit; - elCloneableLifetime.value = properties.cloneableLifetime; + elCloneableLimit.value = properties.cloneLimit; + elCloneableLifetime.value = properties.cloneLifetime; var grabbablesSet = false; var parsedUserData = {}; @@ -1441,9 +1442,10 @@ function loaded() { }); elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); - elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); - elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); - elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic')); + elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index 358bc4a75f..5381d39116 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -41,12 +41,12 @@ entityIsCloneable = function(props) { propsAreCloneDynamic = function(props) { var cloneable = entityIsCloneable(props); if (cloneable) { - return props.cloneableDynamic; + return props.cloneDynamic; } return false; }; -cloneEntity = function(props, worldEntityProps) { +cloneEntity = function(props) { var entityToClone = props.id; var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits From 1e2d2819d512056db75701321e0674ec2c031a41 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 15 May 2018 17:36:39 -0700 Subject: [PATCH 14/69] tweaks --- libraries/entities/src/EntityItemProperties.cpp | 3 --- libraries/entities/src/EntityTree.cpp | 2 +- scripts/system/html/js/entityProperties.js | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 11ef5a4a84..5a2f3a8fc5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2823,7 +2823,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt } bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { - char* copyAt = buffer.data(); int outputLength = 0; @@ -2846,7 +2845,6 @@ bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityID } bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { - const unsigned char* packetData = (const unsigned char*)buffer.constData(); const unsigned char* dataAt = packetData; size_t packetLength = buffer.size(); @@ -3489,7 +3487,6 @@ QList EntityItemProperties::listChangedProperties() { out += "cloneOriginID"; } - getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 647edaccc0..b2daed4e72 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1429,7 +1429,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c case PacketType::EntityClone: isClone = true; // fall through to next case case PacketType::EntityAdd: - isAdd = true; // fall through to next case + isAdd = true; // fall through to next case // FALLTHRU case PacketType::EntityPhysics: case PacketType::EntityEdit: { diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index e016a21731..4271aa9b09 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1042,7 +1042,7 @@ function loaded() { elCloneable.checked = properties.cloneable; elCloneableDynamic.checked = properties.cloneDynamic; - elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; + elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneLimit; elCloneableLifetime.value = properties.cloneLifetime; @@ -1443,7 +1443,7 @@ function loaded() { elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic')); - elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); + elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); From 6c946d7ac5e7f9da7640ef21258f7d60e944609c Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 16 May 2018 11:36:57 -0700 Subject: [PATCH 15/69] prevent continuous clone calls --- .../controllerModules/nearParentGrabEntity.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 0ebd4efb2f..5f310e471f 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -35,6 +35,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.lastUnexpectedChildrenCheckTime = 0; this.robbed = false; this.highlightedEntity = null; + this.cloneAllowed = true; this.parameters = makeDispatcherModuleParameters( 500, @@ -272,6 +273,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { this.checkForUnexpectedChildren(controllerData); this.robbed = false; + this.cloneAllowed = true; return makeRunningValues(false, [], []); } @@ -335,12 +337,14 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var cloneID = cloneEntity(targetProps); - var cloneProps = Entities.getEntityProperties(cloneID); - this.grabbing = true; - this.targetEntityID = cloneID; - this.startNearParentingGrabEntity(controllerData, cloneProps); - + if (this.cloneAllowed) { + var cloneID = cloneEntity(targetProps); + var cloneProps = Entities.getEntityProperties(cloneID); + this.grabbing = true; + this.targetEntityID = cloneID; + this.startNearParentingGrabEntity(controllerData, cloneProps); + this.cloneAllowed = false; + } } else if (targetProps) { this.grabbing = true; this.startNearParentingGrabEntity(controllerData, targetProps); From 06fa4efe055240e900c109bd1b5a9ba705b327b7 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 16 May 2018 11:39:53 -0700 Subject: [PATCH 16/69] add comment --- .../controllers/controllerModules/nearParentGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 5f310e471f..4ab45b33f7 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -343,7 +343,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.grabbing = true; this.targetEntityID = cloneID; this.startNearParentingGrabEntity(controllerData, cloneProps); - this.cloneAllowed = false; + this.cloneAllowed = false; // prevent another clone call until inputs released } } else if (targetProps) { this.grabbing = true; From 3730cbe36c829fa46a2bd83d340e5e2f21bf5d4c Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 10:28:48 -0700 Subject: [PATCH 17/69] reconstruct cloneIDs lists on start, read/write locks on clone ID functions, fix removing last cloneable --- libraries/entities/src/EntityItem.cpp | 36 ++++++++++++++++++++------- libraries/entities/src/EntityItem.h | 3 ++- libraries/entities/src/EntityTree.cpp | 18 +++++++++++++- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1e95e999b1..e6aa572330 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3096,18 +3096,36 @@ void EntityItem::setCloneOriginID(const QUuid& value) { } bool EntityItem::addCloneID(const QUuid& cloneID) { - if (!_cloneIDs.contains(cloneID)) { - _cloneIDs.append(cloneID); - return true; - } + withWriteLock([&] { + if (!_cloneIDs.contains(cloneID)) { + _cloneIDs.append(cloneID); + return true; + } + }); return false; } bool EntityItem::removeCloneID(const QUuid& cloneID) { - int index = _cloneIDs.indexOf(cloneID); - if (index > 0) { - _cloneIDs.removeAt(index); - return true; - } + withWriteLock([&] { + int index = _cloneIDs.indexOf(cloneID); + if (index >= 0) { + _cloneIDs.removeAt(index); + return true; + } + }); return false; } + +const QList EntityItem::getCloneIDs() const { + QList result; + withReadLock([&] { + result = _cloneIDs; + }); + return result; +} + +void EntityItem::setCloneIDs(const QList& cloneIDs) { + withWriteLock([&] { + _cloneIDs = cloneIDs; + }); +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f314cd1418..cc8cefb17b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -509,7 +509,8 @@ public: bool addCloneID(const QUuid& cloneID); bool removeCloneID(const QUuid& cloneID); - const QList& getCloneIDs() const { return _cloneIDs; } + const QList getCloneIDs() const; + void setCloneIDs(const QList& cloneIDs); signals: void requestRenderUpdate(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b2daed4e72..c87f6d771a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -631,7 +631,7 @@ void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); if (entity) { // remove clone ID from it's clone origin's clone ID list if clone origin exists - const QUuid cloneOriginID = entity->getCloneOriginID(); + const QUuid& cloneOriginID = entity->getCloneOriginID(); if (!cloneOriginID.isNull()) { EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID); if (cloneOrigin) { @@ -2385,6 +2385,8 @@ bool EntityTree::readFromMap(QVariantMap& map) { return false; } + QMap> cloneIDs; + bool success = true; foreach (QVariant entityVariant, entitiesQList) { // QVariantMap --> QScriptValue --> EntityItemProperties --> Entity @@ -2477,6 +2479,20 @@ bool EntityTree::readFromMap(QVariantMap& map) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); success = false; } + + const QUuid& cloneOriginID = entity->getCloneOriginID(); + if (!cloneOriginID.isNull()) { + cloneIDs[cloneOriginID].push_back(entity->getEntityItemID()); + } + } + + for (auto iter = cloneIDs.begin(); iter != cloneIDs.end(); ++iter) { + const QUuid& entityID = iter.key(); + const QList& cloneIDs = iter.value(); + EntityItemPointer entity = findEntityByID(entityID); + if (entity) { + entity->setCloneIDs(cloneIDs); + } } return success; From 42d84924274def80ade80cafeb5b7d84aaa3ec44 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 11:17:04 -0700 Subject: [PATCH 18/69] no clock skew --- libraries/entities/src/EntityEditPacketSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index c2323b0a20..9ca102d016 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -34,7 +34,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer Date: Thu, 17 May 2018 11:25:20 -0700 Subject: [PATCH 19/69] Add JSDoc header to new clone function in Entity API --- libraries/entities/src/EntityScriptingInterface.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 883990418a..febc33ffde 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -224,6 +224,14 @@ public slots: Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity); + /**jsdoc + * Request a clone of an entity. Only entities that have been marked as 'cloneable' will be able to be cloned using this method. + * A cloned entity has most of the properties of the orignal entity, and can be requested from clients that do not have rez permissions. + * The client requests a clone from the entity server, which returns back the entityID of a valid clone if the operation was allowed. + * @function Entities.cloneEntity + * @param {Uuid} entityIDToClone - the ID of the entity to clone + * @returns {Entities.EntityID} The ID of the newly created clone + */ Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone); /**jsdoc From b8ce07744da6d0c2c8a963644172529038cd0024 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 14:50:14 -0700 Subject: [PATCH 20/69] initialize prop defaults, no bool returns --- libraries/entities/src/EntityItem.cpp | 8 ++------ libraries/entities/src/EntityItem.h | 14 +++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e6aa572330..667ca9296d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3095,25 +3095,21 @@ void EntityItem::setCloneOriginID(const QUuid& value) { }); } -bool EntityItem::addCloneID(const QUuid& cloneID) { +void EntityItem::addCloneID(const QUuid& cloneID) { withWriteLock([&] { if (!_cloneIDs.contains(cloneID)) { _cloneIDs.append(cloneID); - return true; } }); - return false; } -bool EntityItem::removeCloneID(const QUuid& cloneID) { +void EntityItem::removeCloneID(const QUuid& cloneID) { withWriteLock([&] { int index = _cloneIDs.indexOf(cloneID); if (index >= 0) { _cloneIDs.removeAt(index); - return true; } }); - return false; } const QList EntityItem::getCloneIDs() const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cc8cefb17b..9b1230c843 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -507,8 +507,8 @@ public: void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } - bool addCloneID(const QUuid& cloneID); - bool removeCloneID(const QUuid& cloneID); + void addCloneID(const QUuid& cloneID); + void removeCloneID(const QUuid& cloneID); const QList getCloneIDs() const; void setCloneIDs(const QList& cloneIDs); @@ -666,11 +666,11 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera - bool _cloneable; - float _cloneLifetime; - float _cloneLimit; - bool _cloneDynamic; - bool _cloneAvatarEntity; + bool _cloneable { ENTITY_ITEM_CLONEABLE }; + float _cloneLifetime { ENTITY_ITEM_CLONE_LIFETIME }; + float _cloneLimit { ENTITY_ITEM_CLONE_LIMIT }; + bool _cloneDynamic { ENTITY_ITEM_CLONE_DYNAMIC }; + bool _cloneAvatarEntity { ENTITY_ITEM_CLONE_AVATAR_ENTITY }; QUuid _cloneOriginID; QList _cloneIDs; From 30855f94eb3baed58067ad7d1af8bba1086d9726 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 16:02:58 -0700 Subject: [PATCH 21/69] set last edited to 0 to ensure server update --- libraries/entities/src/EntityScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f47a353ae8..905474fd68 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,6 +333,7 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); + properties.setLastEdited(0); // to ensure we take the properties from the server-created entity bool success = addLocalEntityCopy(properties, newEntityID); if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); From 4e14eb37e304d1216545eb5ba44ccb7187b5bac3 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 16:34:19 -0700 Subject: [PATCH 22/69] update comment --- libraries/entities/src/EntityScriptingInterface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 905474fd68..ca64b3b09d 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,9 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); - properties.setLastEdited(0); // to ensure we take the properties from the server-created entity + // setLastEdited timestamp to 0 to ensure this entity gets updated with the properties + // from the server-created entity, don't change this unless you know what you are doing + properties.setLastEdited(0); bool success = addLocalEntityCopy(properties, newEntityID); if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); From 29b11b910124640c39e59131de2e2443d904368b Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Fri, 18 May 2018 17:12:41 -0700 Subject: [PATCH 23/69] some fixes to server cloneables --- libraries/entities/src/EntityItem.cpp | 6 +++--- libraries/entities/src/EntityItem.h | 16 ++++++++-------- libraries/entities/src/EntityItemProperties.cpp | 10 +++++----- libraries/entities/src/EntityItemProperties.h | 12 ++++++------ .../entities/src/EntityItemPropertiesDefaults.h | 12 ++++++------ .../entities/src/EntityScriptingInterface.cpp | 17 ++++++++++++----- libraries/entities/src/EntityTree.cpp | 9 +++++---- 7 files changed, 45 insertions(+), 37 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 667ca9296d..9bad6f2519 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3112,15 +3112,15 @@ void EntityItem::removeCloneID(const QUuid& cloneID) { }); } -const QList EntityItem::getCloneIDs() const { - QList result; +const QVector EntityItem::getCloneIDs() const { + QVector result; withReadLock([&] { result = _cloneIDs; }); return result; } -void EntityItem::setCloneIDs(const QList& cloneIDs) { +void EntityItem::setCloneIDs(const QVector& cloneIDs) { withWriteLock([&] { _cloneIDs = cloneIDs; }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9b1230c843..42c4605e44 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -509,8 +509,8 @@ public: void addCloneID(const QUuid& cloneID); void removeCloneID(const QUuid& cloneID); - const QList getCloneIDs() const; - void setCloneIDs(const QList& cloneIDs); + const QVector getCloneIDs() const; + void setCloneIDs(const QVector& cloneIDs); signals: void requestRenderUpdate(); @@ -666,13 +666,13 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera - bool _cloneable { ENTITY_ITEM_CLONEABLE }; - float _cloneLifetime { ENTITY_ITEM_CLONE_LIFETIME }; - float _cloneLimit { ENTITY_ITEM_CLONE_LIMIT }; - bool _cloneDynamic { ENTITY_ITEM_CLONE_DYNAMIC }; - bool _cloneAvatarEntity { ENTITY_ITEM_CLONE_AVATAR_ENTITY }; + bool _cloneable { ENTITY_ITEM_DEFAULT_CLONEABLE }; + float _cloneLifetime { ENTITY_ITEM_DEFAULT_CLONE_LIFETIME }; + float _cloneLimit { ENTITY_ITEM_DEFAULT_CLONE_LIMIT }; + bool _cloneDynamic { ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC }; + bool _cloneAvatarEntity { ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY }; QUuid _cloneOriginID; - QList _cloneIDs; + QVector _cloneIDs; private: std::unordered_map _materials; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5a2f3a8fc5..39449c7cd1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3657,9 +3657,9 @@ void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityID setLifetime(getCloneLifetime()); setDynamic(getCloneDynamic()); setClientOnly(getCloneAvatarEntity()); - setCloneable(ENTITY_ITEM_CLONEABLE); - setCloneLifetime(ENTITY_ITEM_CLONE_LIFETIME); - setCloneLimit(ENTITY_ITEM_CLONE_LIMIT); - setCloneDynamic(ENTITY_ITEM_CLONE_DYNAMIC); - setCloneAvatarEntity(ENTITY_ITEM_CLONE_AVATAR_ENTITY); + setCloneable(ENTITY_ITEM_DEFAULT_CLONEABLE); + setCloneLifetime(ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); + setCloneLimit(ENTITY_ITEM_DEFAULT_CLONE_LIMIT); + setCloneDynamic(ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); + setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a34058c010..d00a21435c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -272,12 +272,12 @@ public: DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); - DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); - DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_CLONE_LIFETIME); - DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_CLONE_LIMIT); - DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_CLONE_DYNAMIC); - DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_CLONE_AVATAR_ENTITY); - DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_CLONE_ORIGIN_ID); + DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_DEFAULT_CLONEABLE); + DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_DEFAULT_CLONE_LIMIT); + DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); + DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID); static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 1a31bddebe..0fd926e677 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -97,11 +97,11 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; -const bool ENTITY_ITEM_CLONEABLE = false; -const float ENTITY_ITEM_CLONE_LIFETIME = 300.0f; -const int ENTITY_ITEM_CLONE_LIMIT = 0; -const bool ENTITY_ITEM_CLONE_DYNAMIC = false; -const bool ENTITY_ITEM_CLONE_AVATAR_ENTITY = false; -const QUuid ENTITY_ITEM_CLONE_ORIGIN_ID = QUuid(); +const bool ENTITY_ITEM_DEFAULT_CLONEABLE = false; +const float ENTITY_ITEM_DEFAULT_CLONE_LIFETIME = 300.0f; +const int ENTITY_ITEM_DEFAULT_CLONE_LIMIT = 0; +const bool ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC = false; +const bool ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY = false; +const QUuid ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID = QUuid(); #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f47a353ae8..ace4670fef 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -332,13 +332,20 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); + bool cloneAvatarEntity = properties.getCloneAvatarEntity(); properties.convertToCloneProperties(entityIDToClone); - bool success = addLocalEntityCopy(properties, newEntityID); - if (success) { - getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); - return newEntityID; + + if (cloneAvatarEntity) { + return addEntity(properties, true); } else { - return QUuid(); + bool success = addLocalEntityCopy(properties, newEntityID); + if (success) { + getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); + return newEntityID; + } + else { + return QUuid(); + } } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c87f6d771a..a36ee4be9d 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -639,7 +639,7 @@ void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { } } // clear the clone origin ID on any clones that this entity had - const QList& cloneIDs = entity->getCloneIDs(); + const QVector& cloneIDs = entity->getCloneIDs(); foreach(const QUuid& cloneChildID, cloneIDs) { EntityItemPointer cloneChild = findEntityByEntityItemID(cloneChildID); if (cloneChild) { @@ -1627,7 +1627,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } else if (isClone && !isCloneable) { failedAdd = true; qCDebug(entities) << "User attempted to clone non-cloneable entity from entity ID:" << entityIDToClone; - } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit) { + } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit && cloneLimit != 0) { failedAdd = true; qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { @@ -2039,6 +2039,7 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons if (shouldEraseEntity(entityID, sourceNode)) { entityItemIDsToDelete << entityItemID; + cleanupCloneIDs(entityItemID); } } @@ -2385,7 +2386,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { return false; } - QMap> cloneIDs; + QMap> cloneIDs; bool success = true; foreach (QVariant entityVariant, entitiesQList) { @@ -2488,7 +2489,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { for (auto iter = cloneIDs.begin(); iter != cloneIDs.end(); ++iter) { const QUuid& entityID = iter.key(); - const QList& cloneIDs = iter.value(); + const QVector& cloneIDs = iter.value(); EntityItemPointer entity = findEntityByID(entityID); if (entity) { entity->setCloneIDs(cloneIDs); From 6c8d68afc61ccc917f019664f7bed1b1f6a9d2ff Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Fri, 18 May 2018 18:18:42 -0700 Subject: [PATCH 24/69] add extra cleanup in delete messages and simulation, as a fall back --- libraries/entities/src/EntitySimulation.cpp | 1 + libraries/entities/src/EntityTree.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index d034ddedbe..ba088cb7fd 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -65,6 +65,7 @@ void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { removeEntityInternal(entity); if (entity->getElement()) { _deadEntities.insert(entity); + _entityTree->cleanupCloneIDs(entity->getEntityItemID()); } } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a36ee4be9d..b698ac6eb8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1990,6 +1990,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo if (shouldEraseEntity(entityID, sourceNode)) { entityItemIDsToDelete << entityItemID; + cleanupCloneIDs(entityItemID); } } deleteEntities(entityItemIDsToDelete, true, true); From 6d4f70427921ef9d94509d3a2d820a464b695067 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 21 May 2018 09:32:10 +1200 Subject: [PATCH 25/69] Regularize some JSDoc usage --- interface/src/Application.cpp | 2 +- interface/src/FancyCamera.h | 2 +- interface/src/avatar/MyAvatar.h | 2 +- .../src/raypick/PickScriptingInterface.h | 33 ++++++++++--------- .../src/raypick/PointerScriptingInterface.cpp | 6 ++-- .../scripting/WindowScriptingInterface.cpp | 2 +- .../src/scripting/WindowScriptingInterface.h | 2 +- interface/src/ui/overlays/Overlays.h | 2 +- .../src/avatars-renderer/Avatar.h | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- .../controllers/src/controllers/Actions.cpp | 2 +- .../controllers/src/controllers/InputDevice.h | 2 +- .../src/controllers/StandardController.cpp | 2 +- .../entities/src/AnimationPropertyGroup.cpp | 2 +- .../entities/src/EntityItemProperties.cpp | 2 +- .../src/input-plugins/KeyboardMouseDevice.cpp | 2 +- libraries/networking/src/AddressManager.h | 2 +- libraries/networking/src/DomainHandler.h | 2 +- .../src/AssetScriptingInterface.h | 8 ++--- libraries/script-engine/src/Quat.h | 2 +- .../src/SceneScriptingInterface.h | 6 ++-- libraries/script-engine/src/ScriptUUID.h | 2 +- libraries/shared/src/shared/Camera.h | 13 ++++---- libraries/ui/src/QmlFragmentClass.h | 2 +- .../ui/src/ui/TabletScriptingInterface.h | 2 +- .../oculus/src/OculusControllerManager.cpp | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 2 +- 27 files changed, 56 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 467c8c9a2c..266c085d99 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -715,7 +715,7 @@ private: * NavigationFocusednumbernumberNot used. * * - * @typedef Controller.Hardware-Application + * @typedef {object} Controller.Hardware-Application */ static const QString STATE_IN_HMD = "InHMD"; diff --git a/interface/src/FancyCamera.h b/interface/src/FancyCamera.h index bee21bad22..4ca073fb4f 100644 --- a/interface/src/FancyCamera.h +++ b/interface/src/FancyCamera.h @@ -25,7 +25,7 @@ class FancyCamera : public Camera { // FIXME: JSDoc 3.5.5 doesn't augment @property definitions. The following definition is repeated in Camera.h. /**jsdoc - * @property cameraEntity {Uuid} The ID of the entity that the camera position and orientation follow when the camera is in + * @property {Uuid} cameraEntity The ID of the entity that the camera position and orientation follow when the camera is in * entity mode. */ Q_PROPERTY(QUuid cameraEntity READ getCameraEntity WRITE setCameraEntity) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa6a675d99..fe6ba71c13 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -121,7 +121,7 @@ class MyAvatar : public Avatar { * while flying. * @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if * hmdRollControlEnabled is enabled. - * @property hmdRollControlRate {number} If hmdRollControlEnabled is true, this value determines the maximum turn rate of + * @property {number} hmdRollControlRate If hmdRollControlEnabled is true, this value determines the maximum turn rate of * your avatar when rolling your HMD in degrees per second. * @property {number} userHeight=1.75 - The height of the user in sensor space. * @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. Read-only. diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index a39aa3a4a1..5ef5d27d74 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -22,21 +22,22 @@ * @hifi-interface * @hifi-client-entity * - * @property PICK_NOTHING {number} A filter flag. Don't intersect with anything. Read-only. - * @property PICK_ENTITIES {number} A filter flag. Include entities when intersecting. Read-only. - * @property PICK_OVERLAYS {number} A filter flag. Include overlays when intersecting. Read-only. - * @property PICK_AVATARS {number} A filter flag. Include avatars when intersecting. Read-only. - * @property PICK_HUD {number} A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only. - * @property PICK_COARSE {number} A filter flag. Pick against coarse meshes, instead of exact meshes. Read-only. - * @property PICK_INCLUDE_INVISIBLE {number} A filter flag. Include invisible objects when intersecting. Read-only. - * @property PICK_INCLUDE_NONCOLLIDABLE {number} A filter flag. Include non-collidable objects when intersecting. + * @property {number} PICK_NOTHING A filter flag. Don't intersect with anything. Read-only. + * @property {number} PICK_ENTITIES A filter flag. Include entities when intersecting. Read-only. + * @property {number} PICK_OVERLAYS A filter flag. Include overlays when intersecting. Read-only. + * @property {number} PICK_AVATARS A filter flag. Include avatars when intersecting. Read-only. + * @property {number} PICK_HUD A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only. + * @property {number} PICK_COARSE A filter flag. Pick against coarse meshes, instead of exact meshes. Read-only. + * @property {number} PICK_INCLUDE_INVISIBLE A filter flag. Include invisible objects when intersecting. Read-only. + * @property {number} PICK_INCLUDE_NONCOLLIDABLE A filter flag. Include non-collidable objects when intersecting. * Read-only. - * @property PICK_ALL_INTERSECTIONS {number} Read-only. - * @property INTERSECTED_NONE {number} An intersection type. Intersected nothing with the given filter flags. Read-only. - * @property INTERSECTED_ENTITY {number} An intersection type. Intersected an entity. Read-only. - * @property INTERSECTED_OVERLAY {number} An intersection type. Intersected an overlay. Read-only. - * @property INTERSECTED_AVATAR {number} An intersection type. Intersected an avatar. Read-only. - * @property INTERSECTED_HUD {number} An intersection type. Intersected the HUD sphere. Read-only. + * @property {number} PICK_ALL_INTERSECTIONS Read-only. + * @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags. + * Read-only. + * @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. Read-only. + * @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. Read-only. + * @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. Read-only. + * @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. Read-only. * @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results. Read-only. */ @@ -99,7 +100,7 @@ public: /**jsdoc * An intersection result for a Ray Pick. * - * @typedef {Object} RayPickResult + * @typedef {object} RayPickResult * @property {number} type The intersection type. * @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE) * @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections. @@ -113,7 +114,7 @@ public: /**jsdoc * An intersection result for a Stylus Pick. * - * @typedef {Object} StylusPickResult + * @typedef {object} StylusPickResult * @property {number} type The intersection type. * @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE) * @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections. diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index b7ac899c8d..4e953a5cb8 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -68,14 +68,14 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) * A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.RayPointerRenderState}, * but with an additional distance field. * - * @typedef {Object} Pointers.DefaultRayPointerRenderState + * @typedef {object} Pointers.DefaultRayPointerRenderState * @augments Pointers.RayPointerRenderState * @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined. */ /**jsdoc * A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something. * - * @typedef {Object} Pointers.RayPointerRenderState + * @typedef {object} Pointers.RayPointerRenderState * @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} * @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). * An overlay to represent the beginning of the Ray Pointer, if desired. @@ -87,7 +87,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) /**jsdoc * A trigger mechanism for Ray Pointers. * - * @typedef {Object} Pointers.Trigger + * @typedef {object} Pointers.Trigger * @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger button. * @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered, * it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None". diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 6f6e83842c..af9b5c8a46 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -522,7 +522,7 @@ int WindowScriptingInterface::openMessageBox(QString title, QString text, int bu * RestoreDefaults 0x8000000 "Restore Defaults" * * - * @typedef Window.MessageBoxButton + * @typedef {number} Window.MessageBoxButton */ int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) { auto messageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text, diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 1d06f33ec0..d280d797d6 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -470,7 +470,7 @@ public slots: * * * - * @typedef Window.DisplayTexture + * @typedef {string} Window.DisplayTexture */ bool setDisplayTexture(const QString& name); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 3ff782da99..d100b228ed 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -53,7 +53,7 @@ const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); * @property {number} distance - The distance from the {@link PickRay} origin to the intersection point. * @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point. * @property {Vec3} intersection - The position of the intersection point. - * @property {Object} extraInfo Additional intersection details, if available. + * @property {object} extraInfo Additional intersection details, if available. */ class RayToOverlayIntersectionResult { public: diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 01114b5f6d..0f48e03e55 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -292,7 +292,7 @@ public: */ /**jsdoc * Information about a single joint in an Avatar's skeleton hierarchy. - * @typedef MyAvatar.SkeletonJoint + * @typedef {object} MyAvatar.SkeletonJoint * @property {string} name - Joint name. * @property {number} index - Joint index. * @property {number} parentIndex - Index of this joint's parent (-1 if no parent). diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7a28686f8c..48ef1fb881 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2363,7 +2363,7 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const } /**jsdoc - * @typedef AttachmentData + * @typedef {object} AttachmentData * @property {string} modelUrl * @property {string} jointName * @property {Vec3} translation diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index 978b0888ba..6923ef4b98 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -307,7 +307,7 @@ namespace controller { * action. * * - * @typedef Controller.Actions + * @typedef {object} Controller.Actions */ // Device functions Input::NamedVector ActionsDevice::getAvailableInputs() const { diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 30a58eb2f0..1e626e6a3c 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -79,7 +79,7 @@ enum Hand { * {@link Controller.Hardware-Vive}. * * - * @typedef Controller.Hardware + * @typedef {object} Controller.Hardware * @example List all the currently available Controller.Hardware properties. * function printProperties(string, item) { * print(string); diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index 471943400d..e1733d2524 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -231,7 +231,7 @@ void StandardController::focusOutEvent() { * * * - * @typedef Controller.Standard + * @typedef {object} Controller.Standard */ Input::NamedVector StandardController::getAvailableInputs() const { static Input::NamedVector availableInputs { diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp index 43c6b7a6a5..2db85eb7ac 100644 --- a/libraries/entities/src/AnimationPropertyGroup.cpp +++ b/libraries/entities/src/AnimationPropertyGroup.cpp @@ -46,7 +46,7 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b /**jsdoc * The AnimationProperties are used to configure an animation. - * @typedef Entities.AnimationProperties + * @typedef {object} Entities.AnimationProperties * @property {string} url="" - The URL of the FBX file that has the animation. * @property {number} fps=30 - The speed in frames/s that the animation is played at. * @property {number} firstFrame=0 - The first frame to play in the animation. diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4d7c114176..0def76f1bb 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1391,7 +1391,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool /**jsdoc * The axis-aligned bounding box of an entity. - * @typedef Entities.BoundingBox + * @typedef {object} Entities.BoundingBox * @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box. * @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box. * @property {Vec3} center - The center of the AA box. diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 8ecf527a14..650c9675a7 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -279,7 +279,7 @@ controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevic * moved down. The data value is how far the average position of all touch points moved. * * - * @typedef Controller.Hardware-Keyboard + * @typedef {object} Controller.Hardware-Keyboard * @todo Currently, the mouse wheel in an ordinary mouse generates left/right wheel events instead of up/down. */ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const { diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 7832b26c96..a12a18fa6a 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -138,7 +138,7 @@ public: * * * - * @typedef location.LookupTrigger + * @typedef {number} location.LookupTrigger */ enum LookupTrigger { UserInput, diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 08908dbaf6..4d98391104 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -137,7 +137,7 @@ public: * * * - * @typedef Window.ConnectionRefusedReason + * @typedef {number} Window.ConnectionRefusedReason */ enum class ConnectionRefusedReason : uint8_t { Unknown, diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 7f7a3a68b0..72d6901fb5 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -121,7 +121,7 @@ public: /**jsdoc * A set of properties that can be passed to {@link Assets.getAsset}. - * @typedef {Object} Assets.GetOptions + * @typedef {object} Assets.GetOptions * @property {string} [url] an "atp:" style URL, hash, or relative mapped path to fetch * @property {string} [responseType=text] the desired reponse type (text | arraybuffer | json) * @property {boolean} [decompress=false] whether to attempt gunzip decompression on the fetched data @@ -137,7 +137,7 @@ public: /**jsdoc * Result value returned by {@link Assets.getAsset}. - * @typedef {Object} Assets~getAssetResult + * @typedef {object} Assets~getAssetResult * @property {string} [url] the resolved "atp:" style URL for the fetched asset * @property {string} [hash] the resolved hash for the fetched asset * @property {string|ArrayBuffer|Object} [response] response data (possibly converted per .responseType value) @@ -159,7 +159,7 @@ public: /**jsdoc * A set of properties that can be passed to {@link Assets.putAsset}. - * @typedef {Object} Assets.PutOptions + * @typedef {object} Assets.PutOptions * @property {ArrayBuffer|string} [data] byte buffer or string value representing the new asset's content * @property {string} [path=null] ATP path mapping to automatically create (upon successful upload to hash) * @property {boolean} [compress=false] whether to gzip compress data before uploading @@ -174,7 +174,7 @@ public: /**jsdoc * Result value returned by {@link Assets.putAsset}. - * @typedef {Object} Assets~putAssetResult + * @typedef {object} Assets~putAssetResult * @property {string} [url] the resolved "atp:" style URL for the uploaded asset (based on .path if specified, otherwise on the resulting ATP hash) * @property {string} [path] the uploaded asset's resulting ATP path (or undefined if no path mapping was assigned) * @property {string} [hash] the uploaded asset's resulting ATP hash diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 1ccdfdbf31..76b7ac45e3 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -43,7 +43,7 @@ * @hifi-server-entity * @hifi-assignment-client * - * @property IDENTITY {Quat} { x: 0, y: 0, z: 0, w: 1 } : The identity rotation, i.e., no rotation. + * @property {Quat} IDENTITY - { x: 0, y: 0, z: 0, w: 1 } : The identity rotation, i.e., no rotation. * Read-only. * @example Print the IDENTITY value. * print(JSON.stringify(Quat.IDENTITY)); // { x: 0, y: 0, z: 0, w: 1 } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index fdfbc6f6c0..da42cf2df3 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -21,7 +21,7 @@ namespace SceneScripting { /**jsdoc - * @typedef Scene.Stage.Location + * @typedef {object} Scene.Stage.Location * @property {number} longitude * @property {number} latitude * @property {number} altitude @@ -49,7 +49,7 @@ namespace SceneScripting { using LocationPointer = std::unique_ptr; /**jsdoc - * @typedef Scene.Stage.Time + * @typedef {object} Scene.Stage.Time * @property {number} hour * @property {number} day */ @@ -73,7 +73,7 @@ namespace SceneScripting { using TimePointer = std::unique_ptr