Skip to content

Attributes

SyntaxDescription
[UdonSynced]Variable sync
[UdonSynced(UdonSyncMode.Linear)]Sync with interpolation
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]Specifying send timing
[UdonBehaviourSyncMode(BehaviourSyncMode.Continuous)]Continuous sending
[FieldChangeCallback(nameof(Value))]Change notification
[NetworkCallable]Allowing calls over the network
[RecursiveMethod]Allowing recursion
[Inline]Inlining calls
[SerializeField]Showing a private field
[HideInInspector]Hiding a public field
[Header] [Tooltip]Header and description
[Range(0f, 1f)]Specifying a value range
[Space]Spacing
[SerializeField, Range(0f, 1f)]Multiple attributes on one field
[System.Obsolete]Marking as obsolete
SyntaxDescriptionErrorReasonInstead
private int Down(int n) { return Down(n - 1); }Calling itself without the attributeTUKI0001runtimeAdd [RecursiveMethod] (or write it with a loop or your own stack)
SendCustomNetworkEvent(…, nameof(Take), 1)([NetworkCallable] 無し)Calling a method with arguments over the network by name, without the attributeTUKI0001runtimeAdd [NetworkCallable] on the receiving side
Without the attribute, a method with arguments is registered under a name that includes the argument types. That doesn’t match the name written with nameof, so it can’t be looked up by name. Adding [NetworkCallable] registers it under the name as written.

The sync attributes can be written from this language’s namespace. Using the migration source namespace at the same time makes two attributes with the same name visible, which stops compilation. Removing one using fixes it (Program shape).

A variable with [UdonSynced] keeps the same value across players.

using UnityEngine;
using Tsukimi;
public class AttributesSynced : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
RequestSerialization();
Debug.Log(value); // => 1
}
}

UdonSyncMode specifies the kind of interpolation. Which kinds are available depends on the type.

using UnityEngine;
using Tsukimi;
public class AttributesSyncedInterpolated : TsukimiBehaviour
{
[UdonSynced(UdonSyncMode.Linear)] private float value;
void Start()
{
Debug.Log(value); // => 0
}
}

With Manual, the value is sent when you call RequestSerialization().

using UnityEngine;
using Tsukimi;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class AttributesSyncModeManual : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
RequestSerialization();
}
}

With Continuous, the value is sent without calling RequestSerialization().

using UnityEngine;
using Tsukimi;
[UdonBehaviourSyncMode(BehaviourSyncMode.Continuous)]
public class AttributesSyncModeContinuous : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
}
}

When a synced value arrives, the setter of the specified property is called.

using UnityEngine;
using Tsukimi;
public class AttributesFieldChangeCallback : TsukimiBehaviour
{
[UdonSynced, FieldChangeCallback(nameof(Value))] private int backing;
public int Value
{
get { return backing; }
set { backing = value; }
}
void Start()
{
Value = 1;
Debug.Log(Value); // => 1
}
}

A method called over the network with arguments needs this attribute.

using UnityEngine;
using Tsukimi;
using VRC.SDK3.UdonNetworkCalling;
public class AttributesNetworkCallable : TsukimiBehaviour
{
[NetworkCallable]
public void Receive(int n)
{
Debug.Log(n);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

A method that calls itself needs this attribute, because storage for arguments and local variables isn’t created fresh for each call.

using UnityEngine;
using Tsukimi;
public class AttributesRecursiveMethod : TsukimiBehaviour
{
[RecursiveMethod]
private int CountDown(int n)
{
return n <= 0 ? 0 : CountDown(n - 1);
}
void Start()
{
Debug.Log(CountDown(3)); // => 0
}
}

A method with this attribute is expanded at the call site regardless of its size.

using UnityEngine;
using Tsukimi;
public class AttributesInline : TsukimiBehaviour
{
[Inline]
private int Twice(int n) { return n * 2; }
void Start()
{
Debug.Log(Twice(2)); // => 4
}
}

Even a private field can have its value set from the inspector.

using UnityEngine;
using Tsukimi;
public class AttributesSerializeField : TsukimiBehaviour
{
[SerializeField] private int value;
void Start()
{
Debug.Log(value); // => 0
}
}

The field stays public but no longer appears in the inspector.

using UnityEngine;
using Tsukimi;
public class AttributesHideInInspector : TsukimiBehaviour
{
[HideInInspector] public int value;
void Start()
{
Debug.Log(value); // => 0
}
}

[Header] shows a heading, and [Tooltip] shows a description on hover, in the inspector.

using UnityEngine;
using Tsukimi;
public class AttributesHeaderAndTooltip : TsukimiBehaviour
{
[Header("Group")]
[Tooltip("note")]
public int value;
void Start()
{
Debug.Log(value); // => 0
}
}

In the inspector it becomes a slider, and values outside the specified range can’t be entered.

using UnityEngine;
using Tsukimi;
public class AttributesRange : TsukimiBehaviour
{
[Range(0f, 1f)] public float value;
void Start()
{
Debug.Log(value); // => 0
}
}

Adds spacing between items in the inspector.

using UnityEngine;
using Tsukimi;
public class AttributesSpace : TsukimiBehaviour
{
[Space]
public int value;
void Start()
{
Debug.Log(value); // => 0
}
}
using UnityEngine;
using Tsukimi;
public class AttributesMultipleOnOneField : TsukimiBehaviour
{
[SerializeField, Range(0f, 1f)] private float value;
void Start()
{
Debug.Log(value); // => 0
}
}

Using a member with this attribute produces a warning.

using UnityEngine;
using Tsukimi;
public class AttributesObsolete : TsukimiBehaviour
{
[System.Obsolete]
public void Old() { }
void Start()
{
Debug.Log(1); // => 1
}
}