User:Yosh/sandbox: Difference between revisions

From Resonite Wiki
asdasdasd
wow this is SO much better
Line 1: Line 1:
'''Dynamic variables''', commonly shorted to '''dyn vars''' or '''dynvars''', is a system of data storage wherein one can store arbitrary, scoped data under slot heirarchies with arbitrary names, akin to that of an [https://en.wikipedia.org/wiki/Associative_array associative array]. Their usage is usually found in large systems with many moving parts, but can nonetheless be useful as easy "global" values that can be changed on an object.
'''Dynamic variables''', commonly shorted to '''dyn vars''' or '''dynvars''', is a system of data storage wherein one can store arbitrary, scoped data under slot hierarchies with arbitrary names, akin to that of an [https://en.wikipedia.org/wiki/Associative_array associative array]. Their usage is usually found in large systems with many moving parts, but can nonetheless be useful as easy "global" values that can be changed on an object.


For a quick-start guide on using dynamic variables, the [[How To Use Dynamic Variables]] page serves as a straightforward guide.
For a quick-start guide on using dynamic variables, the [[How To Use Dynamic Variables]] page serves to be a how-to.


== Usage ==
== Overview ==
Dynamic variables as a whole are managed with two parts: ''dynamic variable spaces'' and ''dynamic variables''. The [[Component:DynamicVariableSpace|DynamicVariableSpace]] component defines a dynamic variable space on a slot and its children, while any one of the [[Component:DynamicValueVariable|DynamicValueVariable]], [[Component:DynamicReferenceVariable|DynamicReferenceVariable]], [[Component:DynamicTypeVariable|DynamicTypeVariable]] components define a dynamic variable. Dynamic variable spaces and names must not contain symbols, punctuation, or whitespace, <em>except</em> for period (<code>.</code>), underscore (<code>_</code>), and space (<code> </code>). To check if a character is unable to be used in a dynamic variable name, one can use the [[ProtoFlux:Is Symbol|Is Symbol]], [[ProtoFlux:Is Punctuation|Is Punctuation]], and [[ProtoFlux:Is White Space|Is White Space]] ProtoFlux nodes, taking care of the three exceptions above.
Dynamic variables are managed with two parts: ''dynamic variable spaces'' and ''dynamic variables''. Dynamic variables live under a dynamic variable space, and can be created, modified, and destroyed dynamically.


The process of a dynamic variable being associated with a given space is called ''binding''. The <code>VariableName</code> of a dynamic variable component can be one of the following two forms: <code>VariableName</code> or <code>VariableSpaceName/VariableName</code>. The former represents ''indirect binding'', while the latter represents ''direct binding''. A dynamic variable component will traverse up the slot heirarchy, including its current slot, looking for an applicable variable space to bind to. If a dynamic variable is indirectly binding, it will bind to the first dynamic variable space that does not have <code>OnlyDirectBinding</code> set to <code>True</code>. If a dynamic variable is directly binding, it will bind to the first dynamic variable space that matches its name. If a dynamic variable does not find a dynamic variable space that it can bind to, it will not be accessible outside of the component itself, essentially reducing to a glorified [[Component:ValueField|ValueField]]. A dynamic variable will go through this binding process every time any part of the component changes.
=== Variable Spaces ===
By adding a [[Component:DynamicVariableSpace|DynamicVariableSpace]] to a slot, the slot and all of its children become a part of the named variable space. A slot can be part of multiple spaces at once. Spaces are <em>not</em> nested, meaning it is advised to make unique names for variable spaces.


{{Note|Currently, there exist a few instances where created variables do not instantly bind/rebind to a dynamic variable space, requiring a [[ProtoFlux:Delay Updates|Delay Updates]] of 2+ updates. These include [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1394 creating new dynamic reference variables], [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2717 deleting dynamic variables], changing the name of a dynamic variable or dynamic variable space, and any instance where there is a dynamic variable space change without a component update, such as [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1690 duplicating slots containing a dynamic variable space] or reparenting a slot containing a dynamic variable under a new dynamic variable space. If you find your dynamic variables to be behaving weirdly, try adding a delay of 2 or more updates between such operations.|warning}}
=== Dynamic Variables ===
To create a dynamic variable, attach any one of the following components to a slot:
 
* [[Component:DynamicValueVariable|DynamicValueVariable]], for working with [[Type:IValue`1|IValue]] types ([[Type:int|int]], [[Type:string|string]], [[Type:float3|float3]], etc.).
* [[Component:DynamicReferenceVariable|DynamicReferenceVariable]], for working with [[Type:SyncRef`1|Reference]] types ([[Type:Slot|Slot]], [[Type:User|User]], etc.).
* [[Component:DynamicTypeVariable|DynamicTypeVariable]], for working with the [[Type:Type|Type]] type.
 
Dynamic variables have a name and a value. A variable's name is its unique identifier within the variable space, while its value is the value of the dynamic variable. This is touched on later in [[#Binding]].


=== Dynamic Fields ===
=== Dynamic Fields ===
It is also possible to interface with an existing [[Type:IField|IField]] as if it were a dynamic variable. This is done by attaching a [[Component:DynamicField|DynamicField]] component (for [[Type:IValue`1|IValue]] types), [[Component:DynamicReference|DynamicReference]] component (for [[Type:SyncRef`1|SyncRef]] types), or [[Component:DynamicTypeField|DynamicTypeField]] component (for the [[Type:Type|Type]] type), then dragging the target field into the <code>TargetField</code> field.
It is possible to "transform" an existing [[Type:IField|IField]] on a component into a dynamic variable. This is done by any one of the following components:
 
* [[Component:DynamicField|DynamicField]], for working with IValue types.
* [[Component:DynamicReference|DynamicReference]], for working with Reference types.
 
Upon attaching the component and dragging the field you want to convert into <code>TargetField</code>, the pointed field can then be interfaced with like any other dynamic variable.
 
=== Naming Restrictions ===
The names of dynamic variables and dynamic variable spaces must not contain symbols, punctuation, or whitespace, <em>except</em> for period (<code>.</code>), underscore (<code>_</code>), and space (<code> </code>). To check if a character is unable to be used in a dynamic variable name, one can use the [[ProtoFlux:Is Symbol|Is Symbol]], [[ProtoFlux:Is Punctuation|Is Punctuation]], and [[ProtoFlux:Is White Space|Is White Space]] ProtoFlux nodes, taking care of the three exceptions above.
 
== Binding ==
The process of a dynamic variable being associated with a given space is called ''binding''. A dynamic variable component will traverse up the slot heirarchy, including its current slot, looking for an applicable variable space to bind to. If a dynamic variable does not find a dynamic variable space that it can bind to, it will not be accessible outside of the component itself, essentially reducing to a glorified [[Component:ValueField|ValueField]]. A dynamic variable will go through this binding process every time any part of the component changes.
 
=== Direct Vs Indirect Binding ===
When making a dynamic variable, the <code>VariableName</code> of a dynamic variable component can be one of the following two forms: <code>VariableName</code> or <code>VariableSpaceName/VariableName</code>. The former represents ''indirect binding'', while the latter represents ''direct binding''.
 
If a dynamic variable is indirectly binding, it will bind to the first dynamic variable space that does not have <code>OnlyDirectBinding</code> set to <code>True</code>. If a dynamic variable is directly binding, it will bind to the first dynamic variable space that matches <code>VariableSpaceName</code>.
 
For example, in the following setup:
 
└─ Foo - Variable Space "test"
    └─ Bar - Variable Space "test2"
      └─ Baz - Dynamic Variable "test/var"
 
The dynamic variable <code>test/var</code> will bind to the variable space <code>test</code>.
 
=== Warning ===
As of the time of writing, there exist a few instances where created variables do not instantly bind/rebind to a dynamic variable space, requiring a [[ProtoFlux:Delay Updates|Delay Updates]] of 2+ updates. These include [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1394 creating new dynamic reference variables], [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2717 deleting dynamic variables], changing the name of a dynamic variable or dynamic variable space, and any instance where there is a dynamic variable space change without a component update, such as [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1690 duplicating slots containing a dynamic variable space] or reparenting a slot containing a dynamic variable under a new dynamic variable space. If you find your dynamic variables to be behaving weirdly, try adding a delay of 2 or more updates between such operations.
 
== Interfacing ==
 
=== Reading Dynvars ===
Dynamic variables can be read from like any other field without issue. In ProtoFlux, the [[ProtoFlux:Read Dynamic Variable|Read Dynamic Variable]] node exists as a way to dynamically change what variable should be read by virtue of a slot and a variable name. Additionally, if the slot and variable name are meant to be constant, the [[ProtoFlux:Dynamic Variable Input|Dynamic Variable Input]] node can be used to efficiently and compactly read from a dynamic variable.
 
=== Driving from Dynvars ===
By using a [[Component:DynamicValueVariableDriver|DynamicValueVariableDriver]] or [[Component:DynamicReferenceVariableDriver|DynamicReferenceVariableDriver]] component, you can drive fields using a dynamic variable. This is recommended over traditional methods of driving by virtue of its flexibility and compactness.


=== Reading and Writing ===
=== Writing to Dynvars ===
Dynamic variables can be read in any fashion one sees fit, such as copying from the variable field, sourcing the variable field, or using the [[ProtoFlux:Read Dynamic Variable|Read Dynamic Variable]] node. Dynamic variables can be written to via the [[ProtoFlux:Write Dynamic Variable|Write Dynamic Variable]] or [[ProtoFlux:Write Or Create Dynamic Variable|Write Or Create Dynamic Variable]] nodes. Additionally, it is possible to directly drive a field using the value of a dynamic variable by using either the [[Component:DynamicValueVariableDriver|DynamicValueVariableDriver]] or [[Component:DynamicReferenceVariableDriver|DynamicReferenceVariableDriver]] component.
Dynamic variables should be written to via the [[ProtoFlux:Write Dynamic Variable|Write Dynamic Variable]] or [[ProtoFlux:Write Or Create Dynamic Variable]] ProtoFlux nodes.


==== Driving Dynvars ====
=== Driving Dynvars ===
Driving dynamic variables must be done with caution. For one, one must drive the value field of the dynamic variable, which can incur a delay of the value when reading it back. Additionally, if a dynamic variable is being driven, it is <em>crucial</em> that <em>all</em> instances of the same dynamic variable are driven by the same value. Otherwise, clients will fight over which value is the "true" value of the dynamic variable and cause inconsistent behavior.
Driving dynamic variables must be done with caution. For one, one must drive the value field of the dynamic variable, which can incur a delay of the value when reading it back. Additionally, if a dynamic variable is being driven, it is <em>crucial</em> that <em>all</em> instances of the same dynamic variable are driven by the same value. Otherwise, clients will fight over which value is the "true" value of the dynamic variable and cause inconsistent behavior.


Line 22: Line 65:
Even though dynamic variables allow for a wide array of freedom, there are a few practices generally considered to be favorable when working with dynamic variables:
Even though dynamic variables allow for a wide array of freedom, there are a few practices generally considered to be favorable when working with dynamic variables:


* It is highly recommended to have only one instance of a dynamic variable (dynamic variable component with the same name) at any given time. There aren't any huge problems with having multiple dynamic variable instances if none or all of the instances are being driven, but it allows for cleaner organization of variables.
* It is highly recommended to have only one instance of a dynamic variable (dynamic variable component with the same name) at any given time.
* Do <em>not</em> write to the value of the dynamic variable by sourcing the field and using a [[ProtoFlux:Write|Write]] node. Always use the ProtoFlux nodes for writing to a dynamic variable. Otherwise, you will need to wait 2+ updates before the variable actually propagates the new value when reading the dynamic variable back. Reading can be done in any fashion and will update instantly upon the variable being written to.
** There aren't any huge problems with having multiple dynamic variable instances if none or all of the instances are being driven, but it allows for cleaner organization of variables.
* Using variable names that directly bind allows for a clearer overview of where the variables should be bound. Indirectly binding variable names are more suited for variables that are dynamically created and/or destroyed as part of an object's function.
* Do <em>not</em> write to the value of the dynamic variable by sourcing the field and using a [[ProtoFlux:Write|Write]] node. Always use the ProtoFlux nodes for writing to a dynamic variable.
** Otherwise, you will need to wait 2+ updates before the variable actually propagates the new value when reading the dynamic variable back.
** Reading can be done in any fashion and will update instantly upon the variable being written to.
* Using variable names that directly bind allows for a clearer overview of what space the variables should be bound to. Indirectly binding variable names are more suited for variables that are dynamically created and/or destroyed as part of an object's function.
** Using <code>OnlyDirectBinding</code> on a DynamicVariableSpace strictly enforces this behavior, which can prevent misbindings and catch errors earlier.
** Using <code>OnlyDirectBinding</code> on a DynamicVariableSpace strictly enforces this behavior, which can prevent misbindings and catch errors earlier.
* DynamicVariableSpaces are not nested. If a system is complex enough, or if a DynamicVariableSpace is being shared by multiple objects, using periods (<code>.</code>) to pseudo-isolate objects or systems from one another is greatly encouraged.
* DynamicVariableSpaces are not nested. If a system is complex enough, or if a DynamicVariableSpace is being shared by multiple objects, using periods (<code>.</code>) to pseudo-isolate objects or systems from one another is encouraged.


== Default Spaces ==
== Default Spaces ==
Line 37: Line 83:
* <code>Dash</code>, which exists under the slot containing the [[Component:UserspaceRadiantDash|UserspaceRadiantDash]] in userspace.
* <code>Dash</code>, which exists under the slot containing the [[Component:UserspaceRadiantDash|UserspaceRadiantDash]] in userspace.


== Example Applications ==
== Example Usage ==

Revision as of 05:42, 5 August 2024

Dynamic variables, commonly shorted to dyn vars or dynvars, is a system of data storage wherein one can store arbitrary, scoped data under slot hierarchies with arbitrary names, akin to that of an associative array. Their usage is usually found in large systems with many moving parts, but can nonetheless be useful as easy "global" values that can be changed on an object.

For a quick-start guide on using dynamic variables, the How To Use Dynamic Variables page serves to be a how-to.

Overview

Dynamic variables are managed with two parts: dynamic variable spaces and dynamic variables. Dynamic variables live under a dynamic variable space, and can be created, modified, and destroyed dynamically.

Variable Spaces

By adding a DynamicVariableSpace to a slot, the slot and all of its children become a part of the named variable space. A slot can be part of multiple spaces at once. Spaces are not nested, meaning it is advised to make unique names for variable spaces.

Dynamic Variables

To create a dynamic variable, attach any one of the following components to a slot:

Dynamic variables have a name and a value. A variable's name is its unique identifier within the variable space, while its value is the value of the dynamic variable. This is touched on later in #Binding.

Dynamic Fields

It is possible to "transform" an existing IField on a component into a dynamic variable. This is done by any one of the following components:

Upon attaching the component and dragging the field you want to convert into TargetField, the pointed field can then be interfaced with like any other dynamic variable.

Naming Restrictions

The names of dynamic variables and dynamic variable spaces must not contain symbols, punctuation, or whitespace, except for period (.), underscore (_), and space ( ). To check if a character is unable to be used in a dynamic variable name, one can use the Is Symbol, Is Punctuation, and Is White Space ProtoFlux nodes, taking care of the three exceptions above.

Binding

The process of a dynamic variable being associated with a given space is called binding. A dynamic variable component will traverse up the slot heirarchy, including its current slot, looking for an applicable variable space to bind to. If a dynamic variable does not find a dynamic variable space that it can bind to, it will not be accessible outside of the component itself, essentially reducing to a glorified ValueField. A dynamic variable will go through this binding process every time any part of the component changes.

Direct Vs Indirect Binding

When making a dynamic variable, the VariableName of a dynamic variable component can be one of the following two forms: VariableName or VariableSpaceName/VariableName. The former represents indirect binding, while the latter represents direct binding.

If a dynamic variable is indirectly binding, it will bind to the first dynamic variable space that does not have OnlyDirectBinding set to True. If a dynamic variable is directly binding, it will bind to the first dynamic variable space that matches VariableSpaceName.

For example, in the following setup:

└─ Foo - Variable Space "test"
   └─ Bar - Variable Space "test2"
      └─ Baz - Dynamic Variable "test/var"

The dynamic variable test/var will bind to the variable space test.

Warning

As of the time of writing, there exist a few instances where created variables do not instantly bind/rebind to a dynamic variable space, requiring a Delay Updates of 2+ updates. These include creating new dynamic reference variables, deleting dynamic variables, changing the name of a dynamic variable or dynamic variable space, and any instance where there is a dynamic variable space change without a component update, such as duplicating slots containing a dynamic variable space or reparenting a slot containing a dynamic variable under a new dynamic variable space. If you find your dynamic variables to be behaving weirdly, try adding a delay of 2 or more updates between such operations.

Interfacing

Reading Dynvars

Dynamic variables can be read from like any other field without issue. In ProtoFlux, the Read Dynamic Variable node exists as a way to dynamically change what variable should be read by virtue of a slot and a variable name. Additionally, if the slot and variable name are meant to be constant, the Dynamic Variable Input node can be used to efficiently and compactly read from a dynamic variable.

Driving from Dynvars

By using a DynamicValueVariableDriver or DynamicReferenceVariableDriver component, you can drive fields using a dynamic variable. This is recommended over traditional methods of driving by virtue of its flexibility and compactness.

Writing to Dynvars

Dynamic variables should be written to via the Write Dynamic Variable or ProtoFlux:Write Or Create Dynamic Variable ProtoFlux nodes.

Driving Dynvars

Driving dynamic variables must be done with caution. For one, one must drive the value field of the dynamic variable, which can incur a delay of the value when reading it back. Additionally, if a dynamic variable is being driven, it is crucial that all instances of the same dynamic variable are driven by the same value. Otherwise, clients will fight over which value is the "true" value of the dynamic variable and cause inconsistent behavior.

Best Practices

Even though dynamic variables allow for a wide array of freedom, there are a few practices generally considered to be favorable when working with dynamic variables:

  • It is highly recommended to have only one instance of a dynamic variable (dynamic variable component with the same name) at any given time.
    • There aren't any huge problems with having multiple dynamic variable instances if none or all of the instances are being driven, but it allows for cleaner organization of variables.
  • Do not write to the value of the dynamic variable by sourcing the field and using a Write node. Always use the ProtoFlux nodes for writing to a dynamic variable.
    • Otherwise, you will need to wait 2+ updates before the variable actually propagates the new value when reading the dynamic variable back.
    • Reading can be done in any fashion and will update instantly upon the variable being written to.
  • Using variable names that directly bind allows for a clearer overview of what space the variables should be bound to. Indirectly binding variable names are more suited for variables that are dynamically created and/or destroyed as part of an object's function.
    • Using OnlyDirectBinding on a DynamicVariableSpace strictly enforces this behavior, which can prevent misbindings and catch errors earlier.
  • DynamicVariableSpaces are not nested. If a system is complex enough, or if a DynamicVariableSpace is being shared by multiple objects, using periods (.) to pseudo-isolate objects or systems from one another is encouraged.

Default Spaces

As of the time of writing, there are three dynamic spaces that exist by default:

  • World, which exists under the Root of the world. This space is OnlyDirectBinding.
    • Useful for things that should globally affect the world or broadcast information throughout the world. Example items that use this space include BeatLink and the Redprint manager.
  • User, which exists under every User's User Root Slot. This space is OnlyDirectBinding.
    • Useful for systems that affect avatars, as they can rely on a standardized space being available for each user to read and write variables on.
  • Dash, which exists under the slot containing the UserspaceRadiantDash in userspace.

Example Usage