diff --git a/source/script/_images/add-script.png b/source/script/_images/add-script.png deleted file mode 100755 index c1539a35..00000000 Binary files a/source/script/_images/add-script.png and /dev/null differ diff --git a/source/script/_images/create-properties-scripts-icon.png b/source/script/_images/create-properties-scripts-icon.png new file mode 100644 index 00000000..737a110c Binary files /dev/null and b/source/script/_images/create-properties-scripts-icon.png differ diff --git a/source/script/assignment-client-scripts.md b/source/script/assignment-client-scripts.md deleted file mode 100755 index 955abd8b..00000000 --- a/source/script/assignment-client-scripts.md +++ /dev/null @@ -1,58 +0,0 @@ -# Assignment Client Scripts - -Assignment Client (AC) scripts (also known as "persistent scripts") run persistently in a domain and aren't affected by other scripts. These scripts run on an assignment client separate from the Interface, so the script will continue to run until you either remove the script from the domain or you shut down the domain entirely. - -With AC scripts, you can do things like coordinate actions between entities and avatars, and add virtual pets to greet visitors to your domain. - -**On This Page** -* [Add an AC Script](#add-an-ac-script) -* [Example of an AC Script](#example-of-an-ac-script) - -## Add an AC Script -Once you've written and hosted your script, you need to add it to a domain, either your own or one where you have permissions to run an AC script. - -1. Open your 'Domain Administration Panel'. If you are on a local sandbox, open it by clicking on the Overte icon in the taskbar notifications and 'click Settings'. -2. From the menu, go to **Content > Scripts**. -3. In the Persistent Scripts section, click **+** and paste the URL to your script under 'Script URL'. -![](_images/ac-script.png) -4. At the top of the page, click 'Save and Restart'. Now, every time you enter that domain, the AC script will be running. - -## Example of an AC Script - -The following script counts the number of entities found in a domain using Overte's [EntityViewer](https://apidocs.overte.org/EntityViewer.html). - -```javascript -var SEARCH_CENTER = {x: 0, y: -10, z: 0}; -var SEARCH_RADIUS = 100; - -var isInitialized = false; -var timeout = 1000; - -var update = function(deltaTime) { - if (!isInitialized) { - if (Entities.serversExist() && Entities.canRez()) { - EntityViewer.setPosition(SEARCH_CENTER); - EntityViewer.setCenterRadius(SEARCH_RADIUS); - EntityViewer.queryOctree(); - - Script.setTimeout(function(){ - var foundEntities = Entities.findEntities(SEARCH_CENTER, SEARCH_RADIUS).length; - - print("AC Script found: " + foundEntities + " entities within " + SEARCH_RADIUS + "m of " + JSON.stringify(SEARCH_CENTER)); - - }, timeout); - - isInitialized = true; - Script.update.disconnect(update); - } - } -}; - -Script.update.connect(update); -``` - -**See Also** - -+ [Configure Your Domain Settings](../host/configure-settings) -+ [Get Started with Scripting](get-started-with-scripting) -+ [Write Your Own Scripts](write-scripts) diff --git a/source/script/assignment-client-scripts.rst b/source/script/assignment-client-scripts.rst new file mode 100755 index 00000000..d4fcb0db --- /dev/null +++ b/source/script/assignment-client-scripts.rst @@ -0,0 +1,67 @@ +######################### +Assignment Client Scripts +######################### + +Assignment Client (AC) scripts (also known as "persistent scripts") run persistently in a domain and aren't affected by other scripts. These scripts run on an assignment client separate from the Interface, so the script will continue to run until you either remove the script from the domain or you shut down the domain entirely. + +With AC scripts, you can do things like coordinate actions between entities and avatars, and add virtual pets to greet visitors to your domain. + +.. contents:: On This Page + :depth: 2 + +---------------- +Add an AC Script +---------------- + +Once you've written and hosted your script, you need to add it to a domain, either your own or one where you have permissions to run an AC script. + +1. Open your 'Domain Administration Panel'. If you are on a local domain server, open it by clicking on the Overte icon in the taskbar notifications and 'click Settings'. +2. From the menu, go to **Content > Scripts**. +3. In the Persistent Scripts section, click **+** and paste the URL to your script under 'Script URL'. + +.. image:: _images/ac-script.png + +4. At the top of the page, click 'Save and Restart'. Now, every time you enter that domain, the AC script will be running. + +----------------------- +Example of an AC Script +----------------------- + +The following script counts the number of entities found in a domain using Overte's `EntityViewer `_. + +.. code-block:: javascript + + "use strict" + const SEARCH_CENTER = {x: 0, y: -10, z: 0}; + const SEARCH_RADIUS = 100; + + let isInitialized = false; + const timeout = 1000; + + const update = function(deltaTime) { + if (!isInitialized) { + if (Entities.serversExist() && Entities.canRez()) { + EntityViewer.setPosition(SEARCH_CENTER); + EntityViewer.setCenterRadius(SEARCH_RADIUS); + EntityViewer.queryOctree(); + + Script.setTimeout(function(){ + var foundEntities = Entities.findEntities(SEARCH_CENTER, SEARCH_RADIUS).length; + + print("AC Script found: " + foundEntities + " entities within " + SEARCH_RADIUS + "m of " + JSON.stringify(SEARCH_CENTER)); + + }, timeout); + + isInitialized = true; + Script.update.disconnect(update); + } + } + }; + + Script.update.connect(update); + +**See Also** + +- `Configure Your Domain Settings <../host/configure-settings>`_ +- `Get Started with Scripting `_ +- `Write Your Own Scripts `_ diff --git a/source/script/avatar-scripts.md b/source/script/avatar-scripts.md deleted file mode 100755 index 5016f583..00000000 --- a/source/script/avatar-scripts.md +++ /dev/null @@ -1,82 +0,0 @@ -# Avatar Scripts - -Avatar scripts are bound to an avatar. This means that they run when a user puts on a specific avatar. Likewise, avatar scripts stop running when the avatar is removed or changed. Other users in the domain will be able to see the script in action, but they will not be able to run the script themselves. - -With avatar scripts, you can do things like make your hair flow or create particle clouds around your avatar. - -**On This Page** - -* [Add an Avatar Script](#add-an-avatar-script) -* [Example of an Avatar Script](#example-of-an-avatar-script) - -## Add an Avatar Script -There are two different ways you can add an avatar script to your FST file: either by using our Package Model tool or by manually adding the script. - -To add an avatar script using the Package Model tools: -1. Create a folder called `scripts` in the same location as your FBX, GLB, or glTF file. -2. Copy your avatar script into this new folder. -3. In Interface, go to **Edit > Package Model as .fst** -4. For 'Script Directory', enter the path to the `scripts` folder you created above. - -To add an avatar script manually: -1. Open the FST file for your avatar in the text editor of your choice. -2. Add a line telling the avatar where to find the script file using the syntax `script = [SCRIPT URL]`.![](_images/add-script.png) - -You can add multiple scripts to your avatar by adding multiple `script = url` lines. - -## Example of an Avatar Script - -The following script makes your avatar throw balls when its right hand moves. - -```javascript -(function(){ - var triggerDistance = 0.0; - var TRIGGER_THRESHOLD = 0.9; - var LOAD_THRESHOLD = 0.6 - var init = false; - var rightHandIndex = MyAvatar.getJointIndex("RightHand"); - var rightArmIndex = MyAvatar.getJointIndex("RightArm"); - var distance = 0.0; - var triggered = false; - function fireBall(position, speed) { - var baseID = Entities.addEntity({ - type: "Sphere", - color: { blue: 128, green: 128, red: 20 }, - dimensions: { x: 0.1, y: 0.1, z: 0.1 }, - position: position, - dynamic: true, - collisionless: false, - lifetime: 10, - gravity: speed, - userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }" - }); - Entities.editEntity(baseID, { velocity: speed }); - } - Script.update.connect(function() { - rightHandPos = MyAvatar.getJointPosition(rightHandIndex); - rightArmPos = MyAvatar.getJointPosition(rightArmIndex); - fireDir = Vec3.subtract(rightHandPos, rightArmPos); - var distance = Vec3.length(fireDir); - triggerDistance = distance > triggerDistance ? distance : triggerDistance; - if (!triggered) { - if (distance < LOAD_THRESHOLD * triggerDistance) { - triggered = true; - } - } else if (distance > TRIGGER_THRESHOLD * triggerDistance) { - triggered = false; - fireBall(rightHandPos, Vec3.normalize(fireDir)); - } - }); - MyAvatar.scaleChanged.connect(function () { - triggerDistance = 0.0; - }); -}()); -``` - -This example script uses the [MyAvatar](https://apidocs.overte.org/MyAvatar.html) namespace to determine if your avatar's hand moves. Upon detecting movement, the script makes your avatar launch balls. It also uses some other namespaces such as [Entities](https://apidocs.overte.org/Entities.html) (to create the ball you will launch) and [Vec3](https://apidocs.overte.org/Vec3.html) (to determine the right positions and distances). Add it to your avatar to see how it works. - -**See Also** - -- [Get Started with Scripting](get-started-with-scripting) -- [Write Your Own Scripts](write-scripts) -- [API Reference](https://apidocs.overte.org) diff --git a/source/script/avatar-scripts.rst b/source/script/avatar-scripts.rst new file mode 100755 index 00000000..c2df61fb --- /dev/null +++ b/source/script/avatar-scripts.rst @@ -0,0 +1,119 @@ +############## +Avatar Scripts +############## + +Avatar scripts are bound to an avatar. This means that they run when a user puts on a specific avatar. Likewise, avatar scripts stop running when the avatar is removed or changed. Other users in the domain will be able to see the script in action, but they will not be able to run the script themselves. + +With avatar scripts, you can do things like make your hair flow or create particle clouds around your avatar. + +.. contents:: On This Page + :depth: 2 + +-------------------- +Add an Avatar Script +-------------------- + +The recommended way to add an avatar script to your FST file is by manually editing the file to add your script url: + +1. Open the FST file for your avatar in the text editor of your choice. +2. Add a line telling the avatar where to find the script file using the syntax ``script = [SCRIPT URL]``. + +.. code-block:: javascript + :emphasize-lines: 5 + :caption: A sample of woody's FST file with a script added + + name = mannequin + type = body+head + scale = 1 + filename = mannequin/mannequin.fbx + script = mannequin/scripts/throw_ball.js + joint = jointNeck = Neck + joint = jointLean = Spine + joint = jointEyeLeft = LeftEye + joint = jointEyeRight = RightEye + joint = jointRoot = Hips + joint = jointLeftHand = LeftHand + joint = jointRightHand = RightHand + joint = jointHead = Head + +You can add multiple scripts to your avatar by adding multiple ``script = url`` lines. + +--------------------------- +Example of an Avatar Script +--------------------------- + +The following script makes your avatar throw balls when its right hand moves. + +.. code-block:: javascript + :caption: throw_ball.js + + (function(){ + "use strict" + let triggerDistance = 0.0; + const TRIGGER_THRESHOLD = 0.9; + const LOAD_THRESHOLD = 0.6 + const rightHandIndex = MyAvatar.getJointIndex("RightHand"); + const rightArmIndex = MyAvatar.getJointIndex("RightArm"); + let triggered = false; + + function fireBall(position, speed) { + const baseID = Entities.addEntity({ + type: "Sphere", + color: { blue: 128, green: 128, red: 20 }, + dimensions: { x: 0.1, y: 0.1, z: 0.1 }, + position: position, + dynamic: true, + collisionless: false, + lifetime: 10, // Thrown fireball will despawn after 10 seconds + gravity: speed, + userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }" + }); + Entities.editEntity(baseID, { velocity: speed }); + } + + // VR users can push their right hand forwards from their shoulder to throw + Script.update.connect(function() { + const rightHandPos = MyAvatar.getJointPosition(rightHandIndex); + const rightArmPos = MyAvatar.getJointPosition(rightArmIndex); + const fireDir = Vec3.subtract(rightHandPos, rightArmPos); + const distance = Vec3.length(fireDir); + triggerDistance = distance > triggerDistance ? distance : triggerDistance; + if (!triggered) { + if (distance < LOAD_THRESHOLD * triggerDistance) { + triggered = true; + } + } else if (distance > TRIGGER_THRESHOLD * triggerDistance) { + triggered = false; + fireBall(rightHandPos, Vec3.normalize(fireDir)); + } + }); + MyAvatar.scaleChanged.connect(function () { + triggerDistance = 0.0; + }); + + // Desktop users can press and release "x" to throw + function keyReleaseEvent(event) { + if ((event.text.toUpperCase() === "X") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) { + const rightHandPos = MyAvatar.getJointPosition(rightHandIndex); + const rightArmPos = MyAvatar.getJointPosition(rightArmIndex); + const fireDir = Vec3.subtract(rightHandPos, rightArmPos); + fireBall(rightHandPos, Vec3.normalize(fireDir)); + } + } + // Runs desktop function whenever (any) key is released + Controller.keyReleaseEvent.connect(keyReleaseEvent); + // It is a good idea to clean up when the script stops + Script.scriptEnding.connect(function () { + print("removing key mapping"); + Controller.keyReleaseEvent.disconnect(keyReleaseEvent); + }); + }()); + + +This example script uses the `MyAvatar `_ namespace to determine if your avatar's hand moves. Upon detecting movement, the script makes your avatar launch balls. It also uses some other namespaces such as `Entities `_ (to create the ball you will launch) and `Vec3 `_ (to determine the right positions and distances). Add it to your avatar to see how it works. + +**See Also** + +- `Get Started with Scripting `_ +- `Write Your Own Scripts `_ +- `API Reference `_ diff --git a/source/script/client-entity-scripts.md b/source/script/client-entity-scripts.md deleted file mode 100755 index b4b98561..00000000 --- a/source/script/client-entity-scripts.md +++ /dev/null @@ -1,48 +0,0 @@ -# Client Entity Scripts - -You can make content in Overte interactive by attaching scripts to entities. *Client entity scripts* are entity scripts that run locally on each user's computer. When a user encounters the entity by loading it into view, it will "preload" (or run) the script, then "unload" (or stop) the script when the user leaves. - -There can be (and typically are) multiple entities in a domain, and each one can have a different client entity script associated with it. - -**On This Page** -* [Attach a Client Entity Script to an Entity](#attach-a-client-entity-script-to-an-entity) -* [Example of a Client Entity Script](#example-of-a-client-entity-script) - -## Attach a Client Entity Script to an Entity -To attach a client entity script to an entity: -1. In Interface, pull up your tablet or HUD and go to **Create**. -2. Select the entity you'd like to script by either clicking on it in Interface or finding it in the 'Entity List'. -3. In the **Create** app, go to the 'Properties' tab and scroll down to the 'Behavior' section. -4. For Script, enter the URL to your client entity script. - -
-

Note

-

For client entity scripts, the URL content must be available to every user who visits the domain. This means the URL should be a public http(s) URL, or an Asset Server (ATP) URL for the domain. It cannot be a file URL. The script property also accepts a string as input, allowing you to insert the code directly.

-
- -## Example of a Client Entity Script -The following script changes the color of a non-model entity (such as a box or a sphere) when you click on it: - -```javascript -(function () { - var clicked = false; - this.clickDownOnEntity = function (entityID, mouseEvent) { - if (clicked){ - Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} }); - clicked = false; - } else { - Entities.editEntity(entityID, { color: { red: 255, green: 255, blue: 0} }); - clicked = true; - } - }; -}) - -``` - -This example is written as a JavaScript class prototype function, and it uses the mouse event [clickDownOnEntity()](https://apidocs.overte.org/Entities.html#.sendClickDownOnEntity). When the user clicks on an entity, `clickDownOnEntity()` triggers the function associated with that click event. In this case, it changes the entity's color back and forth between yellow and magenta. - -**See Also** - -- [Get Started with Scripting](get-started-with-scripting) -- [Write Your Own Scripts](write-scripts) -- [API Reference](https://apidocs.overte.org) diff --git a/source/script/client-entity-scripts.rst b/source/script/client-entity-scripts.rst new file mode 100755 index 00000000..34db1c56 --- /dev/null +++ b/source/script/client-entity-scripts.rst @@ -0,0 +1,63 @@ +##################### +Client Entity Scripts +##################### + +You can make content in Overte interactive by attaching scripts to entities. *Client entity scripts* are entity scripts that run locally on each user's computer. When a user encounters the entity by loading it into view, it will "preload" (or run) the script, then "unload" (or stop) the script when the user leaves. + +There typically are multiple entities in a domain, and each one can have a different client entity script associated with it. + +As each client entity script will run on all users' clients simultaneously, it is most suitable for responding to each user interacting with it. If you want to control its behaviour independently, you can give it a brain using a :doc:`server entity script `. + +.. contents:: On This Page + :depth: 2 + +------------------------------------------ +Attach a Client Entity Script to an Entity +------------------------------------------ + +To attach a client entity script to an entity: + +1. In Interface, pull up your tablet or HUD and go to **Create**. +2. Select the entity you'd like to script by either clicking on it in Interface or finding it in the 'Entity List'. +3. In the **Create** app, go to the 'Properties' tab and select the Scripts icon. |scripts-icon| +4. For Script, enter the URL to your client entity script. + +.. note:: For client entity scripts, the URL content must be available to every user who visits the domain. This means the URL should be a public http(s) URL, or an Asset Server (ATP) URL for the domain. It cannot be a file URL. The script property also accepts a string as input, allowing you to insert the code directly. + +.. |scripts-icon| image:: _images/create-properties-scripts-icon.png + :height: 4ex + :class: no-scaled-link inline + :alt: paper and quill icon + +--------------------------------- +Example of a Client Entity Script +--------------------------------- + +The following script changes the color of a non-model entity (such as a box or a sphere) when you click on it: + +.. code-block:: javascript + + (function () { + "use strict" + let clicked = false; + this.mousePressOnEntity = function (entityID, mouseEvent) { + if (clicked){ + Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} }); + clicked = false; + } else { + Entities.editEntity(entityID, { color: { red: 255, green: 255, blue: 0} }); + clicked = true; + } + }; + }); + +Client Entity Scripts are written as a JavaScript class prototype function, and this example uses the mouse/controller event `mousePressOnEntity() `_. When the user clicks on an entity, ``mousePressOnEntity()`` triggers the function associated with that click event. In this case, it changes the entity's color back and forth between yellow and magenta. + +.. note:: + Entity scripts **must** be inside a class prototype function. In the above example we include ``"use strict"`` on the first line of the client entity script to enable `strict mode `_ . This must be inside the class prototype function, not the first line of the file as in other scripts. + +**See Also** + +- `Get Started with Scripting `_ +- `Write Your Own Scripts `_ +- `API Reference `_ diff --git a/source/script/get-started-with-scripting.rst b/source/script/get-started-with-scripting.rst index 4553890f..dc0711e3 100755 --- a/source/script/get-started-with-scripting.rst +++ b/source/script/get-started-with-scripting.rst @@ -2,7 +2,7 @@ Get Started with Scripting ########################## -Many of the scripts in Overte run behind the scenes, so that you don't even know they're running. However, if you want to create some advanced behavior, you may need to :doc:`write your own scripts ` to make sure everything works correctly. +Overte has a powerful scripting interface, in fact many of the features you might use whilst exploring Overte's worlds run on the scripting engine. The tablet you use to access apps, the community apps themselves, even the entities which make up much of the world; all of them are powered by scripts. You can modify many of these existing scripts, and even :doc:`write your own scripts` to reshape the Overte experience into your own. This page ensures that you know what type of script to use and helps you get started running your own simple scripts. @@ -13,40 +13,40 @@ This page ensures that you know what type of script to use and helps you get sta JavaScript Basics in Overte ----------------------------- -Overte scripting runs on a JavaScript engine that is provided with Qt. +Overte scripting runs on the V8 scripting engine, with support for both JavaScript and WebAssembly. To access the Overte API you will need to use JavaScript. .. note:: Note that any functionality that runs around web pages (such as cookies, local storages, or databases) does not work with 3D environments such as Overte. For this reason, you cannot use JavaScript frameworks such as Angular, React, Express, jQuery, Vue, etc. You are likely to interface most with these Overte APIs: -+-------------------------------------------------------------------------+------------------------------------------------------------------+ -| API(s) | Description | -+=========================================================================+==================================================================+ -| `Entities `_ | Lets you manipulate the entities around you, as long | -| | as you have permissions to do so. This means you can | -| | add, remove, and edit entities. Everyone has access | -| | to ``get`` properties of an entity, and can be used | -| | to find Entities in range, direction, collision, or | -| | raytrace. | -+-------------------------------------------------------------------------+------------------------------------------------------------------+ -| `AvatarList `_ | Lets you get information on an `Avatar | -| | `_, | -| `AvatarManager `_ | or manipulate your own client-only `MyAvatar | -| | `_. The | -| `MyAvatar `_ | information here will be always the avatar information | -| | of the client running the script. AvatarList and | -| | AvatarManager are basically the same. | -+-------------------------------------------------------------------------+------------------------------------------------------------------+ -| `Script `_ | Lets you to connect callbacks from your client to script, | -| | such as functionality that is dependent on time | -| | (Script.update, Script.setTime, Script.setInterval etc), | -| | connect paths relatively to Assets (Script.relativePath), | -| | refer to other scripts (Script.include), or create events | -| | which occur when the script is turned off (Script.scriptEnding). | -+-------------------------------------------------------------------------+------------------------------------------------------------------+ - - -There are `many other APIs available `_, and we encourage you to make sure use of them as you become more comfortable scripting in Overte. ++---------------------------------------------------------------------+----------------------------------------------------------------------+ +| API(s) | Description | ++=====================================================================+======================================================================+ +| `Entities `_ | Lets you manipulate the entities around you, as long | +| | as you have permissions to do so. This means you can | +| | add, remove, and edit entities. Everyone has access | +| | to ``get`` properties of an entity, which can be used | +| | to find Entities in range, direction, collision, or | +| | raytrace. | ++---------------------------------------------------------------------+----------------------------------------------------------------------+ +| `AvatarList `_ | Lets you get information on an `Avatar | +| | `_, | +| `AvatarManager `_ | or manipulate your own client-only `MyAvatar | +| | `_. The | +| `MyAvatar `_ | information here will always be the avatar information | +| | of the client running the script. AvatarList and | +| | AvatarManager are basically the same. | ++---------------------------------------------------------------------+----------------------------------------------------------------------+ +| `Script `_ | Allows you to connect callbacks from your client to a script, | +| | such as functionality that is dependent on time | +| | (``Script.update``, ``Script.setTime``, ``Script.setInterval``, etc),| +| | connect paths relatively to Assets (``Script.relativePath``), | +| | refer to other scripts (``Script.include``), or create events | +| | which occur when the script is turned off (``Script.scriptEnding``). | ++---------------------------------------------------------------------+----------------------------------------------------------------------+ + + +There are `many other APIs available `_, which we encourage you to make use of as you become more comfortable scripting in Overte. ---------------- Types of Scripts @@ -66,11 +66,11 @@ Types of Scripts | | hair. | +--------------------------+-------------------------------------------------------------------------------------+ | Client Entity Script | *Client entity scripts* are scripts attached to entities that run locally in | -| | response to a user in a domain. With these scripts, you can customize what happens | -| | when a user encounters an entity. | +| | response to each user in a domain. With these scripts, you can customize what | +| | happens when a user encounters an entity by loading it into view. | +--------------------------+-------------------------------------------------------------------------------------+ | Server Entity Script | *Server entity scripts* are scripts attached to entities that do not require a | -| | user to trigger. These scripts control entities so that their behavior is seen and | +| | user to trigger. These scripts control entities so that their behavior is seen or | | | heard by everyone in the domain. | +--------------------------+-------------------------------------------------------------------------------------+ @@ -84,7 +84,7 @@ Each domain owner has the ability to :doc:`restrict create and edit permissions Running Scripts Window ---------------------- -The Running Scripts window can be used to load, run and stop scripts from a URL or from a disk drive. Overte also provides a number of sample scripts for you to try out. +The Running Scripts window can be used to load, run and stop scripts from a URL or from a local file. Overte also provides a number of sample scripts for you to try out. To open the *Running Scripts* window, go to **Edit > Running Scripts** or press ``Ctrl`` + ``J`` on your keyboard. @@ -94,31 +94,34 @@ Sample Scripts Overte comes with a collection of scripts designed to improve your experience as a user and provide tools for developing your own content. We encourage you to look at these scripts as a resource to learn how to code your own. -.. note:: Loading (or running) a script lets you test the functionality and see how it behaves. If you want to view the actual code, you will need to open the file in the text editor of your choice. In the 'Running Scripts' window, click the 'Reveal Scripts' folder and browse to the JavaScript file that you want to view. - -These are the scripts we have available: - -+----------------+------------------------------------------------------------------------------------+ -| Scripts Folder | Description | -+================+====================================================================================+ -| ``android`` | These scripts were built to run on Android devices. | -+----------------+------------------------------------------------------------------------------------+ -| ``developer`` | These scripts were created for internal use and debugging, but are available as | -| | advanced developers may find them useful when creating content. These scripts are | -| | not "entry-level" and are not guaranteed to work or be documented. | -+----------------+------------------------------------------------------------------------------------+ -| ``modules`` | These scripts create external tools that simplify scripting in Overte. | -| | For example, the AppUI module helps you create a tablet app, while the Request | -| | module processes HTTP requests. | -+----------------+------------------------------------------------------------------------------------+ -| ``system`` | These scripts are critical to the stability and usability of Overte. | -| | Making changes to these scripts is not recommended, nor is it easy, as you may | -| | need 'administrative' privileges. | -+----------------+------------------------------------------------------------------------------------+ -| ``tutorials`` | These scripts provide examples of what you can do using scripts in Overte. | -| | Examples include: creating butterflies, making your avatar clap, and adding | -| | ambient sound to your domain. | -+----------------+------------------------------------------------------------------------------------+ +.. note:: Loading (or running) a script lets you test the functionality and see how it behaves. If you want to view the actual code, you will need to open the file in the text editor of your choice. In the 'Running Scripts' window, click 'Reveal Scripts Folder' and browse to the JavaScript file that you want to view. + +These are the scripts we have available: + ++----------------------+------------------------------------------------------------------------------------+ +| Scripts Folder | Description | ++======================+====================================================================================+ +| ``android`` | These scripts were built to run on Android devices. | ++----------------------+------------------------------------------------------------------------------------+ +| ``communityScripts`` | These scripts were contributed by the community to improve the default | +| | Overte experience. | ++----------------------+------------------------------------------------------------------------------------+ +| ``developer`` | These scripts were created for internal use and debugging, but are available as | +| | advanced developers may find them useful when creating content. These scripts are | +| | not "entry-level" and are not guaranteed to work or be documented. | ++----------------------+------------------------------------------------------------------------------------+ +| ``modules`` | These scripts create external tools that simplify scripting in Overte. | +| | For example, the AppUI module helps you create a tablet app, while the Request | +| | module processes HTTP requests. | ++----------------------+------------------------------------------------------------------------------------+ +| ``system`` | These scripts are critical to the stability and usability of Overte. | +| | Making changes to these scripts is not recommended, nor is it easy, as you may | +| | need 'administrative' privileges. | ++----------------------+------------------------------------------------------------------------------------+ +| ``tutorials`` | These scripts provide examples of what you can do using scripts in Overte. | +| | Examples include: creating butterflies, making your avatar clap, and adding | +| | ambient sound to your domain. | ++----------------------+------------------------------------------------------------------------------------+ ^^^^^^^^^^^^^^^^^^^^^ Load and Run a Script @@ -127,10 +130,13 @@ Load and Run a Script To run a script: 1. Open the 'Running Scripts' window. -2. For scripts hosted in the cloud, click 'From URL'. Enter the URL of your script file and click 'OK'. +2. For scripts hosted on the internet, click 'From URL'. Enter the URL of your script file and click 'OK'. 3. For scripts on your local computer, click 'From Disk'. Browse to your script file and click 'Open'. 4. To load a sample script, browse to the script at the bottom of the 'Running Scripts' window. +.. note:: + Any scripts you load from the 'Running Scripts' window will load automatically the next time you start Overte. + ^^^^^^^^^^^^^^^^^^^^^^^ Reload or Stop a Script ^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,21 +145,10 @@ To reload or stop a script, open the 'Running Scripts' window and do one of the * To reload all running scripts, click the 'Reload All' button at the top of the 'Running Scripts' window. * To reload a specific script, click the circular arrow next to the script. -* To stop all running scripts, click the 'Stop All' button at the top of the 'Running Scripts' window. +* To stop all running scripts, click the 'Remove All' button at the top of the 'Running Scripts' window. * To stop a specific script, click the 'X' next to the script. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Add a Script to the Default Scripts -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You can add a script to the default scripts to run every time you start Interface. - -* In Interface, pull up your Tablet or HUD and go to **Menu > Edit > Running Scripts**. -* Click 'Reveal Scripts Folder' at the bottom. -* In the file explorer window, open the 'defaultScripts.js' file. -* Add your script to this file to make it run with other default scripts. Ensure the folder path to your script is correct. - -.. note:: The 'defaultScripts.js' file is updated every time you update Interface to the latest release version. This means that any changes you make to the file will be overwritten. You can avoid this by writing and running a 'loader' script to load scripts on start up. +.. note:: By stopping a script, you are in effect *removing* that script from the running list. You will need to find and load that script again to have it appear in the list. If you **Remove All** scripts you can get the default scripts back by selecting **Load Defaults** ----------------- Scripting Console @@ -163,14 +158,18 @@ The Scripting Console lets you test and run short script snippets quickly in Ove .. image:: _images/scripting-console.png +.. _debug window: + ------------ Debug Window ------------ -The Debug Window shows the output generated by your running scripts. This lets you watch the script(s) in action and make sure that it is running as you intended. If the script fails, the debugger can help you identify what went wrong, and point you to specific lines of code where the error occurred. To open the Debug Window, go to the 'Developer' menu, then **Scripting > Script Log** (HMD Friendly). If the Developer menu is not visible, first go to the 'Settings' menu and click 'Developer' Menu. +The Debug Window shows the output generated by your running scripts. This lets you watch the script(s) in action and make sure that it is running as you intended. If the script fails, the debugger can help you identify what went wrong, and point you to specific lines of code where the error occurred. To open the Debug Window, go to the 'Developer' menu, then **Scripting > Script Log (HMD Friendly)**. If the Developer menu is not visible, first go to the 'Settings' menu and click 'Developer' Menu. .. image:: _images/debug-window.png +.. note:: To debug a server entity script you should instead use the :ref:`Server Entity Script Log` to view the output of your script. + **See Also** + :doc:`Interface Scripts ` diff --git a/source/script/interface-scripts.md b/source/script/interface-scripts.md deleted file mode 100755 index e9f183f6..00000000 --- a/source/script/interface-scripts.md +++ /dev/null @@ -1,40 +0,0 @@ -# Interface Scripts - -Interface scripts run on your local machine, as long as you have Interface up and running. Each user has full control over when interface scripts are started and stopped. The results (such as when your script changes the color of a box) can be seen by everyone in your domain, but the script itself is running on your local machine. Your Interface will communicate that information to the Entity Server, which will communicate it to whoever is visiting the domain. - -With interface scripts, you can do things like add new menus to the Interface, add plug-ins, or add 3D overlays that you have control over. - -**On This Page** -* [Load an Interface Script](#load-an-interface-script) -* [Example of an Interface Script](#example-of-an-interface-script) - -## Load an Interface Script - -To load and run an interface script: -1. In Interface, go to **Edit > Running Scripts** or press Ctrl + J on your keyboard. -2. For scripts hosted in the cloud, click 'From URL'. Enter the URL of your script file and click 'OK'. -3. For scripts on your local computer, click 'From Disk'. Browse to your script file and click 'Open'. - -## Example of an Interface Script - -The following script automatically enters a first person perspective when you enter VR mode with a HMD. - -```javascript -(function() { - -// Automatically enter first person mode when entering HMD mode -HMD.displayModeChanged.connect(function(isHMDMode) { - if (isHMDMode) { - Camera.setModeString("first person"); - } -}); - -}()); -``` - - - -**See Also** - -+ [Get Started with Scripting](get-started-with-scripting) -+ [Write Your Own Scripts](write-scripts) diff --git a/source/script/interface-scripts.rst b/source/script/interface-scripts.rst new file mode 100755 index 00000000..6ac7a2fe --- /dev/null +++ b/source/script/interface-scripts.rst @@ -0,0 +1,110 @@ +################# +Interface Scripts +################# + +Interface scripts run on your local machine, as long as you have Interface up and running. Each user has full control over when interface scripts are started and stopped. The results (such as when your script changes the color of a box) can be seen by everyone in your domain, but the script itself is running on your local machine. Your Interface will communicate that information to the Entity Server, which will communicate it to whoever is visiting the domain. + +With interface scripts, you can do things like add new menus to the interface, create dynamic gadgets or toys, and manipulate your own avatar to change how it looks or moves. + +.. contents:: On This Page + :depth: 2 + +------------------------ +Load an Interface Script +------------------------ + +To load and run an interface script: + +1. In Interface, go to **Edit > Running Scripts** or press :kbd:`Ctrl+J` on your keyboard. +2. For scripts hosted on the internet, click **From URL**. Enter the URL of your script file and click **OK**. +3. For scripts on your local computer, click **From Disk**. Browse to your script file and click **Open**. + +------------------------------ +Example of an Interface Script +------------------------------ + +The following script creates a light cube of a randomised colour in front of you when you load it, and shows how you can spawn a text entity whenever you switch into or out of VR. + +.. code-block:: javascript + :caption: **example-interface-script.js** + + "use strict" + + // Generate a random colour + function generateColour() { + const randNum = () => (Math.random() * 256) | 0; + return [randNum(), randNum(), randNum()]; + } + + // Generate a random colour + const colour = generateColour(); + + // Spawn a bright cube + const entityID = Entities.addEntity({ + type: "Box", + name: "example colour box", + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })), + dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + unlit: true, // Cube will always be fully lit + billboardMode: "yaw", // Cube will always face you + color: colour, // random colour generated earlier + canCastShadow: false, // Cube will not block light + lifetime: 300 // Delete after 5 minutes. + }, "avatar"); + + // spawn a light inside the cube + const lightID = Entities.addEntity({ + type: "Light", + name: "example colour light", + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })), + dimensions: { x: 20, y: 20, z: 20 }, + parentID: entityID, // Will be a child of the cube entity + color: colour, // random colour generated earlier + intensity: 10, // brightness + falloffRadius: 1.3, // Light intensity reduced by 25% this far out + lifetime: 300 // Delete after 5 minutes. + }, "avatar"); + + // Display some text welcoming you to your new mode when switching in and out of VR + HMD.displayModeChanged.connect(function(isHMDMode) { + if (isHMDMode) { + print("Welcome to VR!"); + Entities.addEntity({ + type: "Text", + name: "example text", + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })), + dimensions: { x: 1.0, y: 0.1, z: 0.5 }, + text: "Welcome to VR!", + unlit: true, // Text will be fully lit + billboardMode: "yaw", // Text will always face you + lifetime: 30 // Delete after 30 seconds. + }, "local"); // Text is only visible to you + print("Entity created: " + entityID); + } else { + print("Welcome to Desktop!"); + Entities.addEntity({ + type: "Text", + name: "example text", + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })), + dimensions: { x: 1.0, y: 0.1, z: 0.5 }, + text: "Welcome to Desktop!", + unlit: true, // Text will be fully lit + billboardMode: "yaw", // Text will always face you + lifetime: 30 // Delete after 30 seconds. + }, "local"); // Text is only visible to you + print("Entity created: " + entityID); + } + + }); + + // Clean up when the script stops running + Script.scriptEnding.connect(function() { + Entities.deleteEntity(entityID); // Removes the Box entity, including its child Light entity. + }); + + + +**See Also** + +- `Get Started with Scripting `_ +- `Write Your Own Scripts `_ diff --git a/source/script/js-tips.md b/source/script/js-tips.md deleted file mode 100755 index 4a9ac72e..00000000 --- a/source/script/js-tips.md +++ /dev/null @@ -1,203 +0,0 @@ -# JavaScript Tips & Tricks - -Overte's robust [JavaScript API](https://apidocs.overte.org) provides the tools for you to build great content and user experiences in VR. We've compiled some advanced JavaScript tips you can use while scripting for Overte. - -You can use the [Scripting Console in Interface](get-started-with-scripting.rst#scripting-console) to try out the examples on this page. The output will be visible in the console itself. - -**On This Page:** - -+ [Compute 3D Math Operations](#compute-3d-math-operations) - + [Get Your Avatar's Position](#get-your-avatars-position) - + [Get Your Avatar's Orientation](#get-your-avatars-orientation) - + [Get the Direction Your Avatar is Facing](#get-the-direction-your-avatar-is-facing) - + [Make an Entity Appear Before Your Avatar](#make-an-entity-appear-before-your-avatar) -+ [Include External JS and JSON Files](#include-external-js-and-json-files) -+ [Equip an Item](#equip-an-item) -+ [Connect a Signal to a Function](#connect-a-signal-to-a-function) - -## Compute 3D Math Operations - -When you script for VR worlds like Overte, you need 3D math operations to compute the position and orientation of 3D objects and avatars in-world. We cannot simply add two vectors. To script 3D math operations and to determine position and orientation information of avatars, you can use the following namespaces in our JavaScript API: - -+ [Vec3](https://apidocs.overte.org/Vec3.html): The Vec3 API has facilities for generating and manipulating 3-dimensional vectors. -+ [Quat](https://apidocs.overte.org/Quat.html): The Quat API provides facilities for generating and manipulating quaternions. -+ [MyAvatar](https://apidocs.overte.org/MyAvatar.html): The MyAvatar API provides facilities for manipulating avatars. - -### Get Your Avatar's Position - -When creating objects in world, it's often very helpful to know where your avatar currently is. - -Overte uses a 3D Cartesian coordinate system where the position vector of an entity or avatar looks like this: - -```javascript -{ x: 0, y: 0, z: 0 } -``` - -To get your avatar's current position, use the [MyAvatar](https://apidocs.overte.org/MyAvatar.html) namespace. MyAvatar contains properties with information related to your avatar. Use the position property, `MyAvatar.position`, which returns an object. - -In the following example, we are using the JSON.stringify method to convert the JavaScript object (returned by `MyAvatar.position`) to a data string that can be sent over the server. - -Open your Scripting Console and find your avatar's position. - -```javascript -JSON.stringify(MyAvatar.position); -// {"x":-10.349810600280762,"y":-9.55379867553711,"z":11.861204147338867} -``` - -### Get Your Avatar's Orientation - -If you want an object to appear in front of you, you need to know how your avatar is currently oriented in-world. - -Rotations are handled are by a number-system called Quaternions. Quaternions help simplify calculations in three dimensional space. They add an extra dimension of 'w' and the values are normalized (-1,1). - -Quaternions are represented in the form: - -```javascript -{ x: 0, y: 0, z: 0, w: 1 } -``` - -Get your avatar's orientation in the Scripting Console by using the `MyAvatar.orientation` property: - -```javascript -JSON.stringify(MyAvatar.orientation); -// {"x":0,"y":-0.4974651634693146,"z":0,"w":0.8674839735031128} -``` - -### Get the Direction Your Avatar is Facing - -You can use the [Quat](https://apidocs.overte.org/Quat.html) namespace to get the direction which your avatar is facing. Pass your avatar's orientation to `Quat.getForward` to get a vector describing which direction you are facing on the world axis. - -```javascript -{ x: 0, y: 0, z: 1 } // Backward -{ x: 0, y: 0, z: -1 } // Forward -{ x: -1, y: 0, z: 0 } // Left -{ x: 1, y: 0, z: 0 } // Right -``` - -### Make an Entity Appear Before Your Avatar - -You can make an entity appear before your avatar and also control the distance at which it appears. - -Use the [Vec3](https://apidocs.overte.org/Vec3.html) namespace and the direction your avatar is facing to return the position at which you can make your entity appear. This position is 1m away from your avatar. - -```javascript -Vec3.sum(MyAvatar.position, Quat.getForward(MyAvatar.orientation)); // This will add your position vector to the direction vector returned from Quat.getForward. This will represent a position that is 1 meter in front of your avatar. -``` - -You can also control the distance at which an entity appears rather than using the default distance of 1m. First, multiply the vector representing the direction your avatar is facing and the distance. - -```javascript -Vec3.multiply(Quat.getForward(MyAvatar.orientation), 2.0); // if we are facing forward, that means our vector { x: 0, y: 0, z: -1 }, get's multiplied by 2.0 giving us a vector of { x: 0, y: 0, z: -2 } -``` - -Use `Vec3.sum` to return a new vector representing how far away an entity will appear from your avatar. - -```javascript -Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation, 2.0))); // this will give us a final vector representing where in the world a point 2 meters directly in front of our avatar is -``` - -We've included the above operations in a function below for you to save and run as a script. - -```javascript -var myPosition = MyAvatar.position; -var myOrientation = MyAvatar.orientation; -var myDirection = Quat.getForward(myOrientation); -var distanceInFrontOfMe = 2.0; -var distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe); -var positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe); - -// we can even wrap this all up in a function to help simplify this any time we want the position of an object to appear in front of us -function getPositionInFrontOfMe(distanceInFrontOfMe){ - var myPosition = MyAvatar.position; - var myOrientation = MyAvatar.orientation; - var myDirection = Quat.getForward(myOrientation); - var distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe); - var positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe); - return positionOfObjectInFrontOfMe; -} - -getPositionInFrontOfMe(4.0); // { x: 0, y: 0, z: -4 } -getPositionInFrontOfMe(8.0); // { x: 0, y: 0, z: -8 } -``` - -## Include External JS and JSON Files - -When writing a script in Overte, you might need to access the methods or objects in an external JS file or get information from a JSON file. For example, if you're writing a script to make your avatar wave, you might need to use some methods that already exist in an external JS file. You can do this using the `require` method in the Scripts namespace of our API. - -Any script that you try to retrieve using this method must export either a function or an object. Let's try this using an example. - -Create a JS script that you want to access from your main script. - -**example.js** - -```javascript -module.exports = { - sayHello: function () { - console.log("Hello!"); - }, - sayGoodbye: function () { - console.log("Goodbye!"); - } -}; -``` - -In **example.js**, you are exporting two functions that print either Hello or Goodbye, depending on which function you call, to the console. Now, let's use `require` in your main script. - -Create a JS script called **main.js**. - -```javascript -var greet = Script.require(Script.resolvePath("example.js")); -greet.sayHello(); // prints Hello to the console -``` - -When you use the `require` method, you are making any function or object exported from **example.js** available to **main.js**. This means that **main.js** now has access to functions that will print either Hello or Goodbye to the console. In the above example, we are printing Hello to the console when we run **main.js**. - -
-

Note

-

We recommend using relative paths in your development so that you can easily move content without having to update absolute paths.

-
- -## Equip an Item -You can equip an item by grabbing and holding an entity without pressing the grab button or trigger continuously. For example, you could equip a paint brush to your avatar's hand and drop it only when you're done painting. - -You can equip an item using a script: - -```javascript -Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'XXX', entityID: 'YYY'})); // where XXX is either the left or right hand and YYY is entityID to equip -``` - -To drop the entity from your avatar's hand: -```javascript -Messages.sendLocalMessage('Hifi-Hand-Drop', 'XXX'); // where XXX is either the left or right hand -``` - -## Connect a Signal to a Function - -Signals can be connected to functions. This means that every time a signal is triggered, a function is executed. For example, if your avatar changes when collisions are enabled or disabled, you can connect a function to react to this specific event such as: -``` -function collisionChanged(enabled) { - if(enabled) { - console.log("avatar collision is enabled"); - } else { - console.log("avatar collision id disabled") - } -} - -MyAvatar.collisionsEnabledChanged.connect(collisionChanged); -``` - -Each signal usually gets passed in arguments, and you can refer to the [API documentation](https://apidocs.overte.org/MyAvatar.html) to see what a signal will provide you, such as the enabled property passed into collision changed. - -It's good practice to disconnect from signals, but you can only do that if you name your function. - -``` -MyAvatar.collsionEnabledChanged.disconnect(collsionChanged); -``` - - - - -**See Also** - -+ [Write Your Own Scripts](write-scripts) -+ [API Reference](https://apidocs.overte.org) diff --git a/source/script/js-tips.rst b/source/script/js-tips.rst new file mode 100755 index 00000000..53cab592 --- /dev/null +++ b/source/script/js-tips.rst @@ -0,0 +1,232 @@ +============================= +JavaScript Tips & Tricks +============================= + +Overte's robust `JavaScript API `_ provides the tools for you to build great content and experiences in VR and on Desktop. We've compiled some advanced JavaScript tips you can use while scripting for Overte. + +You can use the `Scripting Console in Interface `_ to try out the examples on this page. The output will be visible in the console itself. + +.. contents:: On This Page + :depth: 3 + +----------------------------- +Compute 3D Math Operations +----------------------------- + +When you script for virtual worlds like Overte, you need 3D math operations to compute the position and orientation of 3D objects and avatars in-world. We cannot simply add two vectors. To script 3D math operations and to determine position and orientation information of avatars, you can use the following namespaces in our JavaScript API: + ++ `Vec3 `_: The Vec3 API has facilities for generating and manipulating 3-dimensional vectors. ++ `Quat `_: The Quat API provides facilities for generating and manipulating quaternions. ++ `MyAvatar `_: The MyAvatar API provides facilities for manipulating your avatar. + +++++++++++++++++++++++++++++++++ +Get Your Avatar's Position +++++++++++++++++++++++++++++++++ + +When creating objects in world, it's often very helpful to know where your avatar currently is. + +Overte uses a 3D Cartesian coordinate system where the position vector of an entity or avatar looks like this:: + + { x: 0, y: 0, z: 0 } + + +To get your avatar's current position, use the `MyAvatar `_ namespace. MyAvatar contains properties with information related to your avatar. Use the position property, ``MyAvatar.position``, which returns an object. + +In the following example, we are using the ``JSON.stringify`` method to convert the JavaScript object (returned by ``MyAvatar.position``) to a data string that can be sent over the server. + +Open your Scripting Console and find your avatar's position + +.. code-block:: javascript + + JSON.stringify(MyAvatar.position); + // {"x":-10.349810600280762,"y":-9.55379867553711,"z":11.861204147338867} + ++++++++++++++++++++++++++++++++++ +Get Your Avatar's Orientation ++++++++++++++++++++++++++++++++++ + +If you want an object to appear in front of you, you need to know how your avatar is currently oriented in-world. + +Rotations are handled by a number-system called Quaternions. Quaternions help simplify calculations in three dimensional space. They add an extra dimension of 'w' and the values are normalized (-1,1). + +Quaternions are represented in the form:: + + { x: 0, y: 0, z: 0, w: 1 } + +Get your avatar's orientation in the Scripting Console by using the ``MyAvatar.orientation`` property: + +.. code-block:: javascript + + JSON.stringify(MyAvatar.orientation); + // {"x":0,"y":-0.4974651634693146,"z":0,"w":0.8674839735031128} + ++++++++++++++++++++++++++++++++++++++++++++ +Get the Direction Your Avatar is Facing ++++++++++++++++++++++++++++++++++++++++++++ + +You can use the `Quat `_ namespace to get the direction which your avatar is facing. Pass your avatar's orientation to ``Quat.getForward`` to get a vector describing which direction you are facing on the world axis. + +:: + + { x: 0, y: 0, z: 1 } // Backward + { x: 0, y: 0, z: -1 } // Forward + { x: -1, y: 0, z: 0 } // Left + { x: 1, y: 0, z: 0 } // Right + + +++++++++++++++++++++++++++++++++++++++++++++ +Make an Entity Appear Before Your Avatar +++++++++++++++++++++++++++++++++++++++++++++ + +You can make an entity appear before your avatar and also control the distance at which it appears. + +Use the `Vec3 `_ namespace and the direction your avatar is facing to return the position at which you can make your entity appear. This position is 1m away from your avatar: + + +.. code-block:: javascript + + Vec3.sum(MyAvatar.position, Quat.getForward(MyAvatar.orientation)); // This will add your position vector to the direction vector returned from Quat.getForward. This will represent a position that is 1 meter in front of your avatar. + +You can also control the distance at which an entity appears rather than using the default distance of 1m. First, multiply the vector representing the direction your avatar is facing and the distance: + +.. code-block:: javascript + + Vec3.multiply(Quat.getForward(MyAvatar.orientation), 2.0); // if we are facing forward, that means our vector { x: 0, y: 0, z: -1 }, get's multiplied by 2.0 giving us a vector of { x: 0, y: 0, z: -2 } + +Use ``Vec3.sum`` to return a new vector representing how far away an entity will appear from your avatar: + +.. code-block:: javascript + + Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), 2.0)); // this will give us a final vector representing where in the world a point 2 meters directly in front of our avatar is + +We've included the above operations in a function below for you to save and run as a script. + +.. code-block:: javascript + + "use strict" + const myPosition = MyAvatar.position; + const myOrientation = MyAvatar.orientation; + const myDirection = Quat.getForward(myOrientation); + const distanceInFrontOfMe = 2.0; + const distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe); + const positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe); + + // we can even wrap this all up in a function to help simplify this any time we want the position of an object to appear in front of us + function getPositionInFrontOfMe(distanceInFrontOfMe){ + const myPosition = MyAvatar.position; + const myOrientation = MyAvatar.orientation; + const myDirection = Quat.getForward(myOrientation); + const distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe); + const positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe); + return positionOfObjectInFrontOfMe; + } + + getPositionInFrontOfMe(4.0); // { x: 0, y: 0, z: -4 } + getPositionInFrontOfMe(8.0); // { x: 0, y: 0, z: -8 } + +------------------------------------- +Include External JS and JSON Files +------------------------------------- + +When writing a script in Overte, you might need to access the methods or objects in an external JS file or get information from a JSON file. For example, if you're writing a script to make your avatar wave, you might need to use some methods that already exist in an external JS file. You can do this using the ``require`` method in the Scripts namespace of our API. + +Any script that you try to retrieve using this method must export either a function or an object. Let's try this using an example. + +Create a JS script that you want to access from your main script. + +.. code-block:: javascript + :caption: **example.js** + + module.exports = { + sayHello: function () { + print("Hello!"); + }, + sayGoodbye: function () { + print("Goodbye!"); + } + }; + +In **example.js**, you are exporting two functions that print either Hello or Goodbye, depending on which function you call, to the console. Now, let's use ``require`` in your main script. + +Create a JS script called **main.js**: + +.. code-block:: javascript + :caption: **main.js** + + const greet = Script.require(Script.resolvePath("example.js")); + greet.sayHello(); // prints Hello to the console + +When you use the ``require`` method, you are making any function or object exported from **example.js** available to **main.js**. This means that **main.js** now has access to functions that will print either Hello or Goodbye to the console. In the above example, we are printing Hello to the console when we run **main.js**. + +.. note:: We recommend using relative paths in your development so that you can easily move content without having to update absolute paths. + +---------------- +Equip an Item +---------------- + +You can equip an item by grabbing and holding an entity without pressing the grab button or trigger continuously. For example, you could equip a paint brush to your avatar's hand and drop it only when you're done painting. + +You can equip an item using a script: + +.. code-block:: javascript + + Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'XXX', entityID: 'YYY'})); // where XXX is either the 'left' or 'right' hand and YYY is entityID to equip + +To drop the entity from your avatar's hand: + +.. code-block:: javascript + + Messages.sendLocalMessage('Hifi-Hand-Drop', 'XXX'); // where XXX is either the 'left' or 'right' hand + +.. note:: In order for an entity to be equipped it must be `equippable `_ . A user must be able to *grab* an entity before they can equip it, however a script does not need the entity to be `grabbable `_ before it can equip it with the ``'Hifi-Hand-Grab'`` message. + +Below is an example of a complete Interface script which will first create an *equippable* entity, and then equip it + +.. code-block:: javascript + + "use strict" + // Create the entity, note that it is marked as equippable + const entityID = Entities.addEntity({ + type: "Box", + position: Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)), + grab: { + equippable: true, + }, + }); + + // Equip the entity to your avatar's "left" hand + Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'left', entityID: entityID})); + +.. note:: A user can unequip all of their equiped items by pressing **u** on their keyboard. + +--------------------------------- +Connect a Signal to a Function +--------------------------------- + +Signals can be connected to functions. This means that every time a signal is triggered, a function is executed. For example, if your avatar changes when collisions are enabled or disabled, you can connect a function to react to this specific event such as: + +.. code-block:: javascript + + function collisionChanged(enabled) { + if(enabled) { + console.log("avatar collision is enabled"); + } else { + console.log("avatar collision is disabled") + } + } + + MyAvatar.collisionsEnabledChanged.connect(collisionChanged); + +Each signal usually gets passed in arguments, and you can refer to the `API documentation `_ to see what a signal will provide you, such as the enabled property passed into collision changed. + +It's good practice to disconnect from signals, but you can only do that if you name your function: + +.. code-block:: javascript + + MyAvatar.collsionEnabledChanged.disconnect(collsionChanged); + + +**See Also** + +- :doc:`Write Your Own Scripts ` +- `API Reference `_ diff --git a/source/script/midi-tutorial.rst b/source/script/midi-tutorial.rst index bd7c9b10..e49aea4d 100755 --- a/source/script/midi-tutorial.rst +++ b/source/script/midi-tutorial.rst @@ -2,7 +2,7 @@ Tutorial: Use MIDI to Control Your Environment ################################################### -MIDI (Musical Instrument Digital Interface) is a protocol (with electrical connectors and a digital interface) that allows digital tools and electronic devices (virtual and physical) to communicate with each other. MIDI is usually used as a music sequencer. Originally, this format was created in the 80s as a way for instruments to communicate with each other, but over the last 30 years, it has evolved into a highly organized specification that is heavily tested and adopted for a multitude of purposes. +MIDI (Musical Instrument Digital Interface) is a protocol (with electrical connectors and a digital interface) that allows digital tools and electronic devices (virtual and physical) to communicate with each other. MIDI is usually used as a music sequencer. Originally, this format was created in the 80s as a way for instruments to communicate with each other, but since then, it has evolved into a highly organized specification that is heavily tested and adopted for a multitude of purposes. We created a MIDI class (with the help of one of our community members, Brainstormer) that can be used to control your environment in Overte. For example, we used MIDI to control lighting in a domain for a music show. diff --git a/source/script/server-entity-scripts.md b/source/script/server-entity-scripts.md deleted file mode 100755 index cb9f84bd..00000000 --- a/source/script/server-entity-scripts.md +++ /dev/null @@ -1,61 +0,0 @@ -# Server Entity Scripts - -You can make content in Overte interactive by attaching scripts to entities. *Server entity scripts* are entity scripts that run on the server (or domain) that hosts the entity. These scripts run persistently in a domain, even if there are no users present. This means that there is only one instance of the script is running at a time, and it is running on the server. Any behavior that is controlled by your script will be seen and heard by everyone in the domain. - -**On This Page** -* [Attach a Server Entity Script to an Entity](#attach-a-server-entity-script-to-an-entity) -* [Example of a Server Entity Script](#example-of-a-server-entity-script) -* [Script API](#script-api) - -## Attach a Server Entity Script to an Entity -To attach a server entity script to an entity: -1. In Interface, pull up your tablet or HUD and go to **Create**. -2. Select the entity you'd like to script by either clicking on it in Interface or finding it in the 'Entity List'. -3. In the **Create** app, go to the 'Properties' tab and scroll down to the 'Behavior' section. -4. For 'Server Script', enter the URL to your server entity script. - -
-

Note

-

An entity can have multiple server entity scripts attached to it, but all of these must be through a single file URL.

-
- -## Example of a Server Entity Script -The following script modifies the intensity of a light entity, so that it flickers tea lights. - -```javascript -(function() { - var MINIMUM_LIGHT_INTENSITY = 100.0; - var MAXIMUM_LIGHT_INTENSITY = 125.0; - - // Return a random number between `low` (inclusive) and `high` (exclusive) - function randFloat(low, high) { - return low + Math.random() * (high - low); - } - - var self = this; - this.preload = function(entityID) { - self.intervalID = Script.setInterval(function() { - Entities.editEntity(entityID, { - intensity: randFloat(MINIMUM_LIGHT_INTENSITY, MAXIMUM_LIGHT_INTENSITY) - }); - }, 100); - }; - this.unload = function() { - Script.clearInterval(self.intervalID); - } -}); - -``` -This script is a good example of a server entity script because it only needs one actor to update the intensity of the light. The same script could be attached as an entity client script, but all clients who could see the tea light would be editing the entity to vary the intensity of the light to flicker it. - -## Script API - -The Entity Script Server does not have access to all of the listed components of the API. APIs for avatars, controllers, recording, overlays, and mouse and keyboard events are not available in the Entity Script Server. - -Learn more about what APIs are available to server entity scripts [here](https://apidocs.overte.org/Entities.html). - -**See Also** - -- [Get Started with Scripting](get-started-with-scripting) -- [Write Your Own Scripts](write-scripts) -- [API Reference](https://apidocs.overte.org) diff --git a/source/script/server-entity-scripts.rst b/source/script/server-entity-scripts.rst new file mode 100755 index 00000000..d59bf7b6 --- /dev/null +++ b/source/script/server-entity-scripts.rst @@ -0,0 +1,84 @@ +##################### +Server Entity Scripts +##################### + +You can make content in Overte interactive by attaching scripts to entities. *Server entity scripts* are entity scripts that run on the server (or domain) that hosts the entity. These scripts run persistently in a domain, even if there are no users present. This means that there is only one instance of the script running at a time, and it is running on the server. Any behavior that is controlled by your script will be seen or heard by everyone in the domain. + +.. contents:: On This Page + :depth: 2 + +------------------------------------------ +Attach a Server Entity Script to an Entity +------------------------------------------ + +To attach a server entity script to an entity: + +1. In Interface, pull up your tablet or HUD and go to **Create**. +2. Select the entity you'd like to script by either clicking on it in Interface or finding it in the 'Entity List'. +3. In the **Create** app, go to the 'Properties' tab and select the Scripts icon. |scripts-icon| +4. For 'Server Script', enter the URL to your server entity script. + +.. note:: An entity can have multiple server entity scripts attached to it, but all of these must be through a single file URL. + +.. |scripts-icon| image:: _images/create-properties-scripts-icon.png + :height: 4ex + :class: no-scaled-link inline + :alt: paper and quill icon + +--------------------------------- +Example of a Server Entity Script +--------------------------------- + +The following script modifies the intensity of a light entity, so that it flickers tea lights. + +.. code-block:: javascript + + (function() { + "use strict" + const MINIMUM_LIGHT_INTENSITY = 100.0; + const MAXIMUM_LIGHT_INTENSITY = 125.0; + + // Return a random number between `low` (inclusive) and `high` (exclusive) + function randFloat(low, high) { + return low + Math.random() * (high - low); + } + + const self = this; + this.preload = function(entityID) { + self.intervalID = Script.setInterval(function() { + Entities.editEntity(entityID, { + intensity: randFloat(MINIMUM_LIGHT_INTENSITY, MAXIMUM_LIGHT_INTENSITY) + }); + }, 100); + }; + this.unload = function() { + Script.clearInterval(self.intervalID); + } + }); + +This script is a good example of a server entity script because it only needs one actor to update the intensity of the light. The same script could be attached as an entity client script, but all clients who could see the tea light would be editing the entity to vary the intensity of the light to flicker it. + +.. note:: + In the above example we include ``"use strict"`` on the first line of the server entity script to enable `strict mode `_ . This must be inside the class prototype function, not the first line of the file as in other scripts. + +---------- +Script API +---------- + +The Entity Script Server does not have access to all of the listed components of the API. APIs for avatars, controllers, recording, overlays, and mouse and keyboard events are not available in the Entity Script Server. + +Learn more about what APIs are available to server entity scripts `here `_. + +.. _server entity script log: + +------------------------ +Entity Script Server Log +------------------------ + +The Entity Script Server Log allows you to see the output from entity scripts which are running on the domain server. As these scripts do not interact with your interface client directly, their messages will not show up in your :ref:`debug window` or interface logs. To open the Server Entity Script Log window, go to the 'Developer' menu, then **Scripting > Entity Script Server Log**. If the Developer menu is not visible, first go to the 'Settings' menu and click 'Developer' Menu. + +**See Also** + +- `Get Started with Scripting `_ +- `Write Your Own Scripts `_ +- `API Reference `_ diff --git a/source/script/write-scripts.md b/source/script/write-scripts.md index 490a97de..c2ecdb1d 100755 --- a/source/script/write-scripts.md +++ b/source/script/write-scripts.md @@ -1,12 +1,12 @@ # Write Your Own Scripts -Overte's robust [JavaScript API](https://apidocs.overte.org) provides the tools for you to build great content and user experiences in VR. +Overte's robust [JavaScript API](https://apidocs.overte.org) provides the tools for you to build great content and experiences, whether the user is in VR or on Desktop. In this section, you can find simple code samples to do common tasks in Overte. To see these code samples in action, copy the code to a file, `testScripts.js`, saved somewhere on your computer.

Note

-

Entity scripts, unlike interface scripts, are in containing functions. The example scripts here cannot be attached to an entity (and be used as an entity script) unless they are in a containing function ``function() {}``.

+

Entity scripts, unlike interface scripts, are in containing functions. The example scripts here cannot be attached to an entity (and be used as an entity script) unless they are in a containing function function() {}.

**On This Page:** @@ -16,9 +16,11 @@ In this section, you can find simple code samples to do common tasks in Overte. * [Edit an Entity](#edit-an-entity) ## Write to the Debug Window + This is an example of an [interface script](interface-scripts) and cannot be attached to an entity. It shows you how to print something to the [debug window ](get-started-with-scripting.rst#debug-window). In this example, we'll start with a simple "Hello, World" script. ```javascript +"use strict"; print("Hello, World"); ``` @@ -27,18 +29,20 @@ print("Hello, World"); ![](_images/hello-world.png) ## Create an Entity + Instead of [using the Create app to add an entity](../create/entities/create-entities), you can create one using an [interface script](interface-scripts). ```javascript +"use strict"; // Get your position in the domain, so that the cube is spawned in front of you -var position = Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)); -var properties = { +const position = Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)); +const properties = { type: "Box", name: "ScriptBox", position: position, color: { red: 255, green: 0, blue: 0 } }; -var entityID = Entities.addEntity(properties); +const entityID = Entities.addEntity(properties); print("Entity added"); ``` @@ -47,15 +51,17 @@ print("Entity added"); ![](_images/add-entity.png) ## Edit an Entity + To manipulate an entity's properties, you can use `Entities.editEntity`in an [interface script](interface-scripts). ```javascript -var entityID = Entities.addEntity({ +"use strict"; +const entityID = Entities.addEntity({ type: "Box", position: Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)), }); -var properties = Entities.getEntityProperties(entityID, ["color"]); +let properties = Entities.getEntityProperties(entityID, ["color"]); print("Entity color: " + JSON.stringify(properties.color)); Entities.editEntity(entityID, { @@ -68,7 +74,11 @@ print("Entity color: " + JSON.stringify(properties.color)); 1. Copy and paste this in a file `testScript.js` and save it on your computer. 2. When you [load and run this script](get-started-with-scripting.rst#load-and-run-a-script), it will locate your avatar in the domain, create a new entity based on the customized properties that you set, then print the color of that entity to the 'Debug Window'. Then, the script changes the color of the entity to red, and prints the new color in the 'Debug Window'. ![](_images/edit-entity.png) - + +
+

Note

+

In these examples we include "use strict" on the first line. Please include this at the start of all of your scripts, as it will alert you to mistakes in your code and in some cases make your script run faster. See Strict mode for more information.

+
**See Also**