Dynamic Variables/ru: Difference between revisions

From Resonite Wiki
Created page with "Динамические переменные"
 
Updating to match new version of source page
Line 1: Line 1:
<languages/>
<languages/>
{{stub}}


== Обзор ==
== Обзор ==


<span lang="en" dir="ltr" class="mw-content-ltr">'''Dynamic variables''' allow you to read and write data by name. This makes it easy to manage data in large systems; every bit of data is clearly labeled, and you can break data into multiple '''spaces''' to keep your systems separate.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">'''Dynamic variables''' allow you to read and write data by name in the context of a [[Slot|Slot]] hierarchy. This makes it easy to manage data in large systems; every bit of data is clearly labeled, and you can break data into multiple '''spaces''' to keep your systems separate.</span>


== <span lang="en" dir="ltr" class="mw-content-ltr">Naming Restrictions</span> ==
== <span lang="en" dir="ltr" class="mw-content-ltr">Naming Restrictions</span> ==
Line 16: Line 14:
** <span lang="en" dir="ltr" class="mw-content-ltr">As defined in C# [https://docs.microsoft.com/en-us/dotnet/api/system.char.ispunctuation?view=net-5.0 Char.IsPunctuation] and C# [https://docs.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=net-5.0 Char.IsWhiteSpace]</span>
** <span lang="en" dir="ltr" class="mw-content-ltr">As defined in C# [https://docs.microsoft.com/en-us/dotnet/api/system.char.ispunctuation?view=net-5.0 Char.IsPunctuation] and C# [https://docs.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=net-5.0 Char.IsWhiteSpace]</span>
* <span lang="en" dir="ltr" class="mw-content-ltr">'''Except''' for period (.), underscore (_) and space ( ).</span>
* <span lang="en" dir="ltr" class="mw-content-ltr">'''Except''' for period (.), underscore (_) and space ( ).</span>
<div lang="en" dir="ltr" class="mw-content-ltr">
{{Note|Which concept or properties do your spaces and variables represent? Take your time to name them appropriately!<br/> Those names will be used in different places or even by multiple users. Changing them after the fact can become quite challenging. |suggestion}}
</div>


== <span lang="en" dir="ltr" class="mw-content-ltr">Usage</span> ==
== <span lang="en" dir="ltr" class="mw-content-ltr">Usage</span> ==
Line 35: Line 37:
=== <span lang="en" dir="ltr" class="mw-content-ltr">Variables</span> ===
=== <span lang="en" dir="ltr" class="mw-content-ltr">Variables</span> ===


<span lang="en" dir="ltr" class="mw-content-ltr">The simplest way to use dynamic variables is to use the [[DynamicValueVariable%601_(Component)|DynamicValueVariable<T>]] and [[DynamicReferenceVariable%601_(Component)|DynamicReferenceVariable<T>]] components. These are for value (int, float, String, etc.) and reference (Slot, User, etc.) types, respectively.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">The simplest way to use dynamic variables is to use the [[Component:DynamicValueVariable|DynamicValueVariable<T>]] and [[Component:DynamicReferenceVariable|DynamicReferenceVariable<T>]] components. These are for value (int, float, String, etc.) and reference (Slot, User, etc.) types, respectively. [[Component:DynamicTypeVariable|DynamicTypeVariable]] exists to store [[Type:Type|Types]].</span>
   
   
<span lang="en" dir="ltr" class="mw-content-ltr">These components store a value or reference directly. If two variable components have the same name, then they will have identical contents.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">These components store a value or reference directly. If two variable components have the same name, then they will have identical contents.</span>
Line 41: Line 43:
=== <span lang="en" dir="ltr" class="mw-content-ltr">Fields</span> ===
=== <span lang="en" dir="ltr" class="mw-content-ltr">Fields</span> ===


<span lang="en" dir="ltr" class="mw-content-ltr">If you want to use an existing field or reference as the contents of a dynamic variable, you can use the [[DynamicField%601_(Component)|DynamicField<T>]] or [[DynamicReference%601_(Component)|DynamicReference<T>]] components. Instead of storing something directly, they point at a field that contains a value or reference type, respectively.</span>
<div lang="en" dir="ltr" class="mw-content-ltr">
If you want to use an existing field or reference as the contents of a dynamic variable, you can use the [[Component:DynamicField|DynamicField<T>]] or [[Component:DynamicReference|DynamicReference<T>]] components. Instead of storing something directly, they point at a field that contains a value or reference type, respectively.
</div>
 
<div lang="en" dir="ltr" class="mw-content-ltr">
As with variables there is a variant for <code>Type</code> fields: [[Component:DynamicTypeField|DynamicTypeField]]
</div>


<span lang="en" dir="ltr" class="mw-content-ltr">(TODO: clarify value vs. reference types; I think this isn't fully correct)</span>
<span lang="en" dir="ltr" class="mw-content-ltr">(TODO: clarify value vs. reference types; I think this isn't fully correct)</span>
Line 47: Line 55:
=== <span lang="en" dir="ltr" class="mw-content-ltr">Drivers</span> ===
=== <span lang="en" dir="ltr" class="mw-content-ltr">Drivers</span> ===


<span lang="en" dir="ltr" class="mw-content-ltr">You can use the contents of a dynamic variable to drive a field or reference, using the [[DynamicValueVariableDriver%601_(Component)|DynamicValueVariableDriver<T>]] and [[DynamicReferenceVariableDriver%601_(Component)|DynamicReferenceVariableDriver<T>]] components.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">You can use the contents of a dynamic variable to drive a field or reference, using the [[Component:DynamicValueVariableDriver|DynamicValueVariableDriver<T>]] and [[Component:DynamicReferenceVariableDriver|DynamicReferenceVariableDriver<T>]] components.</span>


=== <span lang="en" dir="ltr" class="mw-content-ltr">Unlisted types</span> ===
=== <span lang="en" dir="ltr" class="mw-content-ltr">Unlisted types</span> ===


<span lang="en" dir="ltr" class="mw-content-ltr">When creating a dynamic variable component, you will be given a list of "common types". If the type you seek is not in that list, you will have to enter it by hand. See [[Complex Types in Components]].</span>
<span lang="en" dir="ltr" class="mw-content-ltr">When creating a dynamic variable component, you will be given a list of "common types". If the type you seek is not in that list, you will have to enter it by hand. See [[Complex Types in Components]].</span>
===  <span lang="en" dir="ltr" class="mw-content-ltr">Binding</span> ===
<div lang="en" dir="ltr" class="mw-content-ltr">
Creating, duplicating, or moving a dynamic variable requires '''binding''' that variable to a space.
This is a process that happens automatically but isn't perfect yet. (see [[#Warning|Warning]])
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
In essence it starts searching for a matching dynamic variable space at the slot of the dynamic variable.
If there is no match, it tries the parent slot, its parent etc. until a matching space is found.
Variables with explicitly given space names only match spaces with the same name.
Variables without explicit space name match all spaces that are not <code>OnlyDirectBinding</code>
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
The following image will demonstrate the differences in binding:
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
[[File:Dynamic_Variables.svg|border|an image demonstrating that dynamic variable spaces with enabled OnlyDirectBinding are ignored except by variables which have explicitly declared the same space name]]
* I: <code>A</code> is connected to <code>Inner</code> because <code>Inner</code> is <u>not</u> <code>OnlyDirectBinding</code>.
* II/III: Both variables are bound explicitly.
* IV: <code>A</code> ignores <code>Inner</code> because <code>Inner</code> is <code>OnlyDirectBinding</code>.
* V/VI: Both variables are bound explicitly.
* VII/IX: There is no matching dynamic variable space. Both variables are not bound.
* VIII: The variable is explicitly bound to <code>World</code>.
* I and II share the same value.
* III, IV and VI share the same value.
</div>
{{#mermaid:flowchart BT
    subgraph outside
       
        InvalidSpace["Invalid, not linked"]
        RootSlot
    end
    subgraph RootSlot [RootSlot]
        World["Space #34;World#34;"]
        color["World/Color1"] --> World
       
       
        UserRootSlot
       
    end
    subgraph UserRootSlot
        UserSpace["Space #34;User#34;"]
        AvatarRootSlot
        V["User/Voice"] --> UserSpace
        V2["User/Color"] --> UserSpace
    end
   
    subgraph AvatarRootSlot
        avatar["User/Avatar"]
        avatarworld["World/Avatar.U-myid"]
        hips["HipsSlot"] --> AvatarSpace
        invalid["None/float"]
       
        AvatarSpace["Space #34;Avatar#34;"]
       
        Flux2_node0(["DynamicVariableInput#60;ColorX#62;#12;#34;World/Color1#34;"])
        Flux2_node0 -. points to .-> color
    end
   
   
    avatarworld --> World
    avatar --> UserSpace
    subgraph Flux1
        Flux1_node0(["User Root Slot"]) -. automatically points to .-> UserRootSlot
        Flux1_node1(["Read #34;User/Avatar#34;"]) --> Flux1_node0
        Flux1_node1 -. points to .-> AvatarRootSlot
        Flux1_node2(["Read Variable #34;Avatar/Hips#34;"]) --> Flux1_node1
        Flux1_node2 -. points to .-> hips
    end
    invalid --> InvalidSpace
   
   
   
   
}}


=== <span lang="en" dir="ltr" class="mw-content-ltr">Warning</span> ===
=== <span lang="en" dir="ltr" class="mw-content-ltr">Warning</span> ===


<span lang="en" dir="ltr" class="mw-content-ltr">Creating, duplicating, or moving a dynamic variable requires '''binding''' that variable to its space. This usually takes a small amount of time, before which the dynamic variable can appear to be present, but not be readable or writable. Therefore, if you create a dynamic variable using the [[Create Dynamic Variable`1 (ProtoFlux)|Create Dynamic Variable]] or [[Write Or Create Dynamic Variable`1 (ProtoFlux)|Write Or Create Dynamic Variable]] ProtoFlux Node, or cause it to be duplicated using the [[Duplicate Slot (ProtoFlux)|Duplicate Slot]] ProtoFlux Node, or cause it to be moved using the [[Set Parent (ProtoFlux)|Set Parent]] ProtoFlux Node, you may find it necessary to add an [[Updates Delay (ProtoFlux)|Updates Delay]] or [[Updates Delay With Value (ProtoFlux)|Updates Delay With Value]] ProtoFlux Node afterwards in order to ensure the dynamic variables have been bound by the time you use them. A delay of 1 to 3 updates usually suffices.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">In a few use-cases binding may take a small amount of time, before which the dynamic variable can appear to be present, but not be readable or writable. Therefore, if you create a dynamic variable using the [[ProtoFlux:Create Dynamic Variable|Create Dynamic Variable]] or [[ProtoFlux:Write Or Create Dynamic Variable|Write Or Create Dynamic Variable]] ProtoFlux Node, or cause it to be duplicated using the [[ProtoFlux:Duplicate Slot |Duplicate Slot]] ProtoFlux Node, or cause it to be moved using the [[ProtoFlux:Set Parent|Set Parent]] ProtoFlux Node, you may find it necessary to add an [[ProtoFlux:Updates Delay|Updates Delay]] or [[ProtoFlux:Updates Delay With Value|Updates Delay With Value]] ProtoFlux Node afterwards in order to ensure the dynamic variables have been bound by the time you use them. A delay of 1 to 3 updates usually suffices.</span>
 
TODO: more precise list of problematic uses cases (e.g. <code>Duplicate Slot</code> of a whole space works totally fine.)
 
==  <span lang="en" dir="ltr" class="mw-content-ltr">Example Applications</span> ==
 
The following examples will demonstrate a few use-cases of dynamic variables.
There is a focus on how to use them to create separate objects
 
===  <span lang="en" dir="ltr" class="mw-content-ltr">Modules within an object</span>  ===
 
<div lang="en" dir="ltr" class="mw-content-ltr">
Dynamic variables within an object allow modularization.
Different modules would be connected via dynamic variables within the space located at the root of the object.
If all hard-coded references going in or out of a module are eliminated you can replace it with a different variant/version without additional setup.
Module-local variables can be created with a dynamic variable space located at the root of the module. Use appropriately named spaces to differentiate between the two.
To make available variables more obvious to other people - including you in 6 months - it is recommended to place all dynamic variables within a dedicated slot hierarchy.
</div>
 
<div lang="en" dir="ltr" class="mw-content-ltr">
Commonly used names for such hierarchies are:
* DV
* DynVar
* Vars
* etc.
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
A modular object could look like this:
* Project (Space: <code>MyProject</code>)
** Dynamic Variables
*** projectVar: String (Dynamic variable <code>projectVar</code> of type [[Type:String|String]])
** Module: UI (i.e. [[Component:MeshRenderer|MeshRenderer]] or [[Component:Canvas|Canvas]] plus [[Collider|Colliders]]), may contain:
*** Dynamic Variable Drivers → Visuals
*** [[:Category:Components:Common_UI:Button_Interactions|Button Interactions]] → Dynamic Variables
*** [[:Category:Components:Common_UI:Editors|Editors]] ↔ Dynamic Variables
** Module: Logic (Space: <code>Logic</code>)
*** Dynamic Variables
**** logicVar: int (Dynamic variable <code>logicVar</code> of type [[Type:Int|int]])
**** MyProject/Logic: Slot (Dynamic variable <code>Logic</code> of type [[Slot]] for space <code>MyProject</code>, driven with reference to Slot of module to make it accessible to other modules)
*** [[ProtoFlux]] (may read, write or even drive dynamic variables of space <code>MyProject</code>)
</div>
 
===  <span lang="en" dir="ltr" class="mw-content-ltr">Configurable objects</span>  ===
<div lang="en" dir="ltr" class="mw-content-ltr">
Dynamic variables make it possible to access other object's properties.
</div>
 
<div lang="en" dir="ltr" class="mw-content-ltr">
Assuming objects with a dynamic variable space, a collider and a string variable named <code>Description</code> you could then create a separate tool that reads and displays the <code>Description</code> of the object it is pointed at. The same tool could be extended to edit descriptions.
</div>
 
<div lang="en" dir="ltr" class="mw-content-ltr">
The same concept can also be applied to template slots used within a project.
Their instances can be interacted with using dynamic variables.
</div>
===  <span lang="en" dir="ltr" class="mw-content-ltr">World/User variables</span>  ===
<div lang="en" dir="ltr" class="mw-content-ltr">
There are already pre-made dynamic variable spaces:
* <code>World</code> on [[Root]] (<code>OnlyDirectBinding</code>)
* <code>User</code> on each [[Component:UserRoot|User Root]] Slot (<code>OnlyDirectBinding</code>)
* <code>Dash</code> on Slot of [[Component:UserspaceRadiantDash|UserSpaceRadiantDash]]
They can be used for states that are shared by many objects (i.e. day/night toggle, performance) or to broadcast information into the world. ([[BeatLink]], library objects like the [[Redprint]] manager)
</div>
 
<div lang="en" dir="ltr" class="mw-content-ltr">
See [[Dynamic Variable Naming Standard]] for a more detailed listing.
</div>

Revision as of 18:30, 24 April 2024

Обзор

Dynamic variables allow you to read and write data by name in the context of a Slot hierarchy. This makes it easy to manage data in large systems; every bit of data is clearly labeled, and you can break data into multiple spaces to keep your systems separate.

Naming Restrictions

When using Dynamic Variables there are some restrictions and limitations on naming both spaces and variables within those spaces.

Space and Variable Names cannot contain:

Which concept or properties do your spaces and variables represent? Take your time to name them appropriately!
Those names will be used in different places or even by multiple users. Changing them after the fact can become quite challenging.

Usage

Optionally, the name can be prefixed by the name of a space, terminated by a /, to choose a specific variable space to use. This is useful to distinguish between unrelated systems that all use dynamic variables.

Some valid names include:

  • Health -- no space defined, named Health
  • World/Color -- named Color, in the World space
  • MyCoolSystem/Score -- named Score, in the MyCoolSystem space

Spaces

Dynamic variables can live anywhere in or under the slot containing a DynamicVariableSpace component.

So, a variable space on the world root can be used from anywhere, whilst a variable space on your avatar can be used from anything stored in your avatar.

Variables

The simplest way to use dynamic variables is to use the DynamicValueVariable<T> and DynamicReferenceVariable<T> components. These are for value (int, float, String, etc.) and reference (Slot, User, etc.) types, respectively. DynamicTypeVariable exists to store Types.

These components store a value or reference directly. If two variable components have the same name, then they will have identical contents.

Fields

If you want to use an existing field or reference as the contents of a dynamic variable, you can use the DynamicField<T> or DynamicReference<T> components. Instead of storing something directly, they point at a field that contains a value or reference type, respectively.

As with variables there is a variant for Type fields: DynamicTypeField

(TODO: clarify value vs. reference types; I think this isn't fully correct)

Drivers

You can use the contents of a dynamic variable to drive a field or reference, using the DynamicValueVariableDriver<T> and DynamicReferenceVariableDriver<T> components.

Unlisted types

When creating a dynamic variable component, you will be given a list of "common types". If the type you seek is not in that list, you will have to enter it by hand. See Complex Types in Components.

Binding

Creating, duplicating, or moving a dynamic variable requires binding that variable to a space. This is a process that happens automatically but isn't perfect yet. (see Warning)

In essence it starts searching for a matching dynamic variable space at the slot of the dynamic variable. If there is no match, it tries the parent slot, its parent etc. until a matching space is found. Variables with explicitly given space names only match spaces with the same name. Variables without explicit space name match all spaces that are not OnlyDirectBinding

The following image will demonstrate the differences in binding:

an image demonstrating that dynamic variable spaces with enabled OnlyDirectBinding are ignored except by variables which have explicitly declared the same space name

  • I: A is connected to Inner because Inner is not OnlyDirectBinding.
  • II/III: Both variables are bound explicitly.
  • IV: A ignores Inner because Inner is OnlyDirectBinding.
  • V/VI: Both variables are bound explicitly.
  • VII/IX: There is no matching dynamic variable space. Both variables are not bound.
  • VIII: The variable is explicitly bound to World.
  • I and II share the same value.
  • III, IV and VI share the same value.


Warning

In a few use-cases binding may take a small amount of time, before which the dynamic variable can appear to be present, but not be readable or writable. Therefore, if you create a dynamic variable using the Create Dynamic Variable or Write Or Create Dynamic Variable ProtoFlux Node, or cause it to be duplicated using the Duplicate Slot ProtoFlux Node, or cause it to be moved using the Set Parent ProtoFlux Node, you may find it necessary to add an Updates Delay or Updates Delay With Value ProtoFlux Node afterwards in order to ensure the dynamic variables have been bound by the time you use them. A delay of 1 to 3 updates usually suffices.

TODO: more precise list of problematic uses cases (e.g. Duplicate Slot of a whole space works totally fine.)

Example Applications

The following examples will demonstrate a few use-cases of dynamic variables. There is a focus on how to use them to create separate objects

Modules within an object

Dynamic variables within an object allow modularization. Different modules would be connected via dynamic variables within the space located at the root of the object. If all hard-coded references going in or out of a module are eliminated you can replace it with a different variant/version without additional setup. Module-local variables can be created with a dynamic variable space located at the root of the module. Use appropriately named spaces to differentiate between the two. To make available variables more obvious to other people - including you in 6 months - it is recommended to place all dynamic variables within a dedicated slot hierarchy.

Commonly used names for such hierarchies are:

  • DV
  • DynVar
  • Vars
  • etc.

A modular object could look like this:

  • Project (Space: MyProject)
    • Dynamic Variables
      • projectVar: String (Dynamic variable projectVar of type String)
    • Module: UI (i.e. MeshRenderer or Canvas plus Colliders), may contain:
    • Module: Logic (Space: Logic)
      • Dynamic Variables
        • logicVar: int (Dynamic variable logicVar of type int)
        • MyProject/Logic: Slot (Dynamic variable Logic of type Slot for space MyProject, driven with reference to Slot of module to make it accessible to other modules)
      • ProtoFlux (may read, write or even drive dynamic variables of space MyProject)

Configurable objects

Dynamic variables make it possible to access other object's properties.

Assuming objects with a dynamic variable space, a collider and a string variable named Description you could then create a separate tool that reads and displays the Description of the object it is pointed at. The same tool could be extended to edit descriptions.

The same concept can also be applied to template slots used within a project. Their instances can be interacted with using dynamic variables.

World/User variables

There are already pre-made dynamic variable spaces:

They can be used for states that are shared by many objects (i.e. day/night toggle, performance) or to broadcast information into the world. (BeatLink, library objects like the Redprint manager)

See Dynamic Variable Naming Standard for a more detailed listing.