-
-
Save NGenesis/9729ad29bfff576a9638593e852073b1 to your computer and use it in GitHub Desktop.
Add rudimentary UdonSharp support for passing and handling custom event arguments
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
using UdonSharp; | |
using UnityEngine; | |
using VRC.Udon; | |
using VRC.Udon.Common.Interfaces; | |
using System; | |
namespace Genesis.Udon | |
{ | |
public class CustomEventArgsTest : UdonSharpBehaviour | |
{ | |
public void DoTests() | |
{ | |
this.SendCustomEvent("Test", 1.0f, 2, "stuff", true, this); // Calls Test_0 | |
this.SendCustomEvent("Test", 1.0f, "stuff", 2, true, this); // Calls Test_1 | |
} | |
public void Test(float floatValue, int intValue, string stringValue, bool boolValue, UdonSharpBehaviour eventSender) | |
{ | |
Debug.Log($"Test_0 {floatValue} {intValue} {stringValue} {boolValue} {eventSender.name}"); | |
} | |
public void Test(float floatValue, string stringValue, int intValue, bool boolValue, UdonBehaviour eventSender) | |
{ | |
Debug.Log($"Test_1 {floatValue} {stringValue} {intValue} {boolValue} {eventSender.name}"); | |
} | |
} | |
} |
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
// Modify MethodSymbol.Emit method in Packages\com.vrchat.worlds\Integrations\UdonSharp\Editor\Compiler\Binder\Symbols\MethodSymbol.cs | |
namespace UdonSharp.Compiler.Symbols | |
{ | |
internal abstract class MethodSymbol : Symbol | |
{ | |
public virtual void Emit(EmitContext context) | |
{ | |
EmitContext.MethodLinkage linkage = context.GetMethodLinkage(this, false); | |
// Generate reflection data for method arguments | |
if(!string.IsNullOrEmpty(linkage.MethodExportName)) | |
{ | |
var parameterNames = new List<string>(); | |
var parameterTypes = new List<Type>(); | |
foreach(var parameter in linkage.ParameterValues) | |
{ | |
parameterNames.Add(parameter.UniqueID); | |
parameterTypes.Add(parameter.UdonType.SystemType); | |
} | |
context.RootTable.CreateReflectionValue($"__refl_argnames_{linkage.MethodExportName}", context.GetTypeSymbol(typeof(string).MakeArrayType()), parameterNames.ToArray()); | |
context.RootTable.CreateReflectionValue($"__refl_argtypes_{linkage.MethodExportName}", context.GetTypeSymbol(typeof(Type).MakeArrayType()), parameterTypes.ToArray()); | |
} | |
context.Module.AddCommentTag(""); | |
context.Module.AddCommentTag(RoslynSymbol.ToDisplayString().Replace("\n", "").Replace("\r", "")); | |
context.Module.AddCommentTag(""); | |
context.Module.LabelJump(linkage.MethodLabel); | |
using (context.OpenBlockScope()) | |
{ | |
if (MethodBody is BoundExpression bodyExpression) | |
{ | |
context.EmitReturn(bodyExpression); | |
} | |
else | |
{ | |
context.Emit(MethodBody); | |
context.EmitReturn(); | |
} | |
context.FlattenTableCounters(); | |
} | |
} | |
} | |
} |
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
using UdonSharp; | |
using VRC.Udon.Common.Interfaces; | |
using System; | |
public static class UdonCustomEventExtensions | |
{ | |
public static void SendCustomEvent<T>(this IUdonEventReceiver instance, string eventName, T value) => SendCustomEventArgs(instance, eventName, new object[] { value }); | |
public static void SendCustomEvent<T0, T1>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1 }); | |
public static void SendCustomEvent<T0, T1, T2>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2 }); | |
public static void SendCustomEvent<T0, T1, T2, T3>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4, value5 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7, T8>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7, value8 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(this IUdonEventReceiver instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8, T9 value9) => SendCustomEventArgs(instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7, value8, value9 }); | |
public static void SendCustomEvent<T>(this UdonSharpBehaviour instance, string eventName, T value) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value }); | |
public static void SendCustomEvent<T0, T1>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1 }); | |
public static void SendCustomEvent<T0, T1, T2>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2 }); | |
public static void SendCustomEvent<T0, T1, T2, T3>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4, value5 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7, T8>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7, value8 }); | |
public static void SendCustomEvent<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(this UdonSharpBehaviour instance, string eventName, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8, T9 value9) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, new object[] { value0, value1, value2, value3, value4, value5, value6, value7, value8, value9 }); | |
public static void SendCustomEventArgs(this UdonSharpBehaviour instance, string eventName, object[] args) => SendCustomEventArgs((IUdonEventReceiver)instance, eventName, args); | |
public static void SendCustomEventArgs(this IUdonEventReceiver instance, string eventName, object[] args) | |
{ | |
if(instance == null) return; | |
if(args == null || args.Length == 0) | |
{ | |
// No arguments supplied, call event without arguments | |
instance.SendCustomEvent(eventName); | |
return; | |
} | |
// Find bindable event | |
bool foundBindableEvent = false; | |
int eventIndex = 0; | |
string resolvedEventName = string.Empty; | |
while(!foundBindableEvent) | |
{ | |
resolvedEventName = $"__{eventIndex++}_{eventName}"; | |
// Ensure event exists | |
var resolvedEventTypesName = $"__refl_argtypes_{resolvedEventName}"; | |
if(instance.GetProgramVariableType(resolvedEventTypesName) == null) break; | |
if(CanBindCustomEventArgs(instance, (Type[])instance.GetProgramVariable(resolvedEventTypesName), args)) foundBindableEvent = true; | |
} | |
if(!foundBindableEvent) | |
{ | |
// No bindable events found, call event without arguments | |
instance.SendCustomEvent(eventName); | |
return; | |
} | |
// Retrieve argument names | |
var argNames = (string[])instance.GetProgramVariable($"__refl_argnames_{resolvedEventName}"); | |
if(argNames == null || argNames.Length == 0) | |
{ | |
// No argument overrides found, call event without arguments | |
instance.SendCustomEvent(eventName); | |
return; | |
} | |
// Bind arguments and call event | |
for(var i = 0; i < args.Length && i < argNames.Length; ++i) instance.SetProgramVariable(argNames[i], args[i]); | |
instance.SendCustomEvent(resolvedEventName); | |
} | |
private static bool CanBindCustomEventArgs(this IUdonEventReceiver instance, Type[] argTypes, object[] args) | |
{ | |
if(args == null || argTypes == null || args.Length != argTypes.Length) return false; | |
for(var i = 0; i < args.Length; ++i) | |
{ | |
if(args[i] != null && argTypes[i] != args[i].GetType()) return false; | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment