-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from HakuyaLabs/scripting
Scripting section
- Loading branch information
Showing
64 changed files
with
2,776 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"position": 10, | ||
"label": "Scripting API", | ||
"collapsible": true, | ||
"collapsed": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
--- | ||
sidebar_position: 40 | ||
--- | ||
|
||
# Assets | ||
|
||
Assets are self-contained objects that implement a feature or a behavior in the scene. Different from nodes, an asset usually encapsulates a more complex logic. They can be thought of classes in a program and are more similar to Unity's `MonoBehaviour`. | ||
|
||
## Type Definition | ||
|
||
You can create asset types that can be instantiated and stored in the scene. An asset type inherits from the `Asset` type and is decorated with the `[AssetType]` attribute, like below: | ||
|
||
```csharp | ||
[AssetType( | ||
Id = "c6500f41-45be-4cbe-9a13-37b5ff60d057", | ||
Title = "Hello World", | ||
Category = "CATEGORY_DEBUG", | ||
Singleton = false | ||
)] | ||
public class HelloWorldAsset : Asset { | ||
// Asset implementation | ||
} | ||
``` | ||
|
||
Here's a summary of the parameters: | ||
|
||
- **`Id`**: A unique identifier for the asset type; you should [generate a new GUID](https://www.guidgenerator.com/online-guid-generator.aspx) for each new asset type. Note that this is different from the asset instance's UUID (`asset.Id`). | ||
- **`Title`**: The name of the asset type that will be displayed in the *Add Asset* menu. | ||
- **`Category`**: Optional. The group of the asset in the *Add Asset* menu. | ||
- **`Singleton`**: Optional. If set to `true`, only one instance of the asset can exist in the scene. Default is `false`. | ||
|
||
:::info | ||
Here are some common asset categories you can use: `CATEGORY_INPUT`, `CATEGORY_CHARACTERS`, `CATEGORY_PROP`, `CATEGORY_ACCESSORY`, `CATEGORY_ENVIRONMENT`, `CATEGORY_CINEMATOGRAPHY`, `CATEGORY_EXTERNAL_INTERACTION`, `CATEGORY_MOTION_CAPTURE`. | ||
::: | ||
|
||
## Components | ||
|
||
An asset type can define data inputs and triggers. Unlike nodes, assets do not have data outputs or flow inputs/outputs. | ||
|
||
![](/doc-img/en-scripting-concepts-4.png) | ||
|
||
## Lifecycle | ||
|
||
Assets have the lifecycle stages listed on the [Entities](entities#lifecycle) page. You can override these methods to perform various tasks; for example, `OnUpdate()` is called every frame, similar to Unity's `Update()` method. | ||
|
||
## Active State {#active-state} | ||
|
||
Different from nodes, assets have an active state that inform whether the asset is "active", or ready to use. For example, when a character asset does not have a `Source` selected, it is shown as inactive in the editor. | ||
|
||
![](/doc-img/en-custom-asset-1.png) | ||
|
||
By default, assets are **NOT** active when they are created. You can set the active state of an asset by calling `SetActive(bool state)`. For example, if your asset is always ready to use, you can set it to active in the `OnCreate` method: | ||
|
||
```csharp | ||
public override void OnCreate() { | ||
base.OnCreate(); | ||
SetActive(true); | ||
} | ||
``` | ||
|
||
If your asset only works when connected to an external server, e.g., a remote tracking device, you can set it to active only if the connection is successfully established: | ||
|
||
```csharp | ||
[DataInput] | ||
public string RemoteIP = "127.0.0.1"; | ||
|
||
[DataInput] | ||
public string RemotePort = "12345"; | ||
|
||
public override void OnCreate() { | ||
base.OnCreate(); | ||
WatchAll(new [] { nameof(RemoteIP), nameof(RemotePort) }, ResetConnection); // When RemoteIP or RemotePort changes, reset the connection | ||
} | ||
|
||
protected void ResetConnection() { | ||
SetActive(false); // Inactive until connection is established | ||
if (ConnectToRemoteServer(RemoteIP, RemotePort)) { | ||
SetActive(true); | ||
} | ||
} | ||
``` | ||
|
||
:::tip | ||
Determining whether your asset is "ready to use" is entirely up to you. The convention that Warudo's internal assets use is that an asset is active when all data inputs required for the asset to function properly are set. | ||
::: | ||
|
||
## Creating GameObjects | ||
|
||
You can create GameObjects in the (Unity) scene anytime you want. For example, the following asset creates a cube GameObject when the asset is created, and destroys it when the asset is destroyed: | ||
|
||
```csharp | ||
private GameObject gameObject; | ||
|
||
public override void OnCreate() { | ||
base.OnCreate(); | ||
gameObject = GameObject.CreatePrimitive(PrimitiveType.Cube); | ||
} | ||
|
||
public override void OnDestroy() { | ||
base.OnDestroy(); | ||
Object.Destroy(gameObject); | ||
} | ||
``` | ||
|
||
However, the user cannot move this cube around, since there are no data inputs that control the cube! You can add data inputs to control the cube's position, scale, etc., but an easier way is to inherit from the `GameObjectAsset` type: | ||
|
||
```csharp | ||
using UnityEngine; | ||
using Warudo.Core.Attributes; | ||
using Warudo.Plugins.Core.Assets; | ||
|
||
[AssetType( | ||
Id = "4c00b14a-aed5-423e-abe6-6921032439c5", | ||
Title = "My Awesome Cube", | ||
Category = "CATEGORY_DEBUG" | ||
)] | ||
public class MyAwesomeCubeAsset : GameObjectAsset { | ||
protected override GameObject CreateGameObject() { | ||
return GameObject.CreatePrimitive(PrimitiveType.Cube); | ||
} | ||
} | ||
``` | ||
|
||
The `GameObjectAsset` handles creating and destroying the GameObject for you, and it comes with a `Transform` data input that allows the user to control the GameObject's position, rotation, and scale: | ||
|
||
![](/doc-img/en-custom-asset-2.png) | ||
|
||
:::tip | ||
When to use `GameObjectAsset`? If your asset is "something that can be moved by the user in the (Unity) scene", then it's probably a good idea to inherit from `GameObjectAsset`. | ||
::: | ||
|
||
## Events | ||
|
||
The `Asset` type invokes the following events that you can listen to: | ||
|
||
- **`OnActiveStateChange`**: Called when the active state of the asset changes. | ||
- **`OnSelectedStateChange`**: Called when the asset is selected or deselected in the editor. | ||
- **`OnNameChange`**: Called when the name of the asset changes. | ||
|
||
For example, the built-in [Leap Motion tracking](../../mocap/leap-motion) asset listens to the `OnSelectedStateChange` event to display a Leap Motion controller model in the (Unity) scene when the asset is selected. | ||
|
||
```csharp | ||
public override void OnCreate() { | ||
base.OnCreate(); | ||
OnSelectedStateChange.AddListener(selected => { | ||
if (selected) { | ||
// Show the model | ||
} else { | ||
// Hide the model | ||
} | ||
}); | ||
} | ||
``` | ||
|
||
## Code Examples | ||
|
||
### Basic | ||
|
||
- [AnchorAsset.cs](https://gist.github.com/TigerHix/c549e984df0be34cfd6f8f50e741aab2) | ||
Attachable / GameObjectAsset example. | ||
|
||
### Advanced | ||
|
||
- [CharacterPoserAsset.cs](https://gist.github.com/TigerHix/8413f8e10e508f37bb946d8802ee4e0b) | ||
Custom asset to pose your character with IK anchors. | ||
|
||
<AuthorBar authors={{ | ||
creators: [ | ||
{name: 'HakuyaTira', github: 'TigerHix'}, | ||
], | ||
translators: [ | ||
], | ||
}} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
--- | ||
sidebar_position: 2 | ||
--- | ||
|
||
# Entities | ||
|
||
An entity is an object that is persistent in a [scene](scene) (e.g., nodes, assets) or across scenes (e.g., plugins). Scripting in Warudo is all about defining your own entity types and interacting with the Warudo runtime. You can define your own entity type by inheriting a base class provided by Warudo: | ||
|
||
- **Node:** Inherit from `Node` to create a new node type. A node type can define data inputs, data outputs, flow inputs, flow outputs, and triggers. A node is instantiated by dragging it from the node palette to the blueprint editor; the node instance is saved along with the blueprint. | ||
- **Asset:** Inherit from `Asset` to create a new asset type. An asset type can define data inputs and triggers. An asset is instantiated by using the *Add Asset* menu; the asset instance is saved along with the scene. | ||
- **Plugin:** Inherit from `Plugin` to create a new plugin type. A plugin type can define data inputs and triggers. A plugin is loaded when Warudo starts, or when the plugin is hot-reloaded. There is only one plugin instance per plugin type, and data inputs are saved across scenes. | ||
- **Structured Data:** Inherit from `StructuredData` to create a new [structured data](structured-data) type. Structured data is a complex data type that can be used as an "embedded" data input in nodes, assets, or plugins. | ||
|
||
:::info | ||
In the [Creating Your First Script](../creating-your-first-script.md) tutorial, we created a custom node type called `HelloWorldNode` and a custom asset type called `CookieClickerAsset`. | ||
::: | ||
|
||
:::tip | ||
The concept of entities is loosely similar to Unity's MonoBehaviour, but with a more structured approach. | ||
::: | ||
|
||
After an entity is instantiated, it is automatically assigned a UUID (unique identifier) by Warudo. You can access it via the `Id` property. This UUID is then used to identify the entity in the scene, and is saved along with the scene. | ||
|
||
An entity type can contain regular C# fields and methods. However, to interface with the Warudo runtime, you need to create [**ports and triggers**](ports-and-triggers) in the entity. All entities can have [data input ports](ports-and-triggers#data-input-ports), [data output ports](ports-and-triggers#data-output-ports) and [triggers](ports-and-triggers#triggers), while nodes can additionally have [data output ports](ports-and-triggers#data-output-ports), [flow input ports](ports-and-triggers#flow-input-ports), and [flow output ports](ports-and-triggers#flow-output-ports). | ||
|
||
![](/doc-img/en-custom-node-1.png) | ||
|
||
![](/doc-img/en-scripting-concepts-4.png) | ||
|
||
## Lifecycle {#lifecycle} | ||
|
||
An entity has a lifecycle that consists of several stages: | ||
|
||
- **`OnCreate()`:** Called when the entity is created. This is where you should initialize the instance fields, subscribe to events, etc. | ||
- **Assets:** Called when a new asset is added to the scene by the user, or when the scene is loaded. | ||
- **Nodes:** Called when a new node is added to the blueprint by the user, or when the scene is loaded. Nodes are always created _after_ assets. | ||
- **Plugins:** Called when the plugin is loaded by Warudo on startup, or when the plugin is hot-reloaded. | ||
- **Structured Data:** Called when the parent entity is created, or when the user adds a new structured data to an array of structured data. | ||
- **`OnDestroy()`:** Called when the entity is destroyed. This is where you should release resources, etc. | ||
- **Assets:** Called when the asset is removed from the scene by the user, or when the scene is unloaded. | ||
- **Nodes:** Called when the node is removed from the blueprint by the user, or when the scene is unloaded. Nodes are always destroyed _after_ assets. | ||
- **`Deserialize(TSerialized data)`:** Called when the entity is deserialized from a saved state. For example, this method is called on an asset when the scene is just opened and loaded. _You usually do not need to override this method._ | ||
- **`Serialize()`:** Called when the entity needs to be serialized to a saved state. For example, this method is called on an asset when the scene is about to be saved, or need to be sent to the editor. _You usually do not need to override this method._ | ||
|
||
Assets, nodes, and plugins have extra lifecycle stages: | ||
|
||
- **`OnUpdate()`:** Called every frame when the entity is not destroyed. This is similar to Unity's `Update()` method. | ||
- `OnPreUpdate()` and `OnPostUpdate()` are also provided. They are called before and after `OnUpdate()`, respectively. | ||
- **`OnLateUpdate()`:** Called every frame after `OnUpdate()`. This is similar to Unity's `LateUpdate()` method. | ||
- **`OnFixedUpdate()`:** Called every fixed frame. This is similar to Unity's `FixedUpdate()` method. | ||
- **`OnEndOfFrame()`:** Called at the end of the frame. This is similar to using Unity's [`WaitForEndOfFrame` coroutine](https://docs.unity3d.com/ScriptReference/WaitForEndOfFrame.html). | ||
- **`OnDrawGizmos()`:** Called when the entity should draw gizmos. This is similar to Unity's `OnDrawGizmos()` method. | ||
|
||
:::info | ||
The update order is as follows: plugins → assets → nodes. | ||
::: | ||
|
||
<AuthorBar authors={{ | ||
creators: [ | ||
{name: 'HakuyaTira', github: 'TigerHix'}, | ||
], | ||
translators: [ | ||
], | ||
}} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
sidebar_position: 90 | ||
--- | ||
|
||
# Global Events {#events} | ||
|
||
Warudo contains a `EventBus` class that allows you to subscribe to and broadcast global events. To define a custom event class, inherit from the `Warudo.Core.Events.Event` class. For example: | ||
|
||
```csharp | ||
public class MyEvent : Event { | ||
public string Message { get; } | ||
public MyEvent(string message) { | ||
Message = message; | ||
} | ||
} | ||
``` | ||
|
||
To subscribe (listen) to an event: | ||
|
||
```csharp | ||
Context.EventBus.Subscribe<MyEvent>(e => { | ||
Debug.Log(e.Message); | ||
}); | ||
``` | ||
|
||
To broadcast (fire) an event: | ||
|
||
```csharp | ||
Context.EventBus.Broadcast(new MyEvent("Hello, world!")); | ||
``` | ||
|
||
You should unsubscribe from events when you no longer need to listen to them: | ||
|
||
```csharp | ||
var subscriptionId = Context.EventBus.Subscribe<MyEvent>(e => { | ||
Debug.Log(e.Message); | ||
}); | ||
// Later | ||
Context.EventBus.Unsubscribe<MyEvent>(subscriptionId); | ||
``` | ||
|
||
### Subscribing Events In Entities | ||
|
||
If you are writing code inside an entity type, you can use the `Subscribe` method directly to avoid handling event subscription IDs: | ||
|
||
```csharp | ||
// Inside an entity type, i.e., asset, node, plugin, structured data | ||
Subscribe<MyEvent>(e => { | ||
Debug.Log(e.Message); | ||
}); | ||
``` | ||
|
||
The events are automatically unsubscribed when the entity is destroyed. | ||
|
||
<AuthorBar authors={{ | ||
creators: [ | ||
{name: 'HakuyaTira', github: 'TigerHix'}, | ||
], | ||
translators: [ | ||
], | ||
}} /> |
Oops, something went wrong.