UdonSharp Documentation

repository·master·Indexed 20 days ago

https://github.com/merlinvr/udonsharp

A compiler for VRChat that allows developers to write Udon programs using C# syntax. The tool provides a proxy model for editor scripting, a Class Exposure Tree for verifying Udon compatibility, and configurable compilation behaviors. It includes support for custom inspectors via UdonSharpBehaviour and integration with community resources like CyanEmu for debugging.

Tokens
22.5K
Snippets
55
Records
99
Agent score
73%

What's inside UdonSharp

  1. Use UdonSharpBehaviour instead of UdonBehaviour for type safety

    master

    In UdonSharp code, UdonBehaviour and UdonSharpBehaviour are treated as the same object. However, in C# editor scripts, UdonSharpBehaviour does not inherit from UdonBehaviour.

    To ensure the proxy system correctly handles references, you should:

    1. Prefer UdonSharpBehaviour as variable types: This allows the proxy system to automatically convert proxy references into the correct UdonBehaviour references.
    2. Avoid UdonBehaviour or Component for U# references: If you use UdonBehaviour or generic Component types to store references to other U# scripts, the proxy system may not handle them automatically, and these references might be cleared to null during a build.
    3. Use UdonBehaviour for Graph assets: If you need to reference Udon graphs (which have no C# equivalent), using UdonBehaviour is appropriate.
  2. Optimize GetComponent<T> usage

    master

    Calling GetComponent<T>() is expensive in Udon, especially when fetching an UdonSharpBehaviour type. This is because UdonSharp must iterate through all UdonBehaviours to verify the type.

    Best Practice: Only call GetComponent<T>() during Start() or during infrequent events. Cache the reference in a class variable for later use instead of calling it repeatedly in Update or other frequent loops.

  3. Understand Synced Variables and Data Sizes

    master

    Variables marked with the [UdonSynced] attribute are synchronized across the network. Note that the 'size' listed below refers to the approximate memory size; serialized data transmitted over the network may be larger (e.g., a bool typically sends at least 1 byte).

    To monitor actual serialized data usage, use the byteCount property in the OnPostSerialization event. For detailed networking constraints, refer to the official Udon Network Specs.

    ### Boolean  types
    | Type | Size    |
    | ---- | ------- |
    | bool | 1 byte  |
    
    ### Integral numeric types
    | Type   | Range                           | Size    |
    |--------|---------------------------------|---------|
    | sbyte  | -128 to 127                     | 1 byte  |
    | byte   | 0 to 255                       | 1 byte  |
    | short  | -32,768 to 32,767               | 2 bytes |
    | ushort | 0 to 65,535                     | 2 bytes |
    | int    | -2,147,483,648 to 2,147,483,647 | 4 bytes |
    | uint   | 0 to 4,294,967,295              | 4 bytes |
    | long   | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 8 bytes |
    | ulong  | 0 to 18,446,744,073,709,551,615 | 8 bytes |
    
    ### Floating-point numeric types
    | Type   | Approximate range             | Precision     | Size     |
    |--------|-------------------------------|---------------|----------|
    | float  | ±1.5 x 10^(−45) to ±3.4 x 10^(38) | ~6-9 digits   | 4 bytes  |
    | double | ±5.0 × 10^(−324) to ±1.7 × 10^(308) | ~15-17 digits | 8 bytes  |
    
    ### Vector mathematics types and structures (Unity)
    | Type        | Range         | Size     |
    |-------------|---------------|----------|
    | [Vector2](https://docs.unity3d.com/ScriptReference/Vector2.html) | same as float | 8 bytes  |
    | [Vector3](https://docs.unity3d.com/ScriptReference/Vector3.html) | same as float | 12 bytes |
    | [Vector4](https://docs.unity3d.com/ScriptReference/Vector4.html) | same as float | 16 bytes |
    | [Quaternion](https://docs.unity3d.com/ScriptReference/Quaternion.html) | same as float | 16 bytes |
    
    ### Color structures
    | Type     | Range / Precision | Size     |
    |----------|-------------------|----------|
    | [Color](https://docs.unity3d.com/ScriptReference/Color.html) | same as float     | 16 bytes |
    | [Color32](https://docs.unity3d.com/ScriptReference/Color32.html) | same as byte      | 4 bytes  |
    
    ### Text types and structures
    | Type   | Range            | Size     |
    |--------|------------------|----------|
    | char   | U+0000 to U+FFFF | 2 bytes  |
    | string | same as char     | 2 bytes / char |
    
    ### Other structures
    | Type   | Range            | Size     |
    |--------|------------------|----------|
    | [VRCUrl](#vrcurl) | U+0000 to U+FFFF | 2 bytes / char |
  4. Understand UdonSharp C# language support and limitations

    master

    UdonSharp compiles C# to Udon assembly. It is not fully conformant to the C# language specification.

    Supported Features

    • Flow Control: if, else, while, for, do, foreach, switch, return, break, continue, ternary operator (? : ), and null-coalescing ??.
    • Types & Conversions: Implicit/explicit conversions, arrays, array indexers, and jagged arrays.
    • Methods: User-defined methods (including out, ref, params, and extension methods), static methods, and typeof().
    • Unity/Udon Integration: UdonSharpBehaviour inheritance, virtual methods, and Unity/Udon event callbacks with arguments (e.g., OnPlayerJoined(VRCPlayerApi player)).
    • Advanced: String interpolation, field initializers, and recursive method calls (using the [RecursiveMethod] attribute).

    Key Differences from Standard Unity C#

    • Inheritance: Always inherit from UdonSharpBehaviour instead of MonoBehaviour for the best experience.
    • Component Access: Generic GetComponent<T>() works for standard Unity components, but for UdonBehaviour, you must use: (UdonBehaviour)GetComponent(typeof(UdonBehaviour)).
    • Collections: Only standard arrays [] are supported. List<T> is not currently supported.
    • Initialization: Field initializers are evaluated at compile time. If your initialization logic depends on other objects in the scene, use the Start() method instead.
    • Networking: Use the [UdonSynced] attribute on fields you want to synchronize across the network.
    • Type Abstraction: .GetType() may return unexpected types due to Udon abstraction. For example, a jagged array (e.g., int[][]) will return object[].
    • Struct Mutation Bug: Mutating methods on structs (like Vector3.Normalize()) will not modify the original struct due to Udon limitations.
  5. Optimize SendCustomEvent and cross-behaviour calls

    master

    Calling SendCustomEvent on a method of an UdonBehaviour has specific requirements and performance implications:

    • Visibility: The target method must be public.
    • Performance cost: Calls across different behaviours are slower than local method calls because Udon uses SendCustomEvent internally for cross-behaviour communication.
    • Optimization:
      • Prefer grouping related logic into a single UdonSharpBehaviour rather than splitting it across multiple behaviours.
      • Keep methods private whenever they are not called from other scripts. Reducing the number of public methods improves performance because it reduces the work Udon must do to search for callable methods.
  6. Optimize Udon performance and avoid heavy algorithms

    master

    Udon is significantly slower than standard C# (roughly 200x to 1000x slower). To maintain performance:

    • Avoid heavy iterations in Update: Do not run complex algorithms or large loops inside Update. For example, instead of iterating over 40 GameObjects to rotate them via script, use a Unity Animation.
    • Use built-in components: If a task can be accomplished using a standard Unity or VRChat component, use that instead of writing custom Udon code.
    • Time slicing: If you must perform a large amount of work, split the execution across multiple frames (time slicing) where possible.
    • Prefer animations: For repetitive visual tasks, animations are much more efficient than Udon scripts.
  7. Configure Network event scoping for CustomNetworkEvents

    master

    When using SendCustomNetworkEvent, follow these visibility rules to ensure methods are reachable:

    • Public methods: The target method must be public to receive network events.
    • Underscore prefix: Methods starting with an underscore (e.g., _MyLocalMethod) will not receive network events (as of VRChat 2020.4.4).
    • Best Practices:
      • Keep methods private by default to improve performance and prevent accidental network calls.
      • If you want a method to be public (callable locally by other UdonSharpBehaviours) but not callable via SendCustomNetworkEvent, prefix the method name with an underscore (e.g., public void _MyMethod()).
  8. Understand U# Editor Scripting and Proxies

    master

    UdonSharp (v0.18.0+) provides an editor scripting API that allows you to interact with UdonSharpBehaviour instances using standard C# editor patterns.

    The Proxy Model: When you create a U# script, UdonSharp creates a C# 'proxy' version of your behaviour. This proxy is a valid C# component added to the GameObject that is linked to the underlying UdonBehaviour.

    • Interaction: Most editor scripts should interact with the proxy.
    • Lifecycle: Proxies are created on the same GameObject as their backing UdonBehaviour and are always disabled.
    • Warning: Never re-enable proxies. If you run methods like GetComponentInChildren on a proxy, ensure you include disabled components in your search, otherwise, the proxy will not be returned.
    • Persistence: Proxies are hidden in the inspector and are not saved in scenes or builds, so they do not affect build size.