/// <summary> /// Verifies that Udon supports the given type and resolves the type name used to reference it in Udon /// </summary> /// <param name="externType">The found type</param> /// <param name="skipBaseTypeRemap">Skips remapping base VRCSDK types, this is primarily used for VRCSDK function return value types since they may point to the base type and we want to maintain that.</param> /// <returns>The Udon type name string if it is a valid Udon type, /// or null if it is not a valid Udon type.</returns> public string GetUdonTypeName(System.Type externType, bool skipBaseTypeRemap = false) { if (!skipBaseTypeRemap) { externType = UdonSharpUtils.RemapBaseType(externType); } string externTypeName = externType.GetNameWithoutGenericArity(); while (externType.IsArray || externType.IsByRef) { externType = externType.GetElementType(); } string typeNamespace = externType.Namespace; // Handle nested type names (+ sign in names) if (externType.DeclaringType != null) { string declaringTypeNamespace = ""; System.Type declaringType = externType.DeclaringType; while (declaringType != null) { declaringTypeNamespace = $"{externType.DeclaringType.Name}.{declaringTypeNamespace}"; declaringType = declaringType.DeclaringType; } typeNamespace += $".{declaringTypeNamespace}"; } if (externTypeName == "T" || externTypeName == "T[]") { typeNamespace = ""; } string fullTypeName = SanitizeTypeName($"{typeNamespace}.{externTypeName}"); foreach (System.Type genericType in externType.GetGenericArguments()) { fullTypeName += GetUdonTypeName(genericType); } // Seems like Udon does shortening for this specific type somewhere if (fullTypeName == "SystemCollectionsGenericListT") { fullTypeName = "ListT"; } else if (fullTypeName == "SystemCollectionsGenericIEnumerableT") { fullTypeName = "IEnumerableT"; } fullTypeName = fullTypeName.Replace("VRCUdonUdonBehaviour", "VRCUdonCommonInterfacesIUdonEventReceiver"); return(fullTypeName); }
public string GetUdonFieldAccessorName(FieldInfo externField, FieldAccessorType accessorType, bool validate = true) { System.Type fieldType = UdonSharpUtils.RemapBaseType(externField.DeclaringType); string functionNamespace = SanitizeTypeName(fieldType.FullName).Replace("VRCUdonUdonBehaviour", "VRCUdonCommonInterfacesIUdonEventReceiver"); string methodName = $"__{(accessorType == FieldAccessorType.Get ? "get" : "set")}_{externField.Name.Trim('_')}"; string paramStr = $"__{GetUdonTypeName(externField.FieldType)}"; string finalFunctionSig = $"{functionNamespace}.{methodName}{paramStr}"; if (validate && !nodeDefinitionLookup.Contains(finalFunctionSig)) { throw new System.Exception($"Field accessor {finalFunctionSig} is not exposed in Udon"); } return(finalFunctionSig); }
/// <summary> /// Verifies that Udon supports the given method and resolves the name used to reference it in Udon EXTERN calls /// </summary> /// <param name="externMethod"></param> /// <returns></returns> public string GetUdonMethodName(MethodBase externMethod, bool validate = true, List <System.Type> genericArguments = null) { System.Type methodSourceType = externMethod.ReflectedType; if (genericArguments != null) { if (genericArguments.Count != 1) { throw new System.ArgumentException("UdonSharp only supports 1 type generic methods at the moment"); } methodSourceType = genericArguments.First(); } methodSourceType = UdonSharpUtils.RemapBaseType(methodSourceType); bool isUdonSharpBehaviour = false; if (methodSourceType == typeof(UdonSharpBehaviour) || methodSourceType.IsSubclassOf(typeof(UdonSharpBehaviour))) { methodSourceType = typeof(VRC.Udon.UdonBehaviour); isUdonSharpBehaviour = true; } string functionNamespace = SanitizeTypeName(methodSourceType.FullName ?? methodSourceType.Namespace + methodSourceType.Name).Replace("VRCUdonUdonBehaviour", "VRCUdonCommonInterfacesIUdonEventReceiver"); string methodName = $"__{externMethod.Name.Trim('_').TrimStart('.')}"; ParameterInfo[] methodParams = externMethod.GetParameters(); if (isUdonSharpBehaviour && methodName == "__VRCInstantiate") { functionNamespace = "VRCInstantiate"; methodName = "__Instantiate"; } string paramStr = ""; if (methodParams.Length > 0) { paramStr = "_"; // Arg separator foreach (ParameterInfo parameterInfo in methodParams) { paramStr += $"_{GetUdonTypeName(parameterInfo.ParameterType, true)}"; } } else if (externMethod is ConstructorInfo) { paramStr = "__"; } string returnStr = ""; if (externMethod is MethodInfo) { returnStr = $"__{GetUdonTypeName(((MethodInfo)externMethod).ReturnType, true)}"; } else if (externMethod is ConstructorInfo) { returnStr = $"__{GetUdonTypeName(((ConstructorInfo)externMethod).DeclaringType)}"; } else { throw new System.Exception("Invalid extern method type for getting Udon name"); } string finalFunctionSig = $"{functionNamespace}.{methodName}{paramStr}{returnStr}"; if (validate && !nodeDefinitionLookup.Contains(finalFunctionSig)) { throw new System.Exception($"Method {finalFunctionSig} is not exposed in Udon"); } return(finalFunctionSig); }