private static bool ValidateProgramAssetCollisions(UdonSharpProgramAsset[] allProgramAssets) { Dictionary<MonoScript, List<UdonSharpProgramAsset>> scriptToAssetMap = new Dictionary<MonoScript, List<UdonSharpProgramAsset>>(); foreach (UdonSharpProgramAsset programAsset in allProgramAssets) { if (programAsset == null || programAsset.sourceCsScript == null) continue; // Add program asset to map to check if there are any duplicate program assets that point to the same script if (!scriptToAssetMap.TryGetValue(programAsset.sourceCsScript, out var programAssetList)) { programAssetList = new List<UdonSharpProgramAsset>(); scriptToAssetMap.Add(programAsset.sourceCsScript, programAssetList); } programAssetList.Add(programAsset); } int errorCount = 0; foreach (var scriptAssetMapping in scriptToAssetMap) { if (scriptAssetMapping.Value.Count > 1) { UdonSharpUtils.LogError($"Script {Path.GetFileName(AssetDatabase.GetAssetPath(scriptAssetMapping.Key))} is referenced by {scriptAssetMapping.Value.Count} UdonSharpProgramAssets, scripts can only be referenced by 1 program asset.\n" + "Referenced program assets:\n" + string.Join(",\n", scriptAssetMapping.Value.Select(AssetDatabase.GetAssetPath))); errorCount++; } } return errorCount == 0; }
public void AddExternCall(string externCall, string comment = "") { externStringSet.Add(externCall); AppendCommentedLine($"EXTERN, \"{externCall}\"", comment); programCounter += UdonSharpUtils.GetUdonInstructionSize("EXTERN"); }
public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType) { if (requestedBuildType == VRCSDKRequestedBuildType.Avatar) { return(true); } if (UdonSharpSettings.GetSettings().disableUploadCompile) { return(true); } UdonSharpCompilerV1.CompileSync(new UdonSharpCompileOptions() { IsEditorBuild = false }); UdonSharpEditorCache.SaveAllCache(); if (UdonSharpProgramAsset.AnyUdonSharpScriptHasError()) { UdonSharpUtils.LogError("Failed to compile UdonSharp scripts for build, check error log for details."); UdonSharpUtils.ShowEditorNotification("Failed to compile UdonSharp scripts for build, check error log for details."); return(false); } if (UdonSharpEditorManager.RunAllUpgrades()) { UdonSharpUtils.LogWarning(UdonSharpEditorManager.UPGRADE_MESSAGE); return(false); } return(true); }
public override Value EmitValue(EmitContext context) { Type operandType = ValueType.UdonType.SystemType; object allBits; if (UdonSharpUtils.IsSignedType(operandType)) { allBits = Convert.ChangeType(-1, operandType); } else { allBits = operandType.GetField("MaxValue").GetValue(null); } BoundAccessExpression allBitsExpr = BoundAccessExpression.BindAccess(context.GetConstantValue(ValueType, allBits)); Value returnValue = context.GetReturnValue(ValueType); using (context.InterruptAssignmentScope()) { BoundAccessExpression operandVal = BoundAccessExpression.BindAccess(context.EmitValue(SourceExpression)); context.EmitValueAssignment(returnValue, CreateBoundInvocation(context, null, new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.LogicalXor, ValueType, context), null, new BoundExpression[] { operandVal, allBitsExpr })); } return(returnValue); }
private static void CleanupCompile() { UdonSharpUtils.ClearAsyncProgressBar(); EditorApplication.UnlockReloadAssemblies(); CurrentJob = null; }
public void Compile() { Profiler.BeginSample("UdonSharp Compile"); System.Diagnostics.Stopwatch compileTimer = new System.Diagnostics.Stopwatch(); compileTimer.Start(); int totalErrorCount = 0; try { EditorUtility.DisplayProgressBar("UdonSharp Compile", "Parsing Syntax Trees...", 0f); UdonSharpProgramAsset[] allPrograms = UdonSharpProgramAsset.GetAllUdonSharpPrograms(); List <(UdonSharpProgramAsset, string)> programAssetsAndPaths = new List <(UdonSharpProgramAsset, string)>(); foreach (UdonSharpProgramAsset programAsset in allPrograms) { if (programAsset == null || programAsset.sourceCsScript == null) { continue; } programAssetsAndPaths.Add((programAsset, AssetDatabase.GetAssetPath(programAsset.sourceCsScript))); } UdonSharpProgramAsset[] programAssetsToCompile = modules.Select(e => e.programAsset).Where(e => e != null && e.sourceCsScript != null).ToArray(); try { beforeCompile?.Invoke(programAssetsToCompile); } catch (System.Exception e) { Debug.LogError($"Exception thrown by pre compile listener\n{e}"); } object syntaxTreeLock = new object(); List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)> programsAndSyntaxTrees = new List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)>(); Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)> syntaxTreeSourceLookup = new Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)>(); string[] defines = UdonSharpUtils.GetProjectDefines(isEditorBuild); Parallel.ForEach(programAssetsAndPaths, (currentProgram) => { string programSource = UdonSharpUtils.ReadFileTextSync(currentProgram.Item2); Microsoft.CodeAnalysis.SyntaxTree programSyntaxTree = CSharpSyntaxTree.ParseText(programSource, CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None).WithPreprocessorSymbols(defines)); lock (syntaxTreeLock) { programsAndSyntaxTrees.Add((currentProgram.Item1, programSyntaxTree)); syntaxTreeSourceLookup.Add(currentProgram.Item1, (programSource, programSyntaxTree)); } });
public TypeSymbol GetUdonTypeSymbol(ITypeSymbol type, AbstractPhaseContext context) { if (!TypeSymbol.TryGetSystemType(type, out var systemType)) { throw new InvalidOperationException("foundType should not be null"); } systemType = UdonSharpUtils.UserTypeToUdonType(systemType); return(GetTypeSymbol(systemType, context)); }
public ExternTypeSymbol(INamedTypeSymbol sourceSymbol, AbstractPhaseContext context) : base(sourceSymbol, context) { TryGetSystemType(sourceSymbol, out Type systemType); SystemType = systemType; Type udonType = UdonSharpUtils.UserTypeToUdonType(SystemType); UdonType = (ExternTypeSymbol)(udonType == SystemType ? this : context.GetUdonTypeSymbol(sourceSymbol)); ExternSignature = CompilerUdonInterface.GetUdonTypeName(this); }
public UdonHeapValueStorage(IUdonHeap heap, IUdonSymbolTable symbolTable, string symbolKey) { this.heap = heap; bool isValid = symbolTable.TryGetAddressFromSymbol(UdonSharpUtils.UnmanglePropertyFieldName(symbolKey), out symbolAddress) && heap.GetHeapVariableType(symbolAddress) == typeof(T) && heap.TryGetHeapVariable <T>(symbolAddress, out _); if (!isValid) { symbolAddress = 0xFFFFFFFF; } }
public override void WriteWeak(IValueStorage targetObject, object sourceObject) { VerifySerializationSanity(); if (sourceObject != null && !UdonSharpUtils.IsUserJaggedArray(sourceObject.GetType())) { throw new SerializationException($"Cannot convert {targetObject.GetType()} to {typeMetadata.cSharpType}"); } object tarArray = targetObject.Value; ConvertToUdonArrayElement(ref tarArray, sourceObject, typeMetadata.cSharpType); targetObject.Value = tarArray; }
public void SetToType(System.Type type) { cSharpType = type; if (cSharpType != null && cSharpType.IsArray) { System.Type elementType = cSharpType; while (elementType.IsArray) { elementType = elementType.GetElementType(); } arrayElementMetadata = new TypeSerializationMetadata(elementType); } udonStorageType = UdonSharpUtils.UserTypeToUdonType(cSharpType); }
public override void Read(ref T targetObject, IValueStorage sourceObject) { VerifySerializationSanity(); if (sourceObject == null) { UdonSharpUtils.LogError($"Field for {typeof(T)} does not exist"); return; } if (UsbSerializationContext.CollectDependencies) { if (sourceObject.Value is UnityEngine.Object unityObject && unityObject != null) { UsbSerializationContext.Dependencies.Add(unityObject); } return; } IValueStorage storage = sourceObject as ValueStorage <T>; if (storage == null) { Type storageType = sourceObject.GetType().GetGenericArguments()[0]; if (typeof(T).IsSubclassOf(storageType)) { storage = sourceObject; } else if (targetObject != null && targetObject.GetType().IsAssignableFrom(storageType)) { storage = sourceObject; } else if (targetObject == null && storageType.IsSubclassOf(typeof(T))) { storage = sourceObject; } else { UdonSharpUtils.LogError($"Type {typeof(T)} not compatible with serializer {sourceObject}"); return; } } targetObject = (T)storage.Value; }
internal static void SetSceneBehaviourUpgraded(UdonBehaviour behaviour) { if (!PrefabUtility.IsPartOfPrefabInstance(behaviour) && !PrefabUtility.IsPartOfPrefabAsset(behaviour)) { return; } if (!behaviour.publicVariables.TrySetVariableValue <bool>(UDONSHARP_SCENE_BEHAVIOUR_UPGRADE_MARKER, true)) { behaviour.publicVariables.RemoveVariable(UDONSHARP_SCENE_BEHAVIOUR_UPGRADE_MARKER); IUdonVariable newVar = new UdonVariable <bool>(UDONSHARP_SCENE_BEHAVIOUR_UPGRADE_MARKER, true); behaviour.publicVariables.TryAddVariable(newVar); } UdonSharpUtils.SetDirty(behaviour); }
public void AddJumpIfFalse(JumpLabel jumpTarget, string comment = "") { #if USE_UDON_LABELS AppendCommentedLine($"JUMP_IF_FALSE, {jumpTarget.uniqueName}", comment); #else if (jumpTarget.IsResolved) { AppendCommentedLine($"JUMP_IF_FALSE, {jumpTarget.AddresStr()}", comment); } else { AppendCommentedLine($"JUMP_IF_FALSE_LABEL, [{jumpTarget.uniqueName}]", comment); } #endif programCounter += UdonSharpUtils.GetUdonInstructionSize("JUMP_IF_FALSE"); }
private void ConvertToCSharpArrayElement(ref object targetElement, object elementValue, Type cSharpType) { if (elementValue == null) { targetElement = null; return; } if (UdonSharpUtils.IsUserJaggedArray(cSharpType)) { Array targetArray = (Array)targetElement; Array sourceArray = (Array)elementValue; if (!UsbSerializationContext.CollectDependencies) { if (targetArray == null || targetArray.Length != sourceArray.Length) { targetElement = targetArray = (Array)Activator.CreateInstance(cSharpType, sourceArray.Length); } } for (int i = 0; i < sourceArray.Length; ++i) { object elementVal = targetArray.GetValue(i); ConvertToCSharpArrayElement(ref elementVal, sourceArray.GetValue(i), cSharpType.GetElementType()); if (!UsbSerializationContext.CollectDependencies) { targetArray.SetValue(elementVal, i); } } } else if (cSharpType.IsArray) { IValueStorage innerArrayValueStorage = GetInnerValueStorage(); innerArrayValueStorage.Value = elementValue; rootArraySerializer.ReadWeak(ref targetElement, innerArrayValueStorage); innerValueStorages.Push(innerArrayValueStorage); } else { throw new Exception("Jagged array serializer requires a root array serializer"); } }
private static bool TryImplicitConstantConversion(ref BoundExpression boundExpression, TypeSymbol targetType) { if (!boundExpression.IsConstant) { return(false); } if (boundExpression.ValueType == targetType) { return(false); } var targetSystemType = targetType.UdonType.SystemType; object constantValue = boundExpression.ConstantValue.Value; // if (targetSystemType == typeof(string)) // { // IConstantValue constant = new ConstantValue<string>(constantValue?.ToString() ?? ""); // // boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode); // } var sourceSystemType = boundExpression.ValueType.UdonType.SystemType; if (ConstantExpressionOptimizer.CanDoConstantConversion(sourceSystemType) && ConstantExpressionOptimizer.CanDoConstantConversion(targetSystemType)) { IConstantValue constant = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(targetSystemType), ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue)); boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode); return(true); } if (boundExpression.ValueType.IsEnum && boundExpression.ValueType.IsExtern && UdonSharpUtils.IsIntegerType(targetSystemType)) { boundExpression = new BoundConstantExpression(ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue), targetType); return(true); } return(false); }
static void OnChangePlayMode(PlayModeStateChange state) { // Prevent people from entering play mode when there are compile errors, like normal Unity C# // READ ME // -------- // If you think you know better and are about to edit this out, be aware that you gain nothing by doing so. // If a script hits a compile error, it will not update until the compile errors are resolved. // You will just be left wondering "why aren't my scripts changing when I edit them?" since the old copy of the script will be used until the compile errors are resolved. // -------- if (state == PlayModeStateChange.EnteredPlayMode || state == PlayModeStateChange.ExitingEditMode) { if (UdonSharpProgramAsset.AnyUdonSharpScriptHasError()) { EditorApplication.isPlaying = false; UdonSharpUtils.ShowEditorNotification("All U# compile errors have to be fixed before you can enter playmode!"); } else if (state == PlayModeStateChange.EnteredPlayMode) { CreateProxyBehaviours(GetAllUdonBehaviours()); } } if (state == PlayModeStateChange.EnteredEditMode) { UdonSharpEditorCache.ResetInstance(); if (UdonSharpEditorCache.Instance.LastBuildType == UdonSharpEditorCache.DebugInfoType.Client) { UdonSharpProgramAsset.CompileAllCsPrograms(true); } RunAllUpdates(); } else if (state == PlayModeStateChange.ExitingEditMode) { if (UdonSharpEditorCache.Instance.LastBuildType == UdonSharpEditorCache.DebugInfoType.Client) { UdonSharpProgramAsset.CompileAllCsPrograms(true); } } UdonSharpEditorCache.SaveOnPlayExit(state); }
private string BuildExternSignature(TypeSymbol containingType, string methodName) { Type methodSourceType = containingType.UdonType.SystemType; methodSourceType = UdonSharpUtils.RemapBaseType(methodSourceType); string functionNamespace = CompilerUdonInterface.SanitizeTypeName(methodSourceType.FullName ?? methodSourceType.Namespace + methodSourceType.Name).Replace("VRCUdonUdonBehaviour", "VRCUdonCommonInterfacesIUdonEventReceiver"); methodName = $"__{methodName}"; var parameters = Parameters; string paramStr = ""; if (parameters.Length > 0) { paramStr = "_"; // Arg separator foreach (ParameterSymbol parameter in parameters) { paramStr += $"_{CompilerUdonInterface.GetUdonTypeName(parameter.Type)}"; } } else if (IsConstructor) { paramStr = "__"; } string returnStr; if (!IsConstructor) { returnStr = ReturnType != null ? $"__{CompilerUdonInterface.GetUdonTypeName(ReturnType)}" : "__SystemVoid"; } else { returnStr = $"__{CompilerUdonInterface.GetUdonTypeName(containingType)}"; } string finalFunctionSig = $"{functionNamespace}.{methodName}{paramStr}{returnStr}"; return(finalFunctionSig); }
public ModuleBinding[] LoadSyntaxTreesAndCreateModules(IEnumerable <string> sourcePaths, string[] scriptingDefines) { ConcurrentBag <ModuleBinding> syntaxTrees = new ConcurrentBag <ModuleBinding>(); Parallel.ForEach(sourcePaths, (currentSource) => { string programSource = UdonSharpUtils.ReadFileTextSync(currentSource); var programSyntaxTree = CSharpSyntaxTree.ParseText(programSource, CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None).WithPreprocessorSymbols(scriptingDefines).WithLanguageVersion(LanguageVersion.CSharp7_3)); syntaxTrees.Add(new ModuleBinding() { tree = programSyntaxTree, filePath = currentSource, sourceText = programSource }); }); ModuleBindings = syntaxTrees.ToArray(); return(ModuleBindings); }
private string GetSignature(AbstractPhaseContext context) { System.Type methodSourceType = ContainingType.UdonType.SystemType; methodSourceType = UdonSharpUtils.RemapBaseType(methodSourceType); if (methodSourceType == typeof(string) && (Parameters[0].Type.UdonType.SystemType == typeof(object) || Parameters[1].Type.UdonType.SystemType == typeof(object))) { return("SystemString.__Concat__SystemObject_SystemObject__SystemString"); } string functionNamespace = CompilerUdonInterface.SanitizeTypeName(methodSourceType.FullName ?? methodSourceType.Namespace + methodSourceType.Name); string methodName = $"__{GetOperatorUdonName().Trim('_').TrimStart('.')}"; var parameters = RoslynSymbol.Parameters; string paramStr = "_"; // Arg separator if (parameters.Length > 1 || methodName.Contains("UnaryMinus") || methodName.Contains("UnaryNegation")) // Binary operators { foreach (IParameterSymbol parameter in parameters) { paramStr += $"_{CompilerUdonInterface.GetUdonTypeName(context.GetTypeSymbol(parameter.Type))}"; } } else // Unary operators, we just use the regular binary operator internally and handle it in the bound operator { paramStr += $"_{CompilerUdonInterface.GetUdonTypeName(context.GetTypeSymbol(parameters[0].Type))}"; paramStr += $"_{CompilerUdonInterface.GetUdonTypeName(context.GetTypeSymbol(parameters[0].Type))}"; } string returnStr = $"__{CompilerUdonInterface.GetUdonTypeName(ReturnType)}"; return($"{functionNamespace}.{methodName}{paramStr}{returnStr}"); }
void ConvertToUdonArrayElement(ref object targetElement, object elementValue, System.Type cSharpType) { if (elementValue == null) { targetElement = null; return; } if (UdonSharpUtils.IsUserJaggedArray(cSharpType)) { Array targetArray = (Array)targetElement; Array sourceArray = (Array)elementValue; if (targetArray == null || targetArray.Length != sourceArray.Length) { targetElement = targetArray = (Array)Activator.CreateInstance(UdonSharpUtils.UserTypeToUdonType(cSharpType), new object[] { sourceArray.Length }); } for (int i = 0; i < sourceArray.Length; ++i) { object elementVal = targetArray.GetValue(i); ConvertToUdonArrayElement(ref elementVal, sourceArray.GetValue(i), cSharpType.GetElementType()); targetArray.SetValue(elementVal, i); } } else if (cSharpType.IsArray) { IValueStorage innerArrayValueStorage = GetInnerValueStorage(); innerArrayValueStorage.Value = targetElement; rootArraySerializer.WriteWeak(innerArrayValueStorage, elementValue); targetElement = innerArrayValueStorage.Value; innerValueStorages.Push(innerArrayValueStorage); } else { throw new Exception("Jagged array serializer requires a root array serializer"); } }
private List <System.Type> GetTypeArgumentList(TypeArgumentListSyntax typeArgumentList) { UpdateSyntaxNode(typeArgumentList); List <System.Type> argumentTypes = new List <System.Type>(); foreach (TypeSyntax typeSyntax in typeArgumentList.Arguments) { using (ExpressionCaptureScope typeCaptureScope = new ExpressionCaptureScope(visitorContext, null)) { Visit(typeSyntax); if (!typeCaptureScope.IsType()) { throw new System.ArgumentException("Generic argument must be a valid type"); } argumentTypes.Add(UdonSharpUtils.RemapBaseType(typeCaptureScope.captureType)); } } return(argumentTypes); }
private static bool ValidateUdonSharpBehaviours(UdonSharpProgramAsset[] allProgramAssets, HashSet<string> allSourcePaths) { bool succeeded = true; foreach (var programAsset in allProgramAssets) { if (programAsset.sourceCsScript == null) continue; string sourcePath = AssetDatabase.GetAssetPath(programAsset.sourceCsScript); if (string.IsNullOrEmpty(sourcePath)) continue; if (!allSourcePaths.Contains(sourcePath)) { succeeded = false; UdonSharpUtils.LogError($"Script '{sourcePath}' does not belong to a U# assembly, have you made a U# assembly definition for the assembly the script is a part of?", programAsset.sourceCsScript); } } return succeeded; }
private void VerifySyncValidForType(System.Type typeToSync, UdonSyncMode syncMode) { if (syncMode == UdonSyncMode.NotSynced) { return; } #if UDON_BETA_SDK if (!VRC.Udon.UdonNetworkTypes.CanSync(typeToSync)) { throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } else if (syncMode == UdonSyncMode.Linear && !VRC.Udon.UdonNetworkTypes.CanSyncLinear(typeToSync)) { throw new System.NotSupportedException($"Udon does not support linear interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } else if (syncMode == UdonSyncMode.Smooth && !VRC.Udon.UdonNetworkTypes.CanSyncSmooth(typeToSync)) { throw new System.NotSupportedException($"Udon does not support smooth interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Manual && syncMode != UdonSyncMode.None) { throw new System.NotSupportedException($"Udon does not support variable tweening when the behaviour is in Manual sync mode"); } #else if (!UdonSharpUtils.IsUdonSyncedType(typeToSync)) { throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } if (syncMode != UdonSyncMode.None && (typeToSync == typeof(string) || typeToSync == typeof(char))) { throw new System.NotSupportedException($"Udon does not support tweening the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } #endif }
protected void VerifySyncValidForType(System.Type typeToSync, UdonSyncMode syncMode) { if (syncMode == UdonSyncMode.NotSynced) { return; } if (visitorContext.behaviourSyncMode == BehaviourSyncMode.NoVariableSync) { throw new System.Exception($"Cannot sync variable because behaviour is set to NoVariableSync, change the behaviour sync mode to sync variables"); } if (!VRC.Udon.UdonNetworkTypes.CanSync(typeToSync) && typeToSync != typeof(uint) && typeToSync != typeof(uint[])) // Workaround for the uint types missing from the syncable type list >_> { throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } else if (syncMode == UdonSyncMode.Linear && !VRC.Udon.UdonNetworkTypes.CanSyncLinear(typeToSync)) { throw new System.NotSupportedException($"Udon does not support linear interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } else if (syncMode == UdonSyncMode.Smooth && !VRC.Udon.UdonNetworkTypes.CanSyncSmooth(typeToSync)) { throw new System.NotSupportedException($"Udon does not support smooth interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'"); } if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Manual && syncMode != UdonSyncMode.None) { throw new System.NotSupportedException($"Udon does not support variable tweening when the behaviour is in Manual sync mode"); } else if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Continuous && typeToSync.IsArray) { throw new System.NotSupportedException($"Syncing of array type {UdonSharpUtils.PrettifyTypeName(typeToSync.GetElementType())}[] is only supported in manual sync mode"); } }
static void InjectUnityEventInterceptors() { List <System.Type> udonSharpBehaviourTypes = new List <Type>(); foreach (Assembly assembly in UdonSharpUtils.GetLoadedEditorAssemblies()) { foreach (System.Type type in assembly.GetTypes()) { if (type != typeof(UdonSharpBehaviour) && type.IsSubclassOf(typeof(UdonSharpBehaviour))) { udonSharpBehaviourTypes.Add(type); } } } const string harmonyID = "UdonSharp.Editor.EventPatch"; Harmony harmony = new Harmony(harmonyID); harmony.UnpatchAll(harmonyID); MethodInfo injectedEvent = typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.EventInterceptor), BindingFlags.Static | BindingFlags.Public); HarmonyMethod injectedMethod = new HarmonyMethod(injectedEvent); void InjectEvent(System.Type behaviourType, string eventName) { const BindingFlags eventBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; MethodInfo eventInfo = behaviourType.GetMethods(eventBindingFlags).FirstOrDefault(e => e.Name == eventName && e.ReturnType == typeof(void)); try { if (eventInfo != null) { harmony.Patch(eventInfo, injectedMethod); } } catch (System.Exception) { Debug.LogWarning($"Failed to patch event {eventInfo} on {behaviourType}"); } } foreach (System.Type udonSharpBehaviourType in udonSharpBehaviourTypes) { // Trigger events InjectEvent(udonSharpBehaviourType, "OnTriggerEnter"); InjectEvent(udonSharpBehaviourType, "OnTriggerExit"); InjectEvent(udonSharpBehaviourType, "OnTriggerStay"); InjectEvent(udonSharpBehaviourType, "OnTriggerEnter2D"); InjectEvent(udonSharpBehaviourType, "OnTriggerExit2D"); InjectEvent(udonSharpBehaviourType, "OnTriggerStay2D"); // Collision events InjectEvent(udonSharpBehaviourType, "OnCollisionEnter"); InjectEvent(udonSharpBehaviourType, "OnCollisionExit"); InjectEvent(udonSharpBehaviourType, "OnCollisionStay"); InjectEvent(udonSharpBehaviourType, "OnCollisionEnter2D"); InjectEvent(udonSharpBehaviourType, "OnCollisionExit2D"); InjectEvent(udonSharpBehaviourType, "OnCollisionStay2D"); // Controller InjectEvent(udonSharpBehaviourType, "OnControllerColliderHit"); // Animator events InjectEvent(udonSharpBehaviourType, "OnAnimatorIK"); InjectEvent(udonSharpBehaviourType, "OnAnimatorMove"); // Mouse events InjectEvent(udonSharpBehaviourType, "OnMouseDown"); InjectEvent(udonSharpBehaviourType, "OnMouseDrag"); InjectEvent(udonSharpBehaviourType, "OnMouseEnter"); InjectEvent(udonSharpBehaviourType, "OnMouseExit"); InjectEvent(udonSharpBehaviourType, "OnMouseOver"); InjectEvent(udonSharpBehaviourType, "OnMouseUp"); InjectEvent(udonSharpBehaviourType, "OnMouseUpAsButton"); // Particle events InjectEvent(udonSharpBehaviourType, "OnParticleCollision"); InjectEvent(udonSharpBehaviourType, "OnParticleSystemStopped"); InjectEvent(udonSharpBehaviourType, "OnParticleTrigger"); InjectEvent(udonSharpBehaviourType, "OnParticleUpdateJobScheduled"); // Rendering events InjectEvent(udonSharpBehaviourType, "OnPostRender"); InjectEvent(udonSharpBehaviourType, "OnPreCull"); InjectEvent(udonSharpBehaviourType, "OnPreRender"); InjectEvent(udonSharpBehaviourType, "OnRenderImage"); InjectEvent(udonSharpBehaviourType, "OnRenderObject"); InjectEvent(udonSharpBehaviourType, "OnWillRenderObject"); // Joint events InjectEvent(udonSharpBehaviourType, "OnJointBreak"); InjectEvent(udonSharpBehaviourType, "OnJointBreak2D"); // Audio InjectEvent(udonSharpBehaviourType, "OnAudioFilterRead"); // Transforms InjectEvent(udonSharpBehaviourType, "OnTransformChildrenChanged"); InjectEvent(udonSharpBehaviourType, "OnTransformParentChanged"); // Object state, OnDisable and OnDestroy will get called regardless of the enabled state of the component, include OnEnable for consistency InjectEvent(udonSharpBehaviourType, "OnEnable"); InjectEvent(udonSharpBehaviourType, "OnDisable"); InjectEvent(udonSharpBehaviourType, "OnDestroy"); } // Add method for checking if events need to be skipped InjectedMethods.shouldSkipEventsMethod = (Func <bool>)Delegate.CreateDelegate(typeof(Func <bool>), typeof(UdonSharpBehaviour).GetMethod("ShouldSkipEvents", BindingFlags.Static | BindingFlags.NonPublic)); // Patch GUI object field drawer MethodInfo doObjectFieldMethod = typeof(EditorGUI).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(e => e.Name == "DoObjectField" && e.GetParameters().Length == 9); HarmonyMethod objectFieldProxy = new HarmonyMethod(typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.DoObjectFieldProxy))); harmony.Patch(doObjectFieldMethod, objectFieldProxy); System.Type validatorDelegateType = typeof(EditorGUI).GetNestedType("ObjectFieldValidator", BindingFlags.Static | BindingFlags.NonPublic); InjectedMethods.validationDelegate = Delegate.CreateDelegate(validatorDelegateType, typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.ValidateObjectReference))); InjectedMethods.objectValidatorMethod = typeof(EditorGUI).GetMethod("ValidateObjectReferenceValue", BindingFlags.NonPublic | BindingFlags.Static); MethodInfo crossSceneRefCheckMethod = typeof(EditorGUI).GetMethod("CheckForCrossSceneReferencing", BindingFlags.NonPublic | BindingFlags.Static); InjectedMethods.crossSceneRefCheckMethod = (Func <UnityEngine.Object, UnityEngine.Object, bool>)Delegate.CreateDelegate(typeof(Func <UnityEngine.Object, UnityEngine.Object, bool>), crossSceneRefCheckMethod); // Patch post BuildAssetBundles fixup function MethodInfo buildAssetbundlesMethod = typeof(BuildPipeline).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).First(e => e.Name == "BuildAssetBundles" && e.GetParameters().Length == 5); MethodInfo postBuildMethod = typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.PostBuildAssetBundles), BindingFlags.Public | BindingFlags.Static); HarmonyMethod postBuildHarmonyMethod = new HarmonyMethod(postBuildMethod); MethodInfo preBuildMethod = typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.PreBuildAssetBundles), BindingFlags.Public | BindingFlags.Static); HarmonyMethod preBuildHarmonyMethod = new HarmonyMethod(preBuildMethod); harmony.Patch(buildAssetbundlesMethod, preBuildHarmonyMethod, postBuildHarmonyMethod); }
public void AddCopy(string comment = "") { AppendCommentedLine("COPY", comment); programCounter += UdonSharpUtils.GetUdonInstructionSize("COPY"); }
public void AddJumpIndirect(SymbolDefinition addressSymbol, string comment = "") { AppendCommentedLine($"JUMP_INDIRECT, {addressSymbol.symbolUniqueName}", comment); programCounter += UdonSharpUtils.GetUdonInstructionSize("JUMP_INDIRECT"); }
private void AddPush(string heapAddress, string comment) { AppendCommentedLine($"PUSH, {heapAddress}", comment); programCounter += UdonSharpUtils.GetUdonInstructionSize("PUSH"); }
public void AddJumpToExit() { AppendCommentedLine($"JUMP, 0xFFFFFFFF", ""); programCounter += UdonSharpUtils.GetUdonInstructionSize("JUMP"); }