diff --git a/examples/edit.js b/examples/edit.js
index 2974397cde..e61822558c 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -1349,6 +1349,15 @@ PropertiesTool = function(opts) {
pushCommandForSelections();
selectionManager._update();
}
+ } else if (data.action == "reloadScript") {
+ if (selectionManager.hasSelection()) {
+ var timestamp = Date.now();
+ for (var i = 0; i < selectionManager.selections.length; i++) {
+ Entities.editEntity(selectionManager.selections[i], {
+ scriptTimestamp: timestamp,
+ });
+ }
+ }
} else if (data.action == "centerAtmosphereToZone") {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index 27a2929d1c..b4b336fbda 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -250,6 +250,8 @@
var elCollisionSoundURL = document.getElementById("property-collision-sound-url");
var elLifetime = document.getElementById("property-lifetime");
var elScriptURL = document.getElementById("property-script-url");
+ var elScriptTimestamp = document.getElementById("property-script-timestamp");
+ var elReloadScriptButton = document.getElementById("reload-script-button");
var elUserData = document.getElementById("property-user-data");
var elColorSection = document.getElementById("color-section");
@@ -470,6 +472,7 @@
elCollisionSoundURL.value = properties.collisionSoundURL;
elLifetime.value = properties.lifetime;
elScriptURL.value = properties.script;
+ elScriptTimestamp.value = properties.scriptTimestamp;
elUserData.value = properties.userData;
elHyperlinkHref.value = properties.href;
@@ -688,6 +691,7 @@
elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime'));
elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script'));
+ elScriptTimestamp.addEventListener('change', createEmitNumberPropertyUpdateFunction('scriptTimestamp'));
elUserData.addEventListener('change', createEmitTextPropertyUpdateFunction('userData'));
var colorChangeFunction = createEmitColorPropertyUpdateFunction(
@@ -889,6 +893,12 @@
percentage: parseInt(elRescaleDimensionsPct.value),
}));
});
+ elReloadScriptButton.addEventListener("click", function() {
+ EventBridge.emitWebEvent(JSON.stringify({
+ type: "action",
+ action: "reloadScript"
+ }));
+ });
elCenterAtmosphereToZone.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
type: "action",
@@ -1138,7 +1148,10 @@
-
Script URL
+
Script URL
+
+
+
diff --git a/examples/html/style.css b/examples/html/style.css
index dd2e96ab43..8564479ac7 100644
--- a/examples/html/style.css
+++ b/examples/html/style.css
@@ -250,6 +250,11 @@ table#properties-list {
height: 1.2em;
}
+#properties-list .label input[type=button] {
+ float: right;
+ padding: 0 5px 1px;
+}
+
#properties-list .value > div{
padding: 3pt 0;
}
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index e1bd01547e..845c870d90 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -155,13 +155,14 @@ void EntityTreeRenderer::errorInLoadingScript(const QUrl& url) {
}
}
-QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID, bool isPreload) {
+QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID, bool isPreload, bool reload) {
EntityItemPointer entity = static_cast
(_tree)->findEntityByEntityItemID(entityItemID);
- return loadEntityScript(entity, isPreload);
+ return loadEntityScript(entity, isPreload, reload);
}
-QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& urlOut) {
+QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& urlOut,
+ bool& reload) {
isPending = false;
QUrl url(scriptMaybeURLorText);
@@ -199,7 +200,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
auto scriptCache = DependencyManager::get();
if (!scriptCache->isInBadScriptList(url)) {
- scriptContents = scriptCache->getScript(url, this, isPending);
+ scriptContents = scriptCache->getScript(url, this, isPending, reload);
}
}
}
@@ -208,7 +209,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
}
-QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool isPreload) {
+QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool isPreload, bool reload) {
if (_shuttingDown) {
return QScriptValue(); // since we're shutting down, we don't load any more scripts
}
@@ -228,8 +229,8 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
- // check to make sure our script text hasn't changed on us since we last loaded it
- if (details.scriptText == entityScript) {
+ // check to make sure our script text hasn't changed on us since we last loaded it and we're not redownloading it
+ if (details.scriptText == entityScript && !reload) {
return details.scriptObject; // previously loaded
}
@@ -244,7 +245,7 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool
bool isURL = false; // loadScriptContents() will tell us if this is a URL or just text.
bool isPending = false;
QUrl url;
- QString scriptContents = loadScriptContents(entityScript, isURL, isPending, url);
+ QString scriptContents = loadScriptContents(entityScript, isURL, isPending, url, reload);
if (isPending && isPreload && isURL) {
_waitingOnPreload.insert(url, entityID);
@@ -1029,17 +1030,17 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
}
-void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) {
+void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const bool reload) {
if (_tree && !_shuttingDown) {
checkAndCallUnload(entityID);
- checkAndCallPreload(entityID);
+ checkAndCallPreload(entityID, reload);
}
}
-void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) {
+void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
if (_tree && !_shuttingDown) {
// load the entity script if needed...
- QScriptValue entityScript = loadEntityScript(entityID, true); // is preload!
+ QScriptValue entityScript = loadEntityScript(entityID, true, reload); // is preload!
if (entityScript.property("preload").isValid()) {
QScriptValueList entityArgs = createEntityArgs(entityID);
entityScript.property("preload").call(entityScript, entityArgs);
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h
index e491524c78..451aed6ce5 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.h
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.h
@@ -110,7 +110,7 @@ signals:
public slots:
void addingEntity(const EntityItemID& entityID);
void deletingEntity(const EntityItemID& entityID);
- void entitySciptChanging(const EntityItemID& entityID);
+ void entitySciptChanging(const EntityItemID& entityID, const bool reload);
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
// optional slots that can be wired to menu items
@@ -127,7 +127,7 @@ private:
void applyZonePropertiesToScene(std::shared_ptr zone);
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
- void checkAndCallPreload(const EntityItemID& entityID);
+ void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
void checkAndCallUnload(const EntityItemID& entityID);
QList _releasedModels;
@@ -148,10 +148,10 @@ private:
ScriptEngine* _entitiesScriptEngine;
ScriptEngine* _sandboxScriptEngine;
- QScriptValue loadEntityScript(EntityItemPointer entity, bool isPreload = false);
- QScriptValue loadEntityScript(const EntityItemID& entityItemID, bool isPreload = false);
+ QScriptValue loadEntityScript(EntityItemPointer entity, bool isPreload = false, bool reload = false);
+ QScriptValue loadEntityScript(const EntityItemID& entityItemID, bool isPreload = false, bool reload = false);
QScriptValue getPreviouslyLoadedEntityScript(const EntityItemID& entityItemID);
- QString loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& url);
+ QString loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& url, bool& reload);
QScriptValueList createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID);
QScriptValueList createMouseEventArgs(const EntityItemID& entityID, const MouseEvent& mouseEvent);
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index d2881e5f3a..63a770ab7a 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -54,6 +54,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_friction(ENTITY_ITEM_DEFAULT_FRICTION),
_lifetime(ENTITY_ITEM_DEFAULT_LIFETIME),
_script(ENTITY_ITEM_DEFAULT_SCRIPT),
+ _scriptTimestamp(ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
_collisionSoundURL(ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
_registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
_angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
@@ -107,6 +108,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_FRICTION;
requestedProperties += PROP_LIFETIME;
requestedProperties += PROP_SCRIPT;
+ requestedProperties += PROP_SCRIPT_TIMESTAMP;
requestedProperties += PROP_COLLISION_SOUND_URL;
requestedProperties += PROP_REGISTRATION_POINT;
requestedProperties += PROP_ANGULAR_VELOCITY;
@@ -238,6 +240,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_FRICTION, getFriction());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, getScript());
+ APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, getScriptTimestamp());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping());
@@ -555,6 +558,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
+ READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
//READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
@@ -901,6 +905,7 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(scriptTimestamp, getScriptTimestamp);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getAngularVelocity);
@@ -967,6 +972,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
// non-simulation properties below
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptTimestamp, setScriptTimestamp);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 73f9127361..8d9ad244ef 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -276,6 +276,10 @@ public:
const QString& getScript() const { return _script; }
void setScript(const QString& value) { _script = value; }
+
+ const quint64 getScriptTimestamp() const { return _scriptTimestamp; }
+ void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; }
+
const QString& getCollisionSoundURL() const { return _collisionSoundURL; }
void setCollisionSoundURL(const QString& value) { _collisionSoundURL = value; }
@@ -412,6 +416,7 @@ protected:
float _friction;
float _lifetime;
QString _script;
+ quint64 _scriptTimestamp;
QString _collisionSoundURL;
glm::vec3 _registrationPoint;
glm::vec3 _angularVelocity;
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index cbb3b1dc31..471d191d17 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -51,6 +51,7 @@ CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(created, UNKNOWN_CREATED_TIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
+CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
@@ -299,6 +300,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_FRICTION, friction);
CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime);
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
+ CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp);
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
@@ -391,6 +393,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate));
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(scriptTimestamp);
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
@@ -503,6 +506,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime);
COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(scriptTimestamp, quint64, setScriptTimestamp);
COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint);
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
@@ -710,6 +714,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_FRICTION, properties.getFriction());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, properties.getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, properties.getScript());
+ APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, properties.getScriptTimestamp());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, properties.getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity());
@@ -961,7 +966,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RESTITUTION, float, setRestitution);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FRICTION, float, setFriction);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime);
- READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT,QString, setScript);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT, QString, setScript);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity);
@@ -1099,6 +1105,7 @@ void EntityItemProperties::markAllChanged() {
_userDataChanged = true;
_simulatorIDChanged = true;
_scriptChanged = true;
+ _scriptTimestampChanged = true;
_collisionSoundURLChanged = true;
_registrationPointChanged = true;
_angularVelocityChanged = true;
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 068bc98f7e..294aab7f75 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -98,6 +98,7 @@ public:
DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float);
DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64);
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
+ DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64);
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
@@ -259,6 +260,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Friction, friction, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifetime, lifetime, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
+ DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h
index 11341b160c..7ca93a3f33 100644
--- a/libraries/entities/src/EntityItemPropertiesDefaults.h
+++ b/libraries/entities/src/EntityItemPropertiesDefaults.h
@@ -32,6 +32,7 @@ const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
+const quint64 ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP = 0;
const QString ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL = QString("");
const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = ENTITY_ITEM_HALF_VEC3; // center
diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h
index 0f3459e5d2..d4fcfa8cab 100644
--- a/libraries/entities/src/EntityItemPropertiesMacros.h
+++ b/libraries/entities/src/EntityItemPropertiesMacros.h
@@ -92,6 +92,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { r
inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); }
+inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { return QScriptValue((qsreal)v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
@@ -134,6 +135,7 @@ typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
typedef QVector qVectorVec3;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
+inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index f1ebdb8a1f..666f9e0346 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -55,6 +55,7 @@ enum EntityPropertyList {
PROP_DAMPING,
PROP_LIFETIME,
PROP_SCRIPT,
+ PROP_SCRIPT_TIMESTAMP,
// these properties are supported by some derived classes
PROP_COLOR,
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 363f3c56d7..752082932b 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -185,6 +185,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
// else client accepts what the server says
QString entityScriptBefore = entity->getScript();
+ quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
uint32_t preFlags = entity->getDirtyFlags();
UpdateEntityOperator theOperator(this, containingElement, entity, properties);
@@ -206,8 +207,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
}
QString entityScriptAfter = entity->getScript();
- if (entityScriptBefore != entityScriptAfter) {
- emitEntityScriptChanging(entity->getEntityItemID()); // the entity script has changed
+ quint64 entityScriptTimestampAfter = entity->getScriptTimestamp();
+ bool reload = entityScriptTimestampBefore != entityScriptTimestampAfter;
+ if (entityScriptBefore != entityScriptAfter || reload) {
+ emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed
}
maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
}
@@ -266,9 +269,10 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
return result;
}
-void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
- emit entityScriptChanging(entityItemID);
+void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, const bool reload) {
+ emit entityScriptChanging(entityItemID, reload);
}
+
void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) {
if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) {
emit newCollisionSoundURL(QUrl(nextCollisionSoundURL));
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 1ad3ef6b1c..9c4be9a86f 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -155,7 +155,7 @@ public:
void entityChanged(EntityItemPointer entity);
- void emitEntityScriptChanging(const EntityItemID& entityItemID);
+ void emitEntityScriptChanging(const EntityItemID& entityItemID, const bool reload);
void setSimulation(EntitySimulation* simulation);
EntitySimulation* getSimulation() const { return _simulation; }
@@ -171,7 +171,7 @@ public:
signals:
void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID);
- void entityScriptChanging(const EntityItemID& entityItemID);
+ void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
void newCollisionSoundURL(const QUrl& url);
void clearingEntities();
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index 80333a44e5..4bc81e1da6 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -733,6 +733,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
// 3) remember the old cube for the entity so we can mark it as dirty
if (entityItem) {
QString entityScriptBefore = entityItem->getScript();
+ quint64 entityScriptTimestampBefore = entityItem->getScriptTimestamp();
bool bestFitBefore = bestFitEntityBounds(entityItem);
EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID);
@@ -755,8 +756,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
}
QString entityScriptAfter = entityItem->getScript();
- if (entityScriptBefore != entityScriptAfter) {
- _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed
+ quint64 entityScriptTimestampAfter = entityItem->getScriptTimestamp();
+ bool reload = entityScriptTimestampBefore != entityScriptTimestampAfter;
+ if (entityScriptBefore != entityScriptAfter || reload) {
+ _myTree->emitEntityScriptChanging(entityItemID, reload); // the entity script has changed
}
} else {
diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp
index 78bb3f11e1..f989c417f0 100644
--- a/libraries/networking/src/PacketHeaders.cpp
+++ b/libraries/networking/src/PacketHeaders.cpp
@@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityData:
- return VERSION_ENTITIES_LINE_POINTS;
+ return VERSION_ENTITIES_SCRIPT_TIMESTAMP;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h
index 228df1cdde..5780e7bec2 100644
--- a/libraries/networking/src/PacketHeaders.h
+++ b/libraries/networking/src/PacketHeaders.h
@@ -183,5 +183,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29;
+const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 30;
#endif // hifi_PacketHeaders_h
diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp
index ae16494af3..2047442ce6 100644
--- a/libraries/script-engine/src/ScriptCache.cpp
+++ b/libraries/script-engine/src/ScriptCache.cpp
@@ -27,11 +27,11 @@ ScriptCache::ScriptCache(QObject* parent) {
// nothing to do here...
}
-QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& isPending, bool redownload) {
- assert(!_scriptCache.contains(url) || !redownload);
+QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& isPending, bool reload) {
+ assert(!_scriptCache.contains(url) || !reload);
QString scriptContents;
- if (_scriptCache.contains(url)) {
+ if (_scriptCache.contains(url) && !reload) {
qCDebug(scriptengine) << "Found script in cache:" << url.toString();
scriptContents = _scriptCache[url];
scriptUser->scriptContentsAvailable(url, scriptContents);
@@ -47,8 +47,8 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
- if (redownload) {
- networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
+ if (reload) {
+ networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
qCDebug(scriptengine) << "Redownloading script at:" << url.toString();
} else {
qCDebug(scriptengine) << "Downloading script at:" << url.toString();