overte-JulianGro/libraries/entities/src/EntityScriptingInterface.h
2019-06-22 11:59:07 +12:00

2509 lines
136 KiB
C++

//
// EntityScriptingInterface.h
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 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
//
// TODO: How will we handle collision callbacks with Entities
//
#ifndef hifi_EntityScriptingInterface_h
#define hifi_EntityScriptingInterface_h
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtQml/QJSValue>
#include <QtQml/QJSValueList>
#include <DependencyManager.h>
#include <Octree.h>
#include <OctreeScriptingInterface.h>
#include <RegisteredMetaTypes.h>
#include <PointerEvent.h>
#include <PickFilter.h>
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
#include "PolyLineEntityItem.h"
#include "EntityTree.h"
#include "EntityEditPacketSender.h"
#include "EntitiesScriptEngineProvider.h"
#include "EntityItemProperties.h"
#include "BaseScriptEngine.h"
class EntityTree;
class MeshProxy;
extern const QString GRABBABLE_USER_DATA;
extern const QString NOT_GRABBABLE_USER_DATA;
// helper factory to compose standardized, async metadata queries for "magic" Entity properties
// like .script and .serverScripts. This is used for automated testing of core scripting features
// as well as to provide early adopters a self-discoverable, consistent way to diagnose common
// problems with their own Entity scripts.
class EntityPropertyMetadataRequest {
public:
EntityPropertyMetadataRequest(BaseScriptEngine* engine) : _engine(engine) {};
bool script(EntityItemID entityID, QScriptValue handler);
bool serverScripts(EntityItemID entityID, QScriptValue handler);
private:
QPointer<BaseScriptEngine> _engine;
};
/**jsdoc
* The result of a {@link Entities.findRayIntersection|findRayIntersection} search using a {@link PickRay}.
* @typedef {object} Entities.RayToEntityIntersectionResult
* @property {boolean} intersects - <code>true</code> if the {@link PickRay} intersected an entity, otherwise
* <code>false</code>.
* @property {boolean} accurate - Is always <code>true</code>.
* @property {Uuid} entityID - The ID if the entity intersected, if any, otherwise <code>null</code>.
* @property {number} distance - The distance from the {@link PickRay} origin to the intersection point.
* @property {Vec3} intersection - The intersection point.
* @property {Vec3} surfaceNormal - The surface normal of the entity at the intersection point.
* @property {BoxFace} face - The face of the entity's axis-aligned box that the ray intersects.
* @property {object} extraInfo - Extra information depending on the entity intersected. Currently, only <code>Model</code>
* entities provide extra information, and the information provided depends on the <code>precisionPicking</code> parameter
* value that the search function was called with.
*/
// "accurate" is currently always true because the ray intersection is always performed with an Octree::Lock.
class RayToEntityIntersectionResult {
public:
bool intersects { false };
bool accurate { true };
QUuid entityID;
float distance { 0.0f };
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
};
Q_DECLARE_METATYPE(RayToEntityIntersectionResult)
QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& results);
void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& results);
class ParabolaToEntityIntersectionResult {
public:
bool intersects { false };
bool accurate { true };
QUuid entityID;
float distance { 0.0f };
float parabolicDistance { 0.0f };
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
};
/**jsdoc
* The <code>Entities</code> API provides facilities to create and interact with entities. Entities are 2D or 3D objects
* displayed in-world. Depending on their {@link Entities.EntityHostType|EntityHostType}, they may persist in the domain as
* "domain" entities, travel to different domains with a user as "avatar" entities, or be visible only to an individual user as
* "local" entities (a.k.a. "overlays").
*
* <p>Note: For Interface scripts, the entities available to scripts are those that Interface has displayed and so knows
* about.</p>
*
* <h3>Entity Methods</h3>
*
* <p>Some of the API's signals correspond to entity methods that are called if, if present, in the entity being interacted
* with. The client or server entity script must expose them as a property. However, unlike {@link Entities.callEntityMethod},
* server entity scripts do not need to list them in an <code>remotelyCallable</code> property. The entity methods are called
* with parameters per their corresponding signal.</p>
* <table>
* <thead>
* <tr><th>Method Name</th><th>Corresponding Signal</th></tr>
* </thead>
* <tbody>
* <tr><td><code>clickDownOnEntity</code></td><td>{@link Entities.clickDownOnEntity}</td></tr>
* <tr><td><code>clickReleaseOnEntity</code></td><td>{@link Entities.clickReleaseOnEntity}</td></tr>
* <tr><td><code>collisionWithEntity</code></td><td>{@link Entities.collisionWithEntity}</td></tr>
* <tr><td><code>enterEntity</code></td><td>{@link Entities.enterEntity}</td></tr>
* <tr><td><code>holdingClickOnEntity</code></td><td>{@link Entities.holdingClickOnEntity}</td></tr>
* <tr><td><code>hoverEnterEntity</code></td><td>{@link Entities.hoverEnterEntity}</td></tr>
* <tr><td><code>hoverLeaveEntity</code></td><td>{@link Entities.hoverLeaveEntity}</td></tr>
* <tr><td><code>hoverOverEntity</code></td><td>{@link Entities.hoverOverEntity}</td></tr>
* <tr><td><code>leaveEntity</code></td><td>{@link Entities.leaveEntity}</td></tr>
* <tr><td><code>mouseDoublePressOnEntity</code></td><td>{@link Entities.mouseDoublePressOnEntity}</td></tr>
* <tr><td><code>mouseMoveOnEntity</code></td><td>{@link Entities.mouseMoveOnEntity}</td></tr>
* <tr><td><code>mouseMoveEvent</code></td><td><span class="important">Deprecated: This is a synonym for
* <code>mouseMoveOnEntity</code>.</span></td></tr>
* <tr><td><code>mousePressOnEntity</code></td><td>{@link Entities.mousePressOnEntity}</td></tr>
* <tr><td><code>mouseReleaseOnEntity</code></td><td>{@link Entities.mouseReleaseOnEntity}</td></tr>
* </tbody>
* </table>
* <p>See {@link Entities.clickDownOnEntity} for an example.</p>
*
* @namespace Entities
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
* @hifi-server-entity
* @hifi-assignment-client
*
* @property {Uuid} keyboardFocusEntity - The {@link Entities.EntityProperties-Web|Web} entity that has keyboard focus. If no
* Web entity has keyboard focus, get returns <code>null</code>; set to <code>null</code> or {@link Uuid(0)|Uuid.NULL} to
* clear keyboard focus.
*/
/// handles scripting of Entity commands from JS passed to assigned clients
class EntityScriptingInterface : public OctreeScriptingInterface, public Dependency {
Q_OBJECT
Q_PROPERTY(QUuid keyboardFocusEntity READ getKeyboardFocusEntity WRITE setKeyboardFocusEntity)
friend EntityPropertyMetadataRequest;
public:
EntityScriptingInterface(bool bidOnSimulationOwnership);
class ActivityTracking {
public:
int addedEntityCount { 0 };
int deletedEntityCount { 0 };
int editedEntityCount { 0 };
};
EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); }
virtual NodeType_t getServerNodeType() const override { return NodeType::EntityServer; }
virtual OctreeEditPacketSender* createPacketSender() override { return new EntityEditPacketSender(); }
void setEntityTree(EntityTreePointer modelTree);
EntityTreePointer getEntityTree() { return _entityTree; }
void setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine);
void resetActivityTracking();
ActivityTracking getActivityTracking() const { return _activityTracking; }
RayToEntityIntersectionResult evalRayIntersectionVector(const PickRay& ray, PickFilter searchFilter,
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard);
ParabolaToEntityIntersectionResult evalParabolaIntersectionVector(const PickParabola& parabola, PickFilter searchFilter,
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard);
/**jsdoc
* Gets the properties of multiple entities.
* @function Entities.getMultipleEntityProperties
* @param {Uuid[]} entityIDs - The IDs of the entities to get the properties of.
* @param {string[]|string} [desiredProperties=[]] - The name or names of the properties to get. For properties that are
* objects (e.g., the <code>"keyLight"</code> property), use the property and subproperty names in dot notation (e.g.,
* <code>"keyLight.color"</code>).
* @returns {Entities.EntityProperties[]} The specified properties of each entity for each entity that can be found. If
* none of the entities can be found then an empty array. If no properties are specified, then all properties are
* returned.
* @example <caption>Retrieve the names of the nearby entities</caption>
* var SEARCH_RADIUS = 50; // meters
* var entityIDs = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
* var propertySets = Entities.getMultipleEntityProperties(entityIDs, "name");
* print("Nearby entity names: " + JSON.stringify(propertySets));
*/
static QScriptValue getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine);
QScriptValue getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector<QUuid> entityIDs, const QScriptValue& extendedDesiredProperties);
QUuid addEntityInternal(const EntityItemProperties& properties, entity::HostType entityHostType);
public slots:
/**jsdoc
* Checks whether or not the script can change the <code>locked</code> property of entities. Locked entities have their
* <code>locked</code> property set to <code>true</code> and cannot be edited or deleted.
* @function Entities.canAdjustLocks
* @returns {boolean} <code>true</code> if the domain server will allow the script to change the <code>locked</code>
* property of entities, otherwise <code>false</code>.
* @example <caption>Lock an entity if you can.</caption>
* if (Entities.canAdjustLocks()) {
* Entities.editEntity(entityID, { locked: true });
* } else {
* Window.alert("You do not have the permissions to set an entity locked!");
* }
*/
Q_INVOKABLE bool canAdjustLocks();
/**jsdoc
* Checks whether or not the script can rez (create) new entities in the domain.
* @function Entities.canRez
* @returns {boolean} <code>true</code> if the domain server will allow the script to rez (create) new entities, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool canRez();
/**jsdoc
* Checks whether or not the script can rez (create) new temporary entities in the domain. Temporary entities are entities
* with a finite <code>lifetime</code> property value set.
* @function Entities.canRezTmp
* @returns {boolean} <code>true</code> if the domain server will allow the script to rez (create) new temporary entities,
* otherwise <code>false</code>.
*/
Q_INVOKABLE bool canRezTmp();
/**jsdoc
* Checks whether or not the script can rez (create) new certified entities in the domain. Certified entities are entities
* that have PoP certificates.
* @function Entities.canRezCertified
* @returns {boolean} <code>true</code> if the domain server will allow the script to rez (create) new certified entities,
* otherwise <code>false</code>.
*/
Q_INVOKABLE bool canRezCertified();
/**jsdoc
* Checks whether or not the script can rez (create) new temporary certified entities in the domain. Temporary entities are
* entities with a finite <code>lifetime</code> property value set. Certified entities are entities that have PoP
* certificates.
* @function Entities.canRezTmpCertified
* @returns {boolean} <code>true</code> if the domain server will allow the script to rez (create) new temporary certified
* entities, otherwise <code>false</code>.
*/
Q_INVOKABLE bool canRezTmpCertified();
/**jsdoc
* Checks whether or not the script can make changes to the asset server's assets.
* @function Entities.canWriteAssets
* @returns {boolean} <code>true</code> if the domain server will allow the script to make changes to the asset server's
* assets, otherwise <code>false</code>.
*/
Q_INVOKABLE bool canWriteAssets();
/**jsdoc
* Checks whether or not the script can replace the domain's content set.
* @function Entities.canReplaceContent
* @returns {boolean} <code>true</code> if the domain server will allow the script to replace the domain's content set,
* otherwise <code>false</code>.
*/
Q_INVOKABLE bool canReplaceContent();
/**jsdoc
* Checks whether or not the script can get and set the <code>privateUserData</code> property of entities.
* @function Entities.canGetAndSetPrivateUserData
* @returns {boolean} <code>true</code> if the domain server will allow the script to get and set the
* <code>privateUserData</code> property of entities, otherwise <code>false</code>.
*/
Q_INVOKABLE bool canGetAndSetPrivateUserData();
/**jsdoc
* <p>How an entity is hosted and sent to others for display.</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"domain"</code></td><td>Domain entities are stored on the domain, are visible to everyone, and are
* sent to everyone by the entity server.</td></tr>
* <tr><td><code>"avatar"</code></td><td>Avatar entities are stored on an Interface client, are visible to everyone,
* and are sent to everyone by the avatar mixer. They follow the client to each domain visited, displaying at the
* same domain coordinates unless parented to the client's avatar.</td></tr>
* <tr><td><code>"local"</code></td><td>Local entities are ephemeral &mdash; they aren't stored anywhere &mdash; and
* are visible only to the client. They follow the client to each domain visited, displaying at the same domain
* coordinates unless parented to the client's avatar. Additionally, local entities are collisionless.</td></tr>
* </tbody>
* </table>
* @typedef {string} Entities.EntityHostType
*/
/**jsdoc
* Adds a new domain, avatar, or local entity.
* @function Entities.addEntity
* @param {Entities.EntityProperties} properties - The properties of the entity to create.
* @param {Entities.EntityHostType} [entityHostType="domain"] - The type of entity to create.
* @returns {Uuid} The ID of the entity if successfully created, otherwise {@link Uuid(0)|Uuid.NULL}.
* @example <caption>Create a box domain entity in front of your avatar.</caption>
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* lifetime: 300 // Delete after 5 minutes.
* });
* print("Entity created: " + entityID);
*/
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, const QString& entityHostTypeString) {
entity::HostType entityHostType;
if (entityHostTypeString == "local") {
entityHostType = entity::HostType::LOCAL;
} else if (entityHostTypeString == "avatar") {
entityHostType = entity::HostType::AVATAR;
} else {
entityHostType = entity::HostType::DOMAIN;
}
return addEntityInternal(properties, entityHostType);
}
/**jsdoc
* Adds a new avatar entity (<code>{@link Entities.EntityProperties|entityHostType}</code> property is
* <code>"avatar"</code>) or domain entity (<code>{@link Entities.EntityProperties|entityHostType}</code> property is
* <code>"domain"</code>).
* @function Entities.addEntity
* @param {Entities.EntityProperties} properties - The properties of the entity to create.
* @param {boolean} [avatarEntity=false] - <code>true</code> to create an avatar entity, <code>false</code> to create a
* domain entity.
* @returns {Uuid} The ID of the entity if successfully created, otherwise {@link Uuid(0)|Uuid.NULL}.
*/
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, bool avatarEntity = false) {
entity::HostType entityHostType = avatarEntity ? entity::HostType::AVATAR : entity::HostType::DOMAIN;
return addEntityInternal(properties, entityHostType);
}
/// temporary method until addEntity can be used from QJSEngine
/// Deliberately not adding jsdoc, only used internally.
// FIXME: Deprecate and remove from the API.
Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic,
bool collisionless, bool grabbable, const glm::vec3& position, const glm::vec3& gravity);
/**jsdoc
* Creates a clone of an entity. The clone has a modified <code>name</code> property, other properties set per the original
* entity's clone-related {@link Entities.EntityProperties|properties} (e.g., <code>cloneLifetime</code>), and
* clone-related properties set to defaults.
* <p>Domain entities must have their <code>cloneable</code> property value be <code>true</code> in order to be cloned. A
* domain entity can be cloned by a client that doesn't have rez permissions in the domain.</p>
* <p>Avatar entities must have their <code>cloneable</code> and <code>cloneAvatarEntity</code> property values be
* <code>true</code> in order to be cloned.</p>
* @function Entities.cloneEntity
* @param {Uuid} entityID - The ID of the entity to clone.
* @returns {Uuid} The ID of the new entity if successfully cloned, otherwise {@link Uuid(0)|Uuid.NULL}.
*/
Q_INVOKABLE QUuid cloneEntity(const QUuid& entityID);
/**jsdoc
* Gets an entity's property values.
* @function Entities.getEntityProperties
* @param {Uuid} entityID - The ID of the entity to get the properties of.
* @param {string|string[]} [desiredProperties=[]] - The name or names of the properties to get. For properties that are
* objects (e.g., the <code>"keyLight"</code> property), use the property and subproperty names in dot notation (e.g.,
* <code>"keyLight.color"</code>).
* @returns {Entities.EntityProperties} The specified properties of the entity if the entity can be found, otherwise an
* empty object. If no properties are specified, then all properties are returned.
* @example <caption>Report the color of a new box entity.</caption>
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* lifetime: 300 // Delete after 5 minutes.
* });
* var properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color));
*/
Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(const QUuid& entityID, EntityPropertyFlags desiredProperties);
/**jsdoc
* Edits an entity, changing one or more of its property values.
* @function Entities.editEntity
* @param {Uuid} entityID - The ID of the entity to edit.
* @param {Entities.EntityProperties} properties - The new property values.
* @returns {Uuid} The ID of the entity if the edit was successful, otherwise <code>null</code> or {@link Uuid|Uuid.NULL}.
* @example <caption>Change the color of an entity.</caption>
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* lifetime: 300 // Delete after 5 minutes.
* });
* var properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color));
*
* Script.setTimeout(function () { // Wait for entity to finish creation before editing.
* Entities.editEntity(entityID, {
* color: { red: 255, green: 0, blue: 0 }
* });
* properties = Entities.getEntityProperties(entityID, ["color"]);
* print("Entity color: " + JSON.stringify(properties.color));
* }, 50);
*/
Q_INVOKABLE QUuid editEntity(const QUuid& entityID, const EntityItemProperties& properties);
/**jsdoc
* Deletes an entity.
* @function Entities.deleteEntity
* @param {Uuid} entityID - The ID of the entity to delete.
* @example <caption>Delete an entity a few seconds after creating it.</caption>
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 }
* });
*
* Script.setTimeout(function () {
* Entities.deleteEntity(entityID);
* }, 3000);
*/
Q_INVOKABLE void deleteEntity(const QUuid& entityID);
/**jsdoc
* Gets an entity's type.
* @function Entities.getEntityType
* @param {Uuid} id - The ID of the entity to get the type of.
* @returns {Entities.EntityType} The type of the entity.
*/
Q_INVOKABLE QString getEntityType(const QUuid& entityID);
/**jsdoc
* Gets an entity's script object. In particular, this is useful for accessing a {@link Entities.EntityProperties-Web|Web}
* entity's HTML <code>EventBridge</code> script object to exchange messages with the web page script.
* <p>Alternatively, you can use {@link Entities.emitScriptEvent} and {@link Entities.webEventReceived} to exchange
* messages with a Web entity over its event bridge.</p>
* @function Entities.getEntityObject
* @param {Uuid} id - The ID of the entity to get the script object for.
* @returns {object} The script object for the entity if found.
* @example <caption>Exchange messages with a Web entity.</caption>
* // HTML file, name: "webEntity.html".
* <!DOCTYPE html>
* <html>
* <head>
* <title>HELLO</title>
* </head>
* <body>
* <h1>HELLO</h1></h1>
* <script>
* function onScriptEventReceived(message) {
* // Message received from the script.
* console.log("Message received: " + message);
* }
*
* EventBridge.scriptEventReceived.connect(onScriptEventReceived);
*
* setTimeout(function () {
* // Send a message to the script.
* EventBridge.emitWebEvent("hello");
* }, 5000);
* </script>
* </body>
* </html>
*
* // Script file.
* var webEntity = Entities.addEntity({
* type: "Web",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })),
* rotation: MyAvatar.orientation,
* sourceUrl: Script.resolvePath("webEntity.html"),
* alpha: 1.0,
* lifetime: 300 // 5 min
* });
*
* var webEntityObject;
*
* function onWebEventReceived(message) {
* // Message received.
* print("Message received: " + message);
*
* // Send a message back.
* webEntityObject.emitScriptEvent(message + " back");
* }
*
* Script.setTimeout(function () {
* webEntityObject = Entities.getEntityObject(webEntity);
* webEntityObject.webEventReceived.connect(onWebEventReceived);
* }, 500);
*
* Script.scriptEnding.connect(function () {
* Entities.deleteEntity(webEntity);
* });
*/
Q_INVOKABLE QObject* getEntityObject(const QUuid& id);
/**jsdoc
* Checks whether an entities's assets have been loaded. For example, for an <code>Model</code> entity the result indicates
* whether its textures have been loaded.
* @function Entities.isLoaded
* @param {Uuid} id - The ID of the entity to check.
* @returns {boolean} <code>true</code> if the entity's assets have been loaded, otherwise <code>false</code>.
*/
Q_INVOKABLE bool isLoaded(const QUuid& id);
/**jsdoc
* Checks if there is an entity with a specified ID.
* @function Entities.isAddedEntity
* @param {Uuid} id - The ID to check.
* @returns {boolean} <code>true</code> if an entity with the specified ID exists, <code>false</code> if it doesn't.
*/
Q_INVOKABLE bool isAddedEntity(const QUuid& id);
/**jsdoc
* Calculates the size of some text in a text entity.
* @function Entities.textSize
* @param {Uuid} id - The ID of the entity to use for calculation.
* @param {string} text - The string to calculate the size of.
* @returns {Size} The size of the <code>text</code> in meters if the object is a text entity, otherwise
* <code>{ height: 0, width : 0 }</code>.
*/
Q_INVOKABLE QSizeF textSize(const QUuid& id, const QString& text);
/**jsdoc
* Calls a method in a client entity script from an Interface, avatar, or client entity script, or calls a method in a
* server entity script from a server entity script. The entity script method must be exposed as a property in the target
* entity script. Additionally, if calling a server entity script, the server entity script must include the method's name
* in an exposed property called <code>remotelyCallable</code> that is an array of method names that can be called.
* @function Entities.callEntityMethod
* @param {Uuid} entityID - The ID of the entity to call the method in.
* @param {string} method - The name of the method to call. The method is called with the entity ID as the first parameter
* and the <code>parameters</code> value as the second parameter.
* @param {string[]} [parameters=[]] - The additional parameters to call the specified method with.
* @example <caption>Call a method in a client entity script from an Interface script.</caption>
* // Client entity script.
* var entityScript = (function () {
* this.entityMethod = function (id, params) {
* print("Method at entity : " + id + " ; " + params[0] + ", " + params[1]);
* };
* });
*
* // Entity that hosts the client entity script.
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* script: "(" + entityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Interface script call to the client entity script.
* Script.setTimeout(function () {
* Entities.callEntityMethod(entityID, "entityMethod", ["hello", 12]);
* }, 1000); // Wait for the entity to be created.
*/
Q_INVOKABLE void callEntityMethod(const QUuid& entityID, const QString& method, const QStringList& params = QStringList());
/**jsdoc
* Calls a method in a server entity script from an Interface, avatar, or client entity script. The server entity script
* method must be exposed as a property in the target server entity script. Additionally, the server entity script must
* include the method's name in an exposed property called <code>remotelyCallable</code> that is an array of method names
* that can be called.
* @function Entities.callEntityServerMethod
* @param {Uuid} entityID - The ID of the entity to call the method in.
* @param {string} method - The name of the method to call. The method is called with the entity ID as the first parameter
* and the <code>parameters</code> value as the second parameter.
* @param {string[]} [parameters=[]] - The additional parameters to call the specified method with.
* @example <caption>Call a method in a server entity script from an Interface script.</caption>
* // Server entity script.
* var entityScript = (function () {
* this.entityMethod = function (id, params) {
* print("Method at entity : " + id + " ; " + params[0] + ", " + params[1]); // In server log.
* };
* this.remotelyCallable = [
* "entityMethod"
* ];
* });
*
* // Entity that hosts the server entity script.
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* serverScripts: "(" + entityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Interface script call to the server entity script.
* Script.setTimeout(function () {
* Entities.callEntityServerMethod(entityID, "entityMethod", ["hello", 12]);
* }, 1000); // Wait for the entity to be created.
*/
Q_INVOKABLE void callEntityServerMethod(const QUuid& entityID, const QString& method, const QStringList& params = QStringList());
/**jsdoc
* Calls a method in a specific user's client entity script from a server entity script. The entity script method must be
* exposed as a property in the target client entity script. Additionally, the client entity script must
* include the method's name in an exposed property called <code>remotelyCallable</code> that is an array of method names
* that can be called.
* @function Entities.callEntityClientMethod
* @param {Uuid} clientSessionID - The session ID of the user to call the method in.
* @param {Uuid} entityID - The ID of the entity to call the method in.
* @param {string} method - The name of the method to call. The method is called with the entity ID as the first parameter
* and the <code>parameters</code> value as the second parameter.
* @param {string[]} [parameters=[]] - The additional parameters to call the specified method with.
* @example <caption>Call a method in a client entity script from a server entity script.</caption>
* // Client entity script.
* var clientEntityScript = (function () {
* this.entityMethod = function (id, params) {
* print("Method at client entity : " + id + " ; " + params[0] + ", " + params[1]);
* };
* this.remotelyCallable = [
* "entityMethod"
* ];
* });
*
* // Server entity script.
* var serverEntityScript = (function () {
* var clientSessionID,
* clientEntityID;
*
* function callClientMethod() {
* // Server entity script call to client entity script.
* Entities.callEntityClientMethod(clientSessionID, clientEntityID, "entityMethod", ["hello", 12]);
* }
*
* // Obtain client entity details then call client entity method.
* this.entityMethod = function (id, params) {
* clientSessionID = params[0];
* clientEntityID = params[1];
* callClientMethod();
* };
* this.remotelyCallable = [
* "entityMethod"
* ];
* });
*
* // Entity that hosts the client entity script.
* var clientEntityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: -1, y: 0, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* script: "(" + clientEntityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Entity that hosts the server entity script.
* var serverEntityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 1, y: 0, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* serverScripts: "(" + serverEntityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Interface script call to the server entity script.
* Script.setTimeout(function () {
* Entities.callEntityServerMethod(serverEntityID, "entityMethod", [MyAvatar.sessionUUID, clientEntityID]);
* }, 1000); // Wait for the entities to be created.
*/
Q_INVOKABLE void callEntityClientMethod(const QUuid& clientSessionID, const QUuid& entityID, const QString& method,
const QStringList& params = QStringList());
/**jsdoc
* Finds the domain or avatar entity with a position closest to a specified point and within a specified radius.
* @function Entities.findClosestEntity
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
* @returns {Uuid} The ID of the entity that is closest to the <code>center</code> and within the <code>radius</code>, if
* there is one, otherwise <code>null</code>.
* @example <caption>Find the closest entity within 10m of your avatar.</caption>
* var entityID = Entities.findClosestEntity(MyAvatar.position, 10);
* print("Closest entity: " + entityID);
*/
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const;
/**jsdoc
* Finds all domain and avatar entities that intersect a sphere.
* @function Entities.findEntities
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
* @returns {Uuid[]} An array of entity IDs that intersect the search sphere. The array is empty if no entities could be
* found.
* @example <caption>Report how many entities are within 10m of your avatar.</caption>
* var entityIDs = Entities.findEntities(MyAvatar.position, 10);
* print("Number of entities within 10m: " + entityIDs.length);
*/
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntities(const glm::vec3& center, float radius) const;
/**jsdoc
* Finds all domain and avatar entities whose axis-aligned boxes intersect a search axis-aligned box.
* @function Entities.findEntitiesInBox
* @param {Vec3} corner - The corner of the search AA box with minimum co-ordinate values.
* @param {Vec3} dimensions - The dimensions of the search AA box.
* @returns {Uuid[]} An array of entity IDs whose AA boxes intersect the search AA box. The array is empty if no entities
* could be found.
*/
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
/**jsdoc
* Finds all domain and avatar entities whose axis-aligned boxes intersect a search frustum.
* @function Entities.findEntitiesInFrustum
* @param {ViewFrustum} frustum - The frustum to search in. The <code>position</code>, <code>orientation</code>,
* <code>projection</code>, and <code>centerRadius</code> properties must be specified.
* @returns {Uuid[]} An array of entity IDs whose axis-aligned boxes intersect the search frustum. The array is empty if no
* entities could be found.
* @example <caption>Report the number of entities in view.</caption>
* var entityIDs = Entities.findEntitiesInFrustum(Camera.frustum);
* print("Number of entities in view: " + entityIDs.length);
*/
/// this function will not find any models in script engine contexts which don't have access to entities
Q_INVOKABLE QVector<QUuid> findEntitiesInFrustum(QVariantMap frustum) const;
/**jsdoc
* Finds all domain and avatar entities of a particular type that intersect a sphere.
* @function Entities.findEntitiesByType
* @param {Entities.EntityType} entityType - The type of entity to search for.
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
* @returns {Uuid[]} An array of entity IDs of the specified type that intersect the search sphere. The array is empty if
* no entities could be found.
* @example <caption>Report the number of Model entities within 10m of your avatar.</caption>
* var entityIDs = Entities.findEntitiesByType("Model", MyAvatar.position, 10);
* print("Number of Model entities within 10m: " + entityIDs.length);
*/
/// this function will not find any entities in script engine contexts which don't have access to entities
Q_INVOKABLE QVector<QUuid> findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const;
/**jsdoc
* Finds all domain and avatar entities with a particular name that intersect a sphere.
* @function Entities.findEntitiesByName
* @param {string} entityName - The name of the entity to search for.
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
* @param {boolean} [caseSensitive=false] - If <code>true</code> then the search is case-sensitive.
* @returns {Uuid[]} An array of entity IDs that have the specified name and intersect the search sphere. The array is
* empty if no entities could be found.
* @example <caption>Report the number of entities with the name, "Light-Target".</caption>
* var entityIDs = Entities.findEntitiesByName("Light-Target", MyAvatar.position, 10, false);
* print("Number of entities with the name Light-Target: " + entityIDs.length);
*/
Q_INVOKABLE QVector<QUuid> findEntitiesByName(const QString entityName, const glm::vec3& center, float radius,
bool caseSensitiveSearch = false) const;
/**jsdoc
* Finds the first avatar or domain entity intersected by a {@link PickRay}. <code>Light</code> and <code>Zone</code>
* entities are not intersected unless they've been configured as pickable using
* {@link Entities.setLightsArePickable|setLightsArePickable} and {@link Entities.setZonesArePickable|setZonesArePickable},
* respectively.
* @function Entities.findRayIntersection
* @param {PickRay} pickRay - The pick ray to use for finding entities.
* @param {boolean} [precisionPicking=false] - <code>true</code> to pick against precise meshes, <code>false</code> to pick
* against coarse meshes. If <code>true</code> and the intersected entity is a <code>Model</code> entity, the result's
* <code>extraInfo</code> property includes more information than it otherwise would.
* @param {Uuid[]} [entitiesToInclude=[]] - If not empty then the search is restricted to these entities.
* @param {Uuid[]} [entitiesToDiscard=[]] - Entities to ignore during the search.
* @param {boolean} [visibleOnly=false] - If <code>true</code> then only entities that are
* <code>{@link Entities.EntityProperties|visible}</code> are searched.
* @param {boolean} [collideableOnly=false] - If <code>true</code> then only entities that are not
* <code>{@link Entities.EntityProperties|collisionless}</code> are searched.
* @returns {Entities.RayToEntityIntersectionResult} The result of the search for the first intersected entity.
* @example <caption>Find the entity directly in front of your avatar.</caption>
* var pickRay = {
* origin: MyAvatar.position,
* direction: Quat.getFront(MyAvatar.orientation)
* };
*
* var intersection = Entities.findRayIntersection(pickRay, true);
* if (intersection.intersects) {
* print("Entity in front of avatar: " + intersection.entityID);
* } else {
* print("No entity in front of avatar.");
* }
*/
/// If the scripting context has visible entities, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
/// will be false.
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false,
const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue(),
bool visibleOnly = false, bool collidableOnly = false) const;
/**jsdoc
* Reloads an entity's server entity script such that the latest version re-downloaded.
* @function Entities.reloadServerScripts
* @param {Uuid} entityID - The ID of the entity to reload the server entity script of.
* @returns {boolean} <code>true</code> if the reload request was successfully sent to the server, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool reloadServerScripts(const QUuid& entityID);
/**jsdoc
* Gets the status of a server entity script attached to an entity.
* @function Entities.getServerScriptStatus
* @param {Uuid} entityID - The ID of the entity to get the server entity script status of.
* @param {Entities~getServerScriptStatusCallback} callback - The function to call upon completion.
* @returns {boolean} <code>true</code> always.
*/
/**jsdoc
* Called when a {@link Entities.getServerScriptStatus} call is complete.
* @callback Entities~getServerScriptStatusCallback
* @param {boolean} success - <code>true</code> if the server entity script status could be obtained, otherwise
* <code>false</code>.
* @param {boolean} isRunning - <code>true</code> if there is a server entity script running, otherwise <code>false</code>.
* @param {string} status - <code>"running"</code> if there is a server entity script running, otherwise an error string.
* @param {string} errorInfo - <code>""</code> if there is a server entity script running, otherwise it may contain extra
* information on the error.
*/
Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, QScriptValue callback);
/**jsdoc
* Gets metadata for certain entity properties such as <code>script</code> and <code>serverScripts</code>.
* @function Entities.queryPropertyMetadata
* @param {Uuid} entityID - The ID of the entity to get the metadata for.
* @param {string} property - The property name to get the metadata for.
* @param {Entities~queryPropertyMetadataCallback} callback - The function to call upon completion.
* @returns {boolean} <code>true</code> if the request for metadata was successfully sent to the server, otherwise
* <code>false</code>.
* @throws Throws an error if <code>property</code> is not handled yet or <code>callback</code> is not a function.
*/
/**jsdoc
* Gets metadata for certain entity properties such as <code>script</code> and <code>serverScripts</code>.
* @function Entities.queryPropertyMetadata
* @param {Uuid} entityID - The ID of the entity to get the metadata for.
* @param {string} property - The property name to get the metadata for.
* @param {object} scope - The "<code>this</code>" context that the callback will be executed within.
* @param {Entities~queryPropertyMetadataCallback} callback - The function to call upon completion.
* @returns {boolean} <code>true</code> if the request for metadata was successfully sent to the server, otherwise
* <code>false</code>.
* @throws Throws an error if <code>property</code> is not handled yet or <code>callback</code> is not a function.
*/
/**jsdoc
* Called when a {@link Entities.queryPropertyMetadata} call is complete.
* @callback Entities~queryPropertyMetadataCallback
* @param {string} error - <code>undefined</code> if there was no error, otherwise an error message.
* @param {object} result - The metadata for the requested entity property if there was no error, otherwise
* <code>undefined</code>.
*/
Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, QScriptValue property, QScriptValue scopeOrCallback,
QScriptValue methodOrName = QScriptValue());
/**jsdoc
* Sets whether or not ray picks intersect the bounding box of {@link Entities.EntityProperties-Light|Light} entities. By
* default, Light entities are not intersected. The setting lasts for the Interface session. Ray picks are done using
* {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.setLightsArePickable
* @param {boolean} value - <code>true</code> to make ray picks intersect the bounding box of
* {@link Entities.EntityProperties-Light|Light} entities, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE void setLightsArePickable(bool value);
/**jsdoc
* Gets whether or not ray picks intersect the bounding box of {@link Entities.EntityProperties-Light|Light} entities. Ray
* picks are done using {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.getLightsArePickable
* @returns {boolean} <code>true</code> if ray picks intersect the bounding box of
* {@link Entities.EntityProperties-Light|Light} entities, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool getLightsArePickable() const;
/**jsdoc
* Sets whether or not ray picks intersect the bounding box of {@link Entities.EntityProperties-Zone|Zone} entities. By
* default, Zone entities are not intersected. The setting lasts for the Interface session. Ray picks are done using
* {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.setZonesArePickable
* @param {boolean} value - <code>true</code> to make ray picks intersect the bounding box of
* {@link Entities.EntityProperties-Zone|Zone} entities, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE void setZonesArePickable(bool value);
/**jsdoc
* Gets whether or not ray picks intersect the bounding box of {@link Entities.EntityProperties-Zone|Zone} entities. Ray
* picks are done using {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.getZonesArePickable
* @returns {boolean} <code>true</code> if ray picks intersect the bounding box of
* {@link Entities.EntityProperties-Zone|Zone} entities, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool getZonesArePickable() const;
/**jsdoc
* Sets whether or not {@link Entities.EntityProperties-Zone|Zone} entities' boundaries should be drawn. <em>Currently not
* used.</em>
* @function Entities.setDrawZoneBoundaries
* @param {boolean} value - <code>true</code> if {@link Entities.EntityProperties-Zone|Zone} entities' boundaries should be
* drawn, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE void setDrawZoneBoundaries(bool value);
/**jsdoc
* Gets whether or not {@link Entities.EntityProperties-Zone|Zone} entities' boundaries should be drawn. <em>Currently
* not used.</em>
* @function Entities.getDrawZoneBoundaries
* @returns {boolean} <code>true</code> if {@link Entities.EntityProperties-Zone|Zone} entities' boundaries should be
* drawn, otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool getDrawZoneBoundaries() const;
/**jsdoc
* Sets the values of all voxels in a spherical portion of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @function Entities.setVoxelSphere
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} center - The center of the sphere of voxels to set, in world coordinates.
* @param {number} radius - The radius of the sphere of voxels to set, in world coordinates.
* @param {number} value - If <code>value % 256 == 0</code> then each voxel is cleared, otherwise each voxel is set.
* @example <caption>Create a PolyVox sphere.</caption>
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 }));
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: position,
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 32, y: 32, z: 32 },
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setVoxelSphere(polyVox, position, 0.9, 255);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelSphere(const QUuid& entityID, const glm::vec3& center, float radius, int value);
/**jsdoc
* Sets the values of all voxels in a capsule-shaped portion of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @function Entities.setVoxelCapsule
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} start - The center of the sphere of voxels to set, in world coordinates.
* @param {Vec3} end - The center of the sphere of voxels to set, in world coordinates.
* @param {number} radius - The radius of the capsule cylinder and spherical ends, in world coordinates.
* @param {number} value - If <code>value % 256 == 0</code> then each voxel is cleared, otherwise each voxel is set.
* @example <caption>Create a PolyVox capsule shape.</caption>
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 }));
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: position,
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 32, y: 32, z: 32 },
* lifetime: 300 // Delete after 5 minutes.
* });
* var startPosition = Vec3.sum({ x: -0.5, y: 0, z: 0 }, position);
* var endPosition = Vec3.sum({ x: 0.5, y: 0, z: 0 }, position);
* Entities.setVoxelCapsule(polyVox, startPosition, endPosition, 0.5, 255);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelCapsule(const QUuid& entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value);
/**jsdoc
* Sets the value of a particular voxel in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @function Entities.setVoxel
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} position - The position relative to the minimum axes values corner of the entity. The
* <code>position</code> coordinates are rounded to the nearest integer to get the voxel coordinate. The minimum axes
* corner voxel is <code>{ x: 0, y: 0, z: 0 }</code>.
* @param {number} value - If <code>value % 256 == 0</code> then voxel is cleared, otherwise the voxel is set.
* @example <caption>Create a cube PolyVox entity and clear the minimum axes corner voxel.</caption>
* var entity = Entities.addEntity({
* type: "PolyVox",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })),
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setAllVoxels(entity, 1);
* Entities.setVoxel(entity, { x: 0, y: 0, z: 0 }, 0);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxel(const QUuid& entityID, const glm::vec3& position, int value);
/**jsdoc
* Sets the values of all voxels in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @function Entities.setAllVoxels
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {number} value - If <code>value % 256 == 0</code> then each voxel is cleared, otherwise each voxel is set.
* @example <caption>Create a PolyVox cube.</caption>
* var entity = Entities.addEntity({
* type: "PolyVox",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })),
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setAllVoxels(entity, 1);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setAllVoxels(const QUuid& entityID, int value);
/**jsdoc
* Sets the values of all voxels in a cubic portion of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @function Entities.setVoxelsInCuboid
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} lowPosition - The position of the minimum axes value corner of the cube of voxels to set, in voxel
* coordinates.
* @param {Vec3} cuboidSize - The size of the cube of voxels to set, in voxel coordinates.
* @param {number} value - If <code>value % 256 == 0</code> then each voxel is cleared, otherwise each voxel is set.
* @example <caption>Create a PolyVox cube and clear the voxels in one corner.</caption>
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setAllVoxels(polyVox, 1);
* var cuboidPosition = { x: 12, y: 12, z: 12 };
* var cuboidSize = { x: 4, y: 4, z: 4 };
* Entities.setVoxelsInCuboid(polyVox, cuboidPosition, cuboidSize, 0);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setVoxelsInCuboid(const QUuid& entityID, const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value);
/**jsdoc
* Converts voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity to world coordinates. Voxel
* coordinates are relative to the minimum axes values corner of the entity with a scale of <code>Vec3.ONE</code> being the
* dimensions of each voxel.
* @function Entities.voxelCoordsToWorldCoords
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} voxelCoords - The voxel coordinates. May be fractional and outside the entity's bounding box.
* @returns {Vec3} The world coordinates of the <code>voxelCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityProperties-PolyVox|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Create a PolyVox cube with the 0,0,0 voxel replaced by a sphere.</caption>
* // Cube PolyVox with 0,0,0 voxel missing.
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })),
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setAllVoxels(polyVox, 1);
* Entities.setVoxel(polyVox, { x: 0, y: 0, z: 0 }, 0);
*
* // Red sphere in 0,0,0 corner position.
* var cornerPosition = Entities.voxelCoordsToWorldCoords(polyVox, { x: 0, y: 0, z: 0 });
* var voxelDimensions = Vec3.multiply(2 / 16, Vec3.ONE);
* var sphere = Entities.addEntity({
* type: "Sphere",
* position: Vec3.sum(cornerPosition, Vec3.multiply(0.5, voxelDimensions)),
* dimensions: voxelDimensions,
* color: { red: 255, green: 0, blue: 0 },
* lifetime: 300 // Delete after 5 minutes.
* });
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords);
/**jsdoc
* Converts world coordinates to voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. Voxel
* coordinates are relative to the minimum axes values corner of the entity, with a scale of <code>Vec3.ONE</code> being
* the dimensions of each voxel.
* @function Entities.worldCoordsToVoxelCoords
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} worldCoords - The world coordinates. May be outside the entity's bounding box.
* @returns {Vec3} The voxel coordinates of the <code>worldCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityProperties-PolyVox|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}. The value may be
* fractional and outside the entity's bounding box.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords);
/**jsdoc
* Converts voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity to local coordinates. Local
* coordinates are relative to the minimum axes value corner of the entity, with the scale being the same as world
* coordinates. Voxel coordinates are relative to the minimum axes values corner of the entity, with a scale of
* <code>Vec3.ONE</code> being the dimensions of each voxel.
* @function Entities.voxelCoordsToLocalCoords
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} voxelCoords - The voxel coordinates. May be fractional and outside the entity's bounding box.
* @returns {Vec3} The local coordinates of the <code>voxelCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityProperties-PolyVox|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Get the world dimensions of a voxel in a PolyVox entity.</caption>
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })),
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* lifetime: 300 // Delete after 5 minutes.
* });
* var voxelDimensions = Entities.voxelCoordsToLocalCoords(polyVox, Vec3.ONE);
* print("Voxel dimensions: " + JSON.stringify(voxelDimensions));
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords);
/**jsdoc
* Converts local coordinates to voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. Local
* coordinates are relative to the minimum axes value corner of the entity, with the scale being the same as world
* coordinates. Voxel coordinates are relative to the minimum axes values corner of the entity, with a scale of
* <code>Vec3.ONE</code> being the dimensions of each voxel.
* @function Entities.localCoordsToVoxelCoords
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-PolyVox|PolyVox} entity.
* @param {Vec3} localCoords - The local coordinates. May be outside the entity's bounding box.
* @returns {Vec3} The voxel coordinates of the <code>worldCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityProperties-PolyVox|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}. The value may be
* fractional and outside the entity's bounding box.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords);
/**jsdoc
* Sets all the points in a {@link Entities.EntityProperties-Line|Line} entity.
* @function Entities.setAllPoints
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-Line|Line} entity.
* @param {Vec3[]} points - The points that the entity should draw lines between.
* @returns {boolean} <code>true</code> if the entity was updated, otherwise <code>false</code>. The property may fail to
* be updated if the entity does not exist, the entity is not a {@link Entities.EntityProperties-Line|Line} entity,
* one of the points is outside the entity's dimensions, or the number of points is greater than the maximum allowed.
* @example <caption>Change the shape of a Line entity.</caption>
* // Draw a horizontal line between two points.
* var entity = Entities.addEntity({
* type: "Line",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 2, y: 2, z: 1 },
* linePoints: [
* { x: -1, y: 0, z: 0 },
* { x:1, y: -0, z: 0 }
* ],
* color: { red: 255, green: 0, blue: 0 },
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Change the line to be a "V".
* Script.setTimeout(function () {
* Entities.setAllPoints(entity, [
* { x: -1, y: 1, z: 0 },
* { x: 0, y: -1, z: 0 },
* { x: 1, y: 1, z: 0 },
* ]);
* }, 2000);
*/
Q_INVOKABLE bool setAllPoints(const QUuid& entityID, const QVector<glm::vec3>& points);
/**jsdoc
* Appends a point to a {@link Entities.EntityProperties-Line|Line} entity.
* @function Entities.appendPoint
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-Line|Line} entity.
* @param {Vec3} point - The point to add to the line. The coordinates are relative to the entity's position.
* @returns {boolean} <code>true</code> if the point was added to the line, otherwise <code>false</code>. The point may
* fail to be added if the entity does not exist, the entity is not a {@link Entities.EntityProperties-Line|Line} entity, the
* point is outside the entity's dimensions, or the maximum number of points has been reached.
* @example <caption>Append a point to a Line entity.</caption>
* // Draw a line between two points.
* var entity = Entities.addEntity({
* type: "Line",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 2, y: 2, z: 1 },
* linePoints: [
* { x: -1, y: 1, z: 0 },
* { x: 0, y: -1, z: 0 }
* ],
* color: { red: 255, green: 0, blue: 0 },
* lifetime: 300 // Delete after 5 minutes.
* });
*
* // Add a third point to create a "V".
* Script.setTimeout(function () { // Wait for entity to finish creation before editing.
* Entities.appendPoint(entity, { x: 1, y: 1, z: 0 });
* }, 50);
*/
Q_INVOKABLE bool appendPoint(const QUuid& entityID, const glm::vec3& point);
/**jsdoc
* Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about to the program
* log.
* @function Entities.dumpTree
*/
Q_INVOKABLE void dumpTree() const;
/**jsdoc
* Adds an action to an entity. An action is registered with the physics engine and is applied every physics simulation
* step. Any entity may have more than one action associated with it, but only as many as will fit in an entity's
* <code>{@link Entities.EntityProperties|actionData}</code> property.
* @function Entities.addAction
* @param {Entities.ActionType} actionType - The type of action.
* @param {Uuid} entityID - The ID of the entity to add the action to.
* @param {Entities.ActionArguments} arguments - Configures the action.
* @returns {Uuid} The ID of the action if successfully added, otherwise <code>null</code>.
* @example <caption>Constrain a cube to move along a vertical line.</caption>
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* dynamic: true,
* collisionless: false,
* userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }",
* lifetime: 300 // Delete after 5 minutes.
* });
*
* var actionID = Entities.addAction("slider", entityID, {
* axis: { x: 0, y: 1, z: 0 },
* linearLow: 0,
* linearHigh: 0.6
* });
*/
Q_INVOKABLE QUuid addAction(const QString& actionTypeString, const QUuid& entityID, const QVariantMap& arguments);
/**jsdoc
* Updates an entity action.
* @function Entities.updateAction
* @param {Uuid} entityID - The ID of the entity with the action to update.
* @param {Uuid} actionID - The ID of the action to update.
* @param {Entities.ActionArguments} arguments - The arguments to update.
* @returns {boolean} <code>true</code> if the update was successful, otherwise <code>false</code>.
*/
Q_INVOKABLE bool updateAction(const QUuid& entityID, const QUuid& actionID, const QVariantMap& arguments);
/**jsdoc
* Deletes an action from an entity.
* @function Entities.deleteAction
* @param {Uuid} entityID - The ID of entity to delete the action from.
* @param {Uuid} actionID - The ID of the action to delete.
* @returns {boolean} <code>true</code> if the delete was successful, otherwise <code>false</code>.
*/
Q_INVOKABLE bool deleteAction(const QUuid& entityID, const QUuid& actionID);
/**jsdoc
* Gets the IDs of the actions that are associated with an entity.
* @function Entities.getActionIDs
* @param {Uuid} entityID - The entity to get the action IDs for.
* @returns {Uuid[]} The action IDs if any are found, otherwise an empty array.
*/
Q_INVOKABLE QVector<QUuid> getActionIDs(const QUuid& entityID);
/**jsdoc
* Gets the arguments of an action.
* @function Entities.getActionArguments
* @param {Uuid} entityID - The ID of the entity with the action.
* @param {Uuid} actionID - The ID of the action to get the arguments of.
* @returns {Entities.ActionArguments} The arguments of the action if found, otherwise an empty object.
*/
Q_INVOKABLE QVariantMap getActionArguments(const QUuid& entityID, const QUuid& actionID);
/**jsdoc
* Gets the translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's
* position and orientation.
* @function Entities.getAbsoluteJointTranslationInObjectFrame
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @returns {Vec3} The translation of the joint relative to the entity's position and orientation if the entity is a
* {@link Entities.EntityProperties-Model|Model} entity, the entity is loaded, and the joint index is valid; otherwise
* <code>{@link Vec3(0)|Vec3.ZERO}</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex);
/**jsdoc
* Gets the index of the parent joint of a joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.getJointParent
* @param {Uuid} entityID - The ID of the entity.
* @param {number} index - The integer index of the joint.
* @returns {number} The index of the parent joint if found, otherwise <code>-1</code>.
*/
Q_INVOKABLE int getJointParent(const QUuid& entityID, int index);
/**jsdoc
* Gets the translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's
* position and orientation.
* @function Entities.getAbsoluteJointRotationInObjectFrame
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @returns {Quat} The rotation of the joint relative to the entity's orientation if the entity is a
* {@link Entities.EntityProperties-Model|Model} entity, the entity is loaded, and the joint index is valid; otherwise
* <code>{@link Quat(0)|Quat.IDENTITY}</code>.
* @example <caption>Compare the local and absolute rotations of an avatar model's left hand joint.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var index = Entities.getJointIndex(entityID, "LeftHand");
* var localRotation = Entities.getLocalJointRotation(entityID, index);
* var absoluteRotation = Entities.getAbsoluteJointRotationInObjectFrame(entityID, index);
* print("Left hand local rotation: " + JSON.stringify(Quat.safeEulerAngles(localRotation)));
* print("Left hand absolute rotation: " + JSON.stringify(Quat.safeEulerAngles(absoluteRotation)));
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex);
/**jsdoc
* Sets the translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's
* position and orientation.
* @function Entities.setAbsoluteJointTranslationInObjectFrame
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @param {Vec3} translation - The translation to set the joint to relative to the entity's position and orientation.
* @returns {boolean} <code>true</code>if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the joint index is valid, and the translation is different to the joint's current translation; otherwise
* <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec3 translation);
/**jsdoc
* Sets the rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's position
* and orientation.
* @function Entities.setAbsoluteJointRotationInObjectFrame
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @param {Quat} rotation - The rotation to set the joint to relative to the entity's orientation.
* @returns {boolean} <code>true</code> if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the joint index is valid, and the rotation is different to the joint's current rotation; otherwise
* <code>false</code>.
* @example <caption>Raise an avatar model's left palm.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var index = Entities.getJointIndex(entityID, "LeftHand");
* var absoluteRotation = Entities.getAbsoluteJointRotationInObjectFrame(entityID, index);
* absoluteRotation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, 0, 90), absoluteRotation);
* var success = Entities.setAbsoluteJointRotationInObjectFrame(entityID, index, absoluteRotation);
* print("Success: " + success);
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::quat rotation);
/**jsdoc
* Gets the local translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.getLocalJointTranslation
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @returns {Vec3} The local translation of the joint if the entity is a {@link Entities.EntityProperties-Model|Model}
* entity, the entity is loaded, and the joint index is valid; otherwise <code>{@link Vec3(0)|Vec3.ZERO}</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 getLocalJointTranslation(const QUuid& entityID, int jointIndex);
/**jsdoc
* Gets the local rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.getLocalJointRotation
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @returns {Quat} The local rotation of the joint if the entity is a {@link Entities.EntityProperties-Model|Model} entity,
* the entity is loaded, and the joint index is valid; otherwise <code>{@link Quat(0)|Quat.IDENTITY}</code>.
* @example <caption>Report the local rotation of an avatar model's head joint.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var index = Entities.getJointIndex(entityID, "Head");
* var rotation = Entities.getLocalJointRotation(entityID, index);
* print("Head local rotation: " + JSON.stringify(Quat.safeEulerAngles(rotation)));
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::quat getLocalJointRotation(const QUuid& entityID, int jointIndex);
/**jsdoc
* Sets the local translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.setLocalJointTranslation
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @param {Vec3} translation - The local translation to set the joint to.
* @returns {boolean} <code>true</code>if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the joint index is valid, and the translation is different to the joint's current translation; otherwise
* <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation);
/**jsdoc
* Sets the local rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.setLocalJointRotation
* @param {Uuid} entityID - The ID of the entity.
* @param {number} jointIndex - The integer index of the joint.
* @param {Quat} rotation - The local rotation to set the joint to.
* @returns {boolean} <code>true</code> if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the joint index is valid, and the rotation is different to the joint's current rotation; otherwise
* <code>false</code>.
* @example <caption>Make an avatar model turn its head left.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var index = Entities.getJointIndex(entityID, "Head");
* var rotation = Quat.fromPitchYawRollDegrees(0, 60, 0);
* var success = Entities.setLocalJointRotation(entityID, index, rotation);
* print("Success: " + success);
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation);
/**jsdoc
* Sets the local translations of joints in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.setLocalJointTranslations
* @param {Uuid} entityID - The ID of the entity.
* @param {Vec3[]} translations - The local translations to set the joints to.
* @returns {boolean} <code>true</code>if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the model has joints, and at least one of the translations is different to the model's current
* translations; otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setLocalJointTranslations(const QUuid& entityID, const QVector<glm::vec3>& translations);
/**jsdoc
* Sets the local rotations of joints in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.setLocalJointRotations
* @param {Uuid} entityID - The ID of the entity.
* @param {Quat[]} rotations - The local rotations to set the joints to.
* @returns {boolean} <code>true</code> if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the model has joints, and at least one of the rotations is different to the model's current rotations;
* otherwise <code>false</code>.
* @example <caption>Raise both palms of an avatar model.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
*
* // Get all the joint rotations.
* var jointNames = Entities.getJointNames(entityID);
* var jointRotations = [];
* for (var i = 0, length = jointNames.length; i < length; i++) {
* var index = Entities.getJointIndex(entityID, jointNames[i]);
* jointRotations.push(Entities.getLocalJointRotation(entityID, index));
* }
*
* // Raise both palms.
* var index = jointNames.indexOf("LeftHand");
* jointRotations[index] = Quat.multiply(Quat.fromPitchYawRollDegrees(-90, 0, 0), jointRotations[index]);
* index = jointNames.indexOf("RightHand");
* jointRotations[index] = Quat.multiply(Quat.fromPitchYawRollDegrees(-90, 0, 0), jointRotations[index]);
*
* // Update all the joint rotations.
* var success = Entities.setLocalJointRotations(entityID, jointRotations);
* print("Success: " + success);
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setLocalJointRotations(const QUuid& entityID, const QVector<glm::quat>& rotations);
/**jsdoc
* Sets the local rotations and translations of joints in a {@link Entities.EntityProperties-Model|Model} entity. This is
* the same as calling both {@link Entities.setLocalJointRotations|setLocalJointRotations} and
* {@link Entities.setLocalJointTranslations|setLocalJointTranslations} at the same time.
* @function Entities.setLocalJointsData
* @param {Uuid} entityID - The ID of the entity.
* @param {Quat[]} rotations - The local rotations to set the joints to.
* @param {Vec3[]} translations - The local translations to set the joints to.
* @returns {boolean} <code>true</code> if the entity is a {@link Entities.EntityProperties-Model|Model} entity, the entity
* is loaded, the model has joints, and at least one of the rotations or translations is different to the model's
* current values; otherwise <code>false</code>.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE bool setLocalJointsData(const QUuid& entityID,
const QVector<glm::quat>& rotations,
const QVector<glm::vec3>& translations);
/**jsdoc
* Gets the index of a named joint in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.getJointIndex
* @param {Uuid} entityID - The ID of the entity.
* @param {string} name - The name of the joint.
* @returns {number} The integer index of the joint if the entity is a {@link Entities.EntityProperties-Model|Model}
* entity, the entity is loaded, and the joint is present; otherwise <code>-1</code>. The joint indexes are in order
* per {@link Entities.getJointNames|getJointNames}.
* @example <caption>Report the index of a model's head joint.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var index = Entities.getJointIndex(entityID, "Head");
* print("Head joint index: " + index);
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
/**jsdoc
* Gets the names of all the joints in a {@link Entities.EntityProperties-Model|Model} entity.
* @function Entities.getJointNames
* @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-Model|Model} entity.
* @returns {string[]} The names of all the joints in the entity if it is a {@link Entities.EntityProperties-Model|Model}
* entity and is loaded, otherwise an empty array. The joint names are in order per
* {@link Entities.getJointIndex|getJointIndex}.
* @example <caption>Report a model's joint names.</caption>
* entityID = Entities.addEntity({
* type: "Model",
* modelURL: "https://github.com/highfidelity/hifi-api-docs/blob/master/docs/blue_suited.fbx?raw=true",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* rotation: MyAvatar.orientation,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Script.setTimeout(function () {
* // Joint data aren't available until after the model has loaded.
* var jointNames = Entities.getJointNames(entityID);
* print("Joint names: " + JSON.stringify(jointNames));
* }, 2000);
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
/**jsdoc
* Gets the IDs of entities and avatars that are directly parented to an entity or avatar model. To get all descendants,
* you can recurse on the IDs returned.
* @function Entities.getChildrenIDs
* @param {Uuid} parentID - The ID of the entity or avatar to get the children IDs of.
* @returns {Uuid[]} An array of entity and avatar IDs that are parented directly to the <code>parentID</code>
* entity or avatar. Does not include children's children, etc. The array is empty if no children can be found or
* <code>parentID</code> cannot be found.
* @example <caption>Report the children of an entity.</caption>
* function createEntity(description, position, parent) {
* var entity = Entities.addEntity({
* type: "Sphere",
* position: position,
* dimensions: Vec3.HALF,
* parentID: parent,
* lifetime: 300 // Delete after 5 minutes.
* });
* print(description + ": " + entity);
* return entity;
* }
*
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 2, z: -5 }));
* var root = createEntity("Root", position, Uuid.NULL);
* var child = createEntity("Child", Vec3.sum(position, { x: 0, y: -1, z: 0 }), root);
* var grandChild = createEntity("Grandchild", Vec3.sum(position, { x: 0, y: -2, z: 0 }), child);
*
* var children = Entities.getChildrenIDs(root);
* print("Children of root: " + JSON.stringify(children)); // Only the child entity.
*/
Q_INVOKABLE QVector<QUuid> getChildrenIDs(const QUuid& parentID);
/**jsdoc
* Gets the IDs of entities and avatars that are directly parented to an entity or avatar model's joint. To get all
* descendants, you can use {@link Entities.getChildrenIDs|getChildrenIDs} to recurse on the IDs returned.
* @function Entities.getChildrenIDsOfJoint
* @param {Uuid} parentID - The ID of the entity or avatar to get the children IDs of.
* @param {number} jointIndex - Integer number of the model joint to get the children IDs of.
* @returns {Uuid[]} An array of entity and avatar IDs that are parented directly to the <code>parentID</code>
* entity or avatar at the <code>jointIndex</code> joint. Does not include children's children, etc. The
* array is empty if no children can be found or <code>parentID</code> cannot be found.
* @example <caption>Report the children of your avatar's right hand.</caption>
* function createEntity(description, position, parent) {
* var entity = Entities.addEntity({
* type: "Sphere",
* position: position,
* dimensions: Vec3.HALF,
* parentID: parent,
* lifetime: 300 // Delete after 5 minutes.
* });
* print(description + ": " + entity);
* return entity;
* }
*
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 2, z: -5 }));
* var root = createEntity("Root", position, Uuid.NULL);
* var child = createEntity("Child", Vec3.sum(position, { x: 0, y: -1, z: 0 }), root);
*
* Script.setTimeout(function () { // Wait for entity to finish creation before editing.
* Entities.editEntity(root, {
* parentID: MyAvatar.sessionUUID,
* parentJointIndex: MyAvatar.getJointIndex("RightHand")
* });
*
* var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, MyAvatar.getJointIndex("RightHand"));
* print("Children of hand: " + JSON.stringify(children)); // Only the root entity.
* }, 50);
*/
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
/**jsdoc
* Checks whether an entity has an entity as an ancestor (parent, parent's parent, etc.).
* @function Entities.isChildOfParent
* @param {Uuid} childID - The ID of the child entity to test for being a child, grandchild, etc.
* @param {Uuid} parentID - The ID of the parent entity to test for being a parent, grandparent, etc.
* @returns {boolean} <code>true</code> if the <code>childID</code> entity has the <code>parentID</code> entity
* as a parent or grandparent etc., otherwise <code>false</code>.
* @example <caption>Check that a grandchild entity is a child of its grandparent.</caption>
* function createEntity(description, position, parent) {
* var entity = Entities.addEntity({
* type: "Sphere",
* position: position,
* dimensions: Vec3.HALF,
* parentID: parent,
* lifetime: 300 // Delete after 5 minutes.
* });
* print(description + ": " + entity);
* return entity;
* }
*
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 2, z: -5 }));
* var root = createEntity("Root", position, Uuid.NULL);
* var child = createEntity("Child", Vec3.sum(position, { x: 0, y: -1, z: 0 }), root);
* var grandChild = createEntity("Grandchild", Vec3.sum(position, { x: 0, y: -2, z: 0 }), child);
*
* print("grandChild has root as parent: " + Entities.isChildOfParent(grandChild, root)); // true
*/
Q_INVOKABLE bool isChildOfParent(const QUuid& childID, const QUuid& parentID);
/**jsdoc
* Gets the type &mdash; entity or avatar &mdash; of an in-world item.
* @function Entities.getNestableType
* @param {Uuid} id - The ID of the item to get the type of.
* @returns {Entities.NestableType} The type of the item.
* @example <caption>Report some nestable types.</caption>
* var entity = Entities.addEntity({
* type: "Sphere",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 1, z: -2 })),
* lifetime: 300 // Delete after 5 minutes.
* });
*
* print(Entities.getNestableType(entity)); // "entity"
* print(Entities.getNestableType(Uuid.generate())); // "unknown"
*/
Q_INVOKABLE QString getNestableType(const QUuid& id);
/**jsdoc
* Gets the ID of the {@link Entities.EntityProperties-Web|Web} entity that has keyboard focus.
* @function Entities.getKeyboardFocusEntity
* @returns {Uuid} The ID of the {@link Entities.EntityProperties-Web|Web} entity that has focus, if any, otherwise <code>null</code>.
*/
Q_INVOKABLE QUuid getKeyboardFocusEntity() const;
/**jsdoc
* Sets the {@link Entities.EntityProperties-Web|Web} entity that has keyboard focus.
* @function Entities.setKeyboardFocusEntity
* @param {Uuid} id - The ID of the {@link Entities.EntityProperties-Web|Web} entity to set keyboard focus to. Use
* <code>null</code> or {@link Uuid(0)|Uuid.NULL} to unset keyboard focus from an entity.
*/
Q_INVOKABLE void setKeyboardFocusEntity(const QUuid& id);
/**jsdoc
* Emits a {@link Entities.mousePressOnEntity|mousePressOnEntity} event.
* @function Entities.sendMousePressOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.mouseMoveOnEntity|mouseMoveOnEntity} event.
* @function Entities.sendMouseMoveOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.mouseReleaseOnEntity|mouseReleaseOnEntity} event.
* @function Entities.sendMouseReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.clickDownOnEntity|clickDownOnEntity} event.
* @function Entities.sendClickDownOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.holdingClickOnEntity|holdingClickOnEntity} event.
* @function Entities.sendHoldingClickOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.clickReleaseOnEntity|clickReleaseOnEntity} event.
* @function Entities.sendClickReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.hoverEnterEntity|hoverEnterEntity} event.
* @function Entities.sendHoverEnterEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.hoverOverEntity|hoverOverEntity} event.
* @function Entities.sendHoverOverEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Emits a {@link Entities.hoverLeaveEntity|hoverLeaveEntity} event.
* @function Entities.sendHoverLeaveEntity
* @param {Uuid} entityID - The ID of the entity to emit the event for.
* @param {PointerEvent} event - The event details.
*/
Q_INVOKABLE void sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event);
/**jsdoc
* Checks whether an entity wants hand controller pointer events. For example, a {@link Entities.EntityProperties-Web|Web}
* entity does but a {@link Entities.EntityProperties-Shape|Shape} entity doesn't.
* @function Entities.wantsHandControllerPointerEvents
* @param {Uuid} entityID - The ID of the entity.
* @returns {boolean} <code>true</code> if the entity can be found and it wants hand controller pointer events, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool wantsHandControllerPointerEvents(const QUuid& id);
/**jsdoc
* Sends a message to a {@link Entities.EntityProperties-Web|Web} entity's HTML page. To receive the message, the web
* page's script must connect to the <code>EventBridge</code> that is automatically provided to the script:
* <pre class="prettyprint"><code>EventBridge.scriptEventReceived.connect(function(message) {
* ...
* });</code></pre>
* <p>Use {@link Entities.webEventReceived} to receive messages from the Web entity's HTML page.</p>
* <p>Alternatively, you can use {@link Entities.getEntityObject} to exchange messages over a Web entity's HTML event
* bridge.</p>
* @function Entities.emitScriptEvent
* @param {Uuid} entityID - The ID of the Web entity to send the message to.
* @param {string} message - The message to send.
* @example <caption>Exchange messages with a Web entity.</caption>
* // HTML file, name: "webEntity.html".
* <!DOCTYPE html>
* <html>
* <head>
* <title>HELLO</title>
* </head>
* <body>
* <h1>HELLO</h1></h1>
* <script>
* function onScriptEventReceived(message) {
* // Message received from the script.
* console.log("Message received: " + message);
* }
*
* EventBridge.scriptEventReceived.connect(onScriptEventReceived);
*
* setTimeout(function () {
* // Send a message to the script.
* EventBridge.emitWebEvent("hello");
* }, 5000);
* </script>
* </body>
* </html>
*
* // Script file.
* var webEntity = Entities.addEntity({
* type: "Web",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })),
* rotation: MyAvatar.orientation,
* sourceUrl: Script.resolvePath("webEntity.html"),
* alpha: 1.0,
* lifetime: 300 // 5 min
* });
*
* function onWebEventReceived(entityID, message) {
* if (entityID === webEntity) {
* // Message received.
* print("Message received: " + message);
*
* // Send a message back.
* Entities.emitScriptEvent(webEntity, message + " back");
* }
* }
*
* Entities.webEventReceived.connect(onWebEventReceived);
*/
Q_INVOKABLE void emitScriptEvent(const EntityItemID& entityID, const QVariant& message);
/**jsdoc
* Checks whether an axis-aligned box and a capsule intersect.
* @function Entities.AABoxIntersectsCapsule
* @param {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box.
* @param {Vec3} dimensions - The dimensions of the AA box.
* @param {Vec3} start - One end of the capsule.
* @param {Vec3} end - The other end of the capsule.
* @param {number} radius - The radius of the capsule.
* @returns {boolean} <code>true</code> if the AA box and capsule intersect, otherwise <code>false</code>.
*/
Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions,
const glm::vec3& start, const glm::vec3& end, float radius);
/**jsdoc
* Gets the meshes in a {@link Entities.EntityProperties-Model|Model} or {@link Entities.EntityProperties-PolyVox|PolyVox}
* entity.
* @function Entities.getMeshes
* @param {Uuid} entityID - The ID of the <code>Model</code> or <code>PolyVox</code> entity to get the meshes of.
* @param {Entities~getMeshesCallback} callback - The function to call upon completion.
* @deprecated This function is deprecated and will be removed. Use the {@link Graphics} API instead.
*/
/**jsdoc
* Called when a {@link Entities.getMeshes} call is complete.
* @callback Entities~getMeshesCallback
* @param {MeshProxy[]} meshes - If <code>success<</code> is <code>true</code>, a {@link MeshProxy} per mesh in the
* <code>Model</code> or <code>PolyVox</code> entity; otherwise <code>undefined</code>.
* @param {boolean} success - <code>true</code> if the {@link Entities.getMeshes} call was successful, <code>false</code>
* otherwise. The call may be unsuccessful if the requested entity could not be found.
* @deprecated This function is deprecated and will be removed. Use the {@link Graphics} API instead.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE void getMeshes(const QUuid& entityID, QScriptValue callback);
/**jsdoc
* Gets the object to world transform, excluding scale, of an entity.
* @function Entities.getEntityTransform
* @param {Uuid} entityID - The ID of the entity.
* @returns {Mat4} The entity's object to world transform excluding scale (i.e., translation and rotation, with scale of 1)
* if the entity can be found, otherwise a transform with zero translation and rotation and a scale of 1.
* @example <caption>Position and rotation in an entity's world transform.</caption>
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 1, z: -2 }));
* var orientation = MyAvatar.orientation;
* print("Position: " + JSON.stringify(position));
* print("Orientation: " + JSON.stringify(orientation));
*
* var entityID = Entities.addEntity({
* type: "Sphere",
* position: position,
* rotation: orientation,
* dimensions: Vec3.HALF,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* var transform = Entities.getEntityTransform(entityID);
* print("Transform: " + JSON.stringify(transform));
* print("Translation: " + JSON.stringify(Mat4.extractTranslation(transform))); // Same as position.
* print("Rotation: " + JSON.stringify(Mat4.extractRotation(transform))); // Same as orientation.
* print("Scale: " + JSON.stringify(Mat4.extractScale(transform))); // { x: 1, y: 1, z: 1 }
*/
Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID);
/**jsdoc
* Gets the object to parent transform, excluding scale, of an entity.
* @function Entities.getEntityLocalTransform
* @param {Uuid} entityID - The ID of the entity.
* @returns {Mat4} The entity's object to parent transform excluding scale (i.e., translation and rotation, with scale of
* 1) if the entity can be found, otherwise a transform with zero translation and rotation and a scale of 1. If the
* entity doesn't have a parent, its world transform is returned.
* @example <caption>Position and rotation in an entity's local transform.</caption>
* function createEntity(position, rotation, parent) {
* var entity = Entities.addEntity({
* type: "Box",
* position: position,
* rotation: rotation,
* dimensions: Vec3.HALF,
* parentID: parent,
* lifetime: 300 // Delete after 5 minutes.
* });
* return entity;
* }
*
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 2, z: -5 }));
*
* var parent = createEntity(position, MyAvatar.orientation, Uuid.NULL);
*
* var childTranslation = { x: 0, y: -1.5, z: 0 };
* var childRotation = Quat.fromPitchYawRollDegrees(0, 45, 0);
* var child = createEntity(Vec3.sum(position, childTranslation), Quat.multiply(childRotation, MyAvatar.orientation), parent);
*
* var transform = Entities.getEntityLocalTransform(child);
* print("Transform: " + JSON.stringify(transform));
* print("Translation: " + JSON.stringify(Mat4.extractTranslation(transform))); // childTranslation
* print("Rotation: " + JSON.stringify(Quat.safeEulerAngles(Mat4.extractRotation(transform)))); // childRotation
* print("Scale: " + JSON.stringify(Mat4.extractScale(transform))); // { x: 1, y: 1, z: 1 } */
Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID);
/**jsdoc
* Converts a position in world coordinates to a position in an avatar, entity, or joint's local coordinates.
* @function Entities.worldToLocalPosition
* @param {Vec3} worldPosition - The world position to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent= false] - <code>true</code> to scale the local position per the parent's scale,
* <code>false</code> for the local position to be at world scale.
* @returns {Vec3} The position converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Report the local coordinates of an entity parented to another.</caption>
* var parentPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 }));
* var childPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 1, z: -5 }));
*
* var parentEntity = Entities.addEntity({
* type: "Box",
* position: parentPosition,
* rotation: MyAvatar.orientation,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* lifetime: 300 // Delete after 5 minutes.
* });
* var childEntity = Entities.addEntity({
* type: "Sphere",
* position: childPosition,
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* parentID: parentEntity,
* lifetime: 300 // Delete after 5 minutes.
* });
*
* var localPosition = Entities.worldToLocalPosition(childPosition, parentEntity);
* print("Local position: " + JSON.stringify(localPosition)); // 0, 1, 0.
* localPosition = Entities.getEntityProperties(childEntity, "localPosition").localPosition;
* print("Local position: " + JSON.stringify(localPosition)); // The same.
*/
Q_INVOKABLE glm::vec3 worldToLocalPosition(glm::vec3 worldPosition, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a rotation or orientation in world coordinates to rotation in an avatar, entity, or joint's local coordinates.
* @function Entities.worldToLocalRotation
* @param {Quat} worldRotation - The world rotation to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent=false] - <em>Not used in the calculation.</em>
* @returns {Quat} The rotation converted to local coordinates if successful, otherwise {@link Quat(0)|Quat.IDENTITY}.
*/
Q_INVOKABLE glm::quat worldToLocalRotation(glm::quat worldRotation, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a velocity in world coordinates to a velocity in an avatar, entity, or joint's local coordinates.
* @function Entities.worldToLocalVelocity
* @param {Vec3} worldVelocity - The world velocity to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent=false] - <code>true</code> to scale the local velocity per the parent's scale,
* <code>false</code> for the local velocity to be at world scale.
* @returns {Vec3} The velocity converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 worldToLocalVelocity(glm::vec3 worldVelocity, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a Euler angular velocity in world coordinates to an angular velocity in an avatar, entity, or joint's local
* coordinates.
* @function Entities.worldToLocalAngularVelocity
* @param {Vec3} worldAngularVelocity - The world Euler angular velocity to convert. (Can be in any unit, e.g., deg/s or
* rad/s.)
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent=false] - <em>Not used in the calculation.</em>
* @returns {Vec3} The angular velocity converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 worldToLocalAngularVelocity(glm::vec3 worldAngularVelocity, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts dimensions in world coordinates to dimensions in an avatar or entity's local coordinates.
* @function Entities.worldToLocalDimensions
* @param {Vec3} worldDimensions - The world dimensions to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - <em>Not used in the calculation.</em>
* @param {boolean} [scalesWithParent=false] - <code>true</code> to scale the local dimensions per the parent's scale,
* <code>false</code> for the local dimensions to be at world scale.
* @returns {Vec3} The dimensions converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 worldToLocalDimensions(glm::vec3 worldDimensions, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a position in an avatar, entity, or joint's local coordinate to a position in world coordinates.
* @function Entities.localToWorldPosition
* @param {Vec3} localPosition - The local position to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithparent=false] - <code>true</code> if the local dimensions are scaled per the parent's scale,
* <code>false</code> if the local dimensions are at world scale.
* @returns {Vec3} The position converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 localToWorldPosition(glm::vec3 localPosition, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a rotation or orientation in an avatar, entity, or joint's local coordinate to a rotation in world coordinates.
* @function Entities.localToWorldRotation
* @param {Quat} localRotation - The local rotation to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent= false] - <em>Not used in the calculation.</em>
* @returns {Quat} The rotation converted to local coordinates if successful, otherwise {@link Quat(0)|Quat.IDENTITY}.
*/
Q_INVOKABLE glm::quat localToWorldRotation(glm::quat localRotation, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a velocity in an avatar, entity, or joint's local coordinate to a velocity in world coordinates.
* @function Entities.localToWorldVelocity
* @param {Vec3} localVelocity - The local velocity to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent= false] - <code>true</code> if the local velocity is scaled per the parent's scale,
* <code>false</code> if the local velocity is at world scale.
* @returns {Vec3} The velocity converted to world coordinates it successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 localToWorldVelocity(glm::vec3 localVelocity, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts a Euler angular velocity in an avatar, entity, or joint's local coordinate to an angular velocity in world
* coordinates.
* @function Entities.localToWorldAngularVelocity
* @param {Vec3} localAngularVelocity - The local Euler angular velocity to convert. (Can be in any unit, e.g., deg/s or
* rad/s.)
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - The joint in the avatar or entity that the local coordinates are based on. If
* <code>-1</code> then no joint is used and the local coordinates are based solely on the avatar or entity.
* @param {boolean} [scalesWithParent= false] - <em>Not used in the calculation.</em>
* @returns {Vec3} The angular velocity converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 localToWorldAngularVelocity(glm::vec3 localAngularVelocity, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Converts dimensions in an avatar or entity's local coordinates to dimensions in world coordinates.
* @function Entities.localToWorldDimensions
* @param {Vec3} localDimensions - The local dimensions to convert.
* @param {Uuid} parentID - The avatar or entity that the local coordinates are based on.
* @param {number} [parentJointIndex=-1] - <em>Not used in the calculation.</em>
* @param {boolean} [scalesWithParent= false] - <code>true</code> if the local dimensions are scaled per the parent's
* scale, <code>false</code> if the local dimensions are at world scale.
* @returns {Vec3} The dimensions converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE glm::vec3 localToWorldDimensions(glm::vec3 localDimensions, const QUuid& parentID,
int parentJointIndex = -1, bool scalesWithParent = false);
/**jsdoc
* Gets the static certificate for an entity. The static certificate contains static properties of the item which cannot
* be altered.
* @function Entities.getStaticCertificateJSON
* @param {Uuid} entityID - The ID of the entity to get the static certificate for.
* @returns {string} The entity's static certificate as a JSON string if the entity can be found, otherwise <code>""</code>.
*/
Q_INVOKABLE QString getStaticCertificateJSON(const QUuid& entityID);
/**jsdoc
* Verifies the entity's proof of provenance, i.e., that the entity's <code>certificateID</code> property was produced by
* High Fidelity signing the entity's static certificate JSON.
* @function Entities.verifyStaticCertificateProperties
* @param {Uuid} entityID - The ID of the entity to verify.
* @returns {boolean} <code>true</code> if the entity can be found, its <code>certificateID</code> property is present, and
* its value matches the entity's static certificate JSON; otherwise <code>false</code>.
*/
Q_INVOKABLE bool verifyStaticCertificateProperties(const QUuid& entityID);
/**jsdoc
* Gets information about an entity property, including a minimum to maximum range for some numerical properties.
* @function Entities.getPropertyInfo
* @param {string} propertyName - The name of the property to get the information for.
* @returns {Entities.EntityPropertyInfo} The information about the property if it can be found, otherwise an empty object.
* @example <caption>Report property info. for some properties.</caption>
* print("alpha: " + JSON.stringify(Entities.getPropertyInfo("alpha")));
* print("script: " + JSON.stringify(Entities.getPropertyInfo("script")));
*/
Q_INVOKABLE const EntityPropertyInfo getPropertyInfo(const QString& propertyName) const;
signals:
/**jsdoc
* Triggered on the client that is the physics simulation owner during the collision of two entities. Note: Isn't triggered
* for a collision with an avatar.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.collisionWithEntity
* @param {Uuid} idA - The ID of one entity in the collision. For an entity script, this is the ID of the entity containing
* the script.
* @param {Uuid} idB - The ID of the other entity in the collision.
* @param {Collision} collision - The details of the collision.
* @returns {Signal}
* @example <caption>Change the color of an entity when it collides with another entity.</caption>
* var entityScript = (function () {
* function randomInteger(min, max) {
* return Math.floor(Math.random() * (max - min + 1)) + min;
* }
*
* this.collisionWithEntity = function (myID, otherID, collision) {
* Entities.editEntity(myID, {
* color: {
* red: randomInteger(128, 255),
* green: randomInteger(128, 255),
* blue: randomInteger(128, 255)
* }
* });
* };
* });
*
* var entityID = Entities.addEntity({
* type: "Box",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 0.5, y: 0.5, z: 0.5 },
* color: { red: 128, green: 128, blue: 128 },
* gravity: { x: 0, y: -9.8, z: 0 },
* velocity: { x: 0, y: 0.1, z: 0 }, // Kick off physics.
* dynamic: true,
* collisionless: false, // So that collision events are generated.
* script: "(" + entityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*/
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
/**jsdoc
* Triggered when your ability to change the <code>locked</code> property of entities changes.
* @function Entities.canAdjustLocksChanged
* @param {boolean} canAdjustLocks - <code>true</code> if the script can change the <code>locked</code> property of an
* entity, <code>false</code> if it can't.
* @returns {Signal}
* @example <caption>Report when your ability to change locks changes.</caption>
* function onCanAdjustLocksChanged(canAdjustLocks) {
* print("You can adjust entity locks: " + canAdjustLocks);
* }
* Entities.canAdjustLocksChanged.connect(onCanAdjustLocksChanged);
*/
void canAdjustLocksChanged(bool canAdjustLocks);
/**jsdoc
* Triggered when your ability to rez (create) entities changes.
* @function Entities.canRezChanged
* @param {boolean} canRez - <code>true</code> if the script can rez (create) entities, <code>false</code> if it can't.
* @returns {Signal}
*/
void canRezChanged(bool canRez);
/**jsdoc
* Triggered when your ability to rez (create) temporary entities changes. Temporary entities are entities with a finite
* <code>lifetime</code> property value set.
* @function Entities.canRezTmpChanged
* @param {boolean} canRezTmp - <code>true</code> if the script can rez (create) temporary entities, <code>false</code> if
* it can't.
* @returns {Signal}
*/
void canRezTmpChanged(bool canRezTmp);
/**jsdoc
* Triggered when your ability to rez (create) certified entities changes. Certified entities are entities that have PoP
* certificates.
* @function Entities.canRezCertifiedChanged
* @param {boolean} canRezCertified - <code>true</code> if the script can rez (create) certified entities,
* <code>false</code> if it can't.
* @returns {Signal}
*/
void canRezCertifiedChanged(bool canRezCertified);
/**jsdoc
* Triggered when your ability to rez (create) temporary certified entities changes. Temporary entities are entities with a
* finite <code>lifetime</code> property value set. Certified entities are entities that have PoP certificates.
* @function Entities.canRezTmpCertifiedChanged
* @param {boolean} canRezTmpCertified - <code>true</code> if the script can rez (create) temporary certified entities,
* <code>false</code> if it can't.
* @returns {Signal}
*/
void canRezTmpCertifiedChanged(bool canRezTmpCertified);
/**jsdoc
* Triggered when your ability to make changes to the asset server's assets changes.
* @function Entities.canWriteAssetsChanged
* @param {boolean} canWriteAssets - <code>true</code> if the script can change the <code>?</code> property of an entity,
* <code>false</code> if it can't.
* @returns {Signal}
*/
void canWriteAssetsChanged(bool canWriteAssets);
/**jsdoc
* Triggered when your ability to get and set private user data changes.
* @function Entities.canGetAndSetPrivateUserDataChanged
* @param {boolean} canGetAndSetPrivateUserData - <code>true</code> if the script change the <code>privateUserData</code>
* property of an entity, <code>false</code> if it can't.
* @returns {Signal}
*/
void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData);
/**jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is on an entity, or a controller trigger is fully
* pressed while its laser is on an entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.mousePressOnEntity
* @param {Uuid} entityID - The ID of the entity that was pressed on.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
* @example <caption>Report when an entity is clicked with the mouse or laser.</caption>
* function onMousePressOnEntity(entityID, event) {
* print("Clicked on entity: " + entityID);
* }
*
* Entities.mousePressOnEntity.connect(onMousePressOnEntity);
*/
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when a mouse button is double-clicked while the mouse cursor is on an entity.
* @function Entities.mouseDoublePressOnEntity
* @param {Uuid} entityID - The ID of the entity that was double-pressed on.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Repeatedly triggered while the mouse cursor or controller laser moves on an entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.mouseMoveOnEntity
* @param {Uuid} entityID - The ID of the entity that was moved on.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when a mouse button is released after clicking on an entity or the controller trigger is partly or fully
* released after pressing on an entity, even if the mouse pointer or controller laser has moved off the entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.mouseReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally pressed.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is not on an entity.
* @function Entities.mousePressOffEntity
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void mousePressOffEntity();
/**jsdoc
* Triggered when a mouse button is double-clicked while the mouse cursor is not on an entity.
* @function Entities.mouseDoublePressOffEntity
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void mouseDoublePressOffEntity();
/**jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is on an entity. Note: Not triggered by controllers.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.clickDownOnEntity
* @param {Uuid} entityID - The ID of the entity that was clicked on.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
* @example <caption>Compare clickDownOnEntity signal and entity script method.</caption>
* var entityScript = (function () {
* // Method is called for only this entity.
* this.clickDownOnEntity = function (entityID, event) {
* print("Entity : Clicked sphere ; " + event.type);
* };
* });
*
* var sphereID = Entities.addEntity({
* type: "Sphere",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
* script: "(" + entityScript + ")", // Could host the script on a Web server instead.
* lifetime: 300 // Delete after 5 minutes.
* });
*
* Entities.clickDownOnEntity.connect(function (entityID, event) {
* // Signal is triggered for all entities.
* if (entityID === sphereID) {
* print("Interface : Clicked sphere ; " + event.type);
* } else {
* print("Interface : Clicked another entity ; " + event.type);
* }
* });
*/
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Repeatedly triggered while a mouse button continues to be held after clicking an entity, even if the mouse cursor has
* moved off the entity. Note: Not triggered by controllers.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.holdingClickOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally clicked.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when a mouse button is released after clicking on an entity, even if the mouse cursor has moved off the
* entity. Note: Not triggered by controllers.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.clickReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally clicked.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void clickReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when the mouse cursor or controller laser starts hovering on an entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.hoverEnterEntity
* @param {Uuid} entityID - The ID of the entity that is being hovered.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void hoverEnterEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Repeatedly triggered when the mouse cursor or controller laser moves while hovering over an entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.hoverOverEntity
* @param {Uuid} entityID - The ID of the entity that is being hovered.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void hoverOverEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when the mouse cursor or controller laser stops hovering over an entity.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.hoverLeaveEntity
* @param {Uuid} entityID - The ID of the entity that was being hovered.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}
*/
void hoverLeaveEntity(const EntityItemID& entityItemID, const PointerEvent& event);
/**jsdoc
* Triggered when an avatar enters an entity, but only if the entity has an entity method exposed for this event.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.enterEntity
* @param {Uuid} entityID - The ID of the entity that the avatar entered.
* @returns {Signal}
*/
void enterEntity(const EntityItemID& entityItemID);
/**jsdoc
* Triggered when an avatar leaves an entity, but only if the entity has an entity method exposed for this event.
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
* @function Entities.leaveEntity
* @param {Uuid} entityID - The ID of the entity that the avatar left.
* @returns {Signal}
*/
void leaveEntity(const EntityItemID& entityItemID);
/**jsdoc
* Triggered when an entity is deleted.
* @function Entities.deletingEntity
* @param {Uuid} entityID - The ID of the entity deleted.
* @returns {Signal}
* @example <caption>Report when an entity is deleted.</caption>
* Entities.deletingEntity.connect(function (entityID) {
* print("Deleted entity: " + entityID);
* });
*/
void deletingEntity(const EntityItemID& entityID);
/**jsdoc
* Triggered when an entity is added to Interface's local in-memory tree of entities it knows about. This may occur when
* entities are loaded upon visiting a domain, when the user rotates their view so that more entities become visible, and
* when any type of entity is created (e.g., by {@link Entities.addEntity|addEntity}).
* @function Entities.addingEntity
* @param {Uuid} entityID - The ID of the entity added.
* @returns {Signal}
* @example <caption>Report when an entity is added.</caption>
* Entities.addingEntity.connect(function (entityID) {
* print("Added entity: " + entityID);
* });
*/
void addingEntity(const EntityItemID& entityID);
/**jsdoc
* Triggered when an "wearable" entity is deleted, for example when removing a "wearable" from your avatar.
* @function Entities.deletingWearable
* @param {Uuid} entityID - The ID of the "wearable" entity deleted.
* @returns {Signal}
* @example <caption>Report when a "wearable" entity is deleted.</caption>
* Entities.deletingWearable.connect(function (entityID) {
* print("Deleted wearable: " + entityID);
* });
*/
void deletingWearable(const EntityItemID& entityID);
/**jsdoc
* Triggered when an "wearable" entity is added to Interface's local in-memory tree of entities it knows about, for example
* when adding a "wearable" to your avatar.
* @function Entities.addingWearable
* @param {Uuid} entityID - The ID of the "wearable" entity added.
* @returns {Signal}
* @example <caption>Report when a "wearable" entity is added.</caption>
* Entities.addingWearable.connect(function (entityID) {
* print("Added wearable: " + entityID);
* });
*/
void addingWearable(const EntityItemID& entityID);
/**jsdoc
* Triggered when you disconnect from a domain, at which time Interface's local in-memory tree of entities that it knows
* about is cleared.
* @function Entities.clearingEntities
* @returns {Signal}
* @example <caption>Report when Interfaces's entity tree is cleared.</caption>
* Entities.clearingEntities.connect(function () {
* print("Entities cleared");
* });
*/
void clearingEntities();
/**jsdoc
* Triggered when a script in a {@link Entities.EntityProperties-Web|Web} entity's HTML sends an event over the entity's
* HTML event bridge. The HTML web page can send a message by calling:
* <pre class="prettyprint"><code>EventBridge.emitWebEvent(message);</code></pre>
* <p>Use {@link Entities.emitScriptEvent} to send messages to the Web entity's HTML page.</p>
* <p>Alternatively, you can use {@link Entities.getEntityObject} to exchange messages over a Web entity's HTML event
* bridge.</p>
* @function Entities.webEventReceived
* @param {Uuid} entityID - The ID of the Web entity that the message was received from.
* @param {string} message - The message received.
* @returns {Signal}
*/
void webEventReceived(const EntityItemID& entityItemID, const QVariant& message);
protected:
void withEntitiesScriptEngine(std::function<void(QSharedPointer<EntitiesScriptEngineProvider>)> function) {
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
function(_entitiesScriptEngine);
};
private slots:
void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode);
void onAddingEntity(EntityItem* entity);
void onDeletingEntity(EntityItem* entity);
private:
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);
bool polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);
bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
bool addLocalEntityCopy(EntityItemProperties& propertiesWithSimID, EntityItemID& id, bool isClone = false);
EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID,
EntityTypes::EntityType entityType = EntityTypes::Unknown);
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
RayToEntityIntersectionResult evalRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
PickFilter searchFilter, const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard) const;
/// actually does the work of finding the parabola intersection, can be called in locking mode or tryLock mode
ParabolaToEntityIntersectionResult evalParabolaIntersectionWorker(const PickParabola& parabola, Octree::lockType lockType,
PickFilter searchFilter, const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard) const;
EntityTreePointer _entityTree;
std::recursive_mutex _entitiesScriptEngineLock;
QSharedPointer<EntitiesScriptEngineProvider> _entitiesScriptEngine;
bool _bidOnSimulationOwnership { false };
ActivityTracking _activityTracking;
};
#endif // hifi_EntityScriptingInterface_h