Beispiel #1
0
        /// <summary>
        /// Deletes an UdonSharp program asset and the serialized program asset associated with it
        /// </summary>
        /// <param name="programAsset"></param>
        public static void DeleteProgramAsset(UdonSharpProgramAsset programAsset)
        {
            if (programAsset == null)
            {
                return;
            }

            AbstractSerializedUdonProgramAsset serializedAsset = programAsset.GetSerializedUdonProgramAsset();

            if (serializedAsset != null)
            {
                string assetPath = AssetDatabase.GetAssetPath(serializedAsset);
                serializedAsset = AssetDatabase.LoadAssetAtPath <AbstractSerializedUdonProgramAsset>(assetPath);

                if (serializedAsset != null)
                {
                    AssetDatabase.DeleteAsset(assetPath);
                }
            }

            string programAssetPath = AssetDatabase.GetAssetPath(programAsset);

            programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(programAssetPath);

            if (programAsset != null)
            {
                AssetDatabase.DeleteAsset(programAssetPath);
            }
        }
Beispiel #2
0
        public bool IsSourceFileDirty(UdonSharpProgramAsset programAsset)
        {
            if (programAsset?.sourceCsScript == null)
            {
                return(false);
            }

            if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(programAsset, out string programAssetGuid, out long _))
            {
                return(false);
            }

            // We haven't seen the source file before, so it needs to be compiled
            if (!sourceFileHashLookup.TryGetValue(programAssetGuid, out string sourceFileHash))
            {
                return(true);
            }

            string currentHash = HashSourceFile(programAsset.sourceCsScript);

            if (currentHash != sourceFileHash)
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Creates a new UdonAssemblyProgramAsset from an UdonSharpProgramAsset for the sake of portability. Most info used for the inspector gets stripped so this isn't a great solution for remotely complex assets.
        /// </summary>
        /// <param name="udonSharpProgramAsset">The source program asset</param>
        /// <param name="savePath">The save path for the asset file. Save path is only needed here because Udon needs a GUID for saving the serialized program asset and it'd be a pain to break that requirement at the moment</param>
        /// <returns>The exported UdonAssemblyProgramAsset</returns>
        public static UdonAssemblyProgramAsset UdonSharpProgramToAssemblyProgram(UdonSharpProgramAsset udonSharpProgramAsset, string savePath)
        {
            if (EditorApplication.isPlaying)
            {
                throw new System.NotSupportedException("UdonSharpEditorUtility.UdonSharpProgramToAssemblyProgram() cannot be called in play mode");
            }

            UdonAssemblyProgramAsset newProgramAsset = ScriptableObject.CreateInstance <UdonAssemblyProgramAsset>();

            AssetDatabase.CreateAsset(newProgramAsset, savePath);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);

            newProgramAsset = AssetDatabase.LoadAssetAtPath <UdonAssemblyProgramAsset>(savePath);

            FieldInfo assemblyField = typeof(UdonAssemblyProgramAsset).GetField("udonAssembly", BindingFlags.NonPublic | BindingFlags.Instance);

            udonSharpProgramAsset.CompileCsProgram();

            assemblyField.SetValue(newProgramAsset, assemblyField.GetValue(udonSharpProgramAsset));

            MethodInfo assembleMethod = typeof(UdonAssemblyProgramAsset).GetMethod("AssembleProgram", BindingFlags.NonPublic | BindingFlags.Instance);

            assembleMethod.Invoke(newProgramAsset, new object[] { });

            IUdonProgram uSharpProgram         = udonSharpProgramAsset.GetRealProgram();
            FieldInfo    assemblyProgramGetter = typeof(UdonProgramAsset).GetField("program", BindingFlags.NonPublic | BindingFlags.Instance);
            IUdonProgram assemblyProgram       = (IUdonProgram)assemblyProgramGetter.GetValue(newProgramAsset);

            if (uSharpProgram == null || assemblyProgram == null)
            {
                return(null);
            }

            string[] symbols = uSharpProgram.SymbolTable.GetSymbols();

            foreach (string symbol in symbols)
            {
                uint        symbolAddress = uSharpProgram.SymbolTable.GetAddressFromSymbol(symbol);
                System.Type symbolType    = uSharpProgram.Heap.GetHeapVariableType(symbolAddress);
                object      symbolValue   = uSharpProgram.Heap.GetHeapVariable(symbolAddress);

                assemblyProgram.Heap.SetHeapVariable(assemblyProgram.SymbolTable.GetAddressFromSymbol(symbol), symbolValue, symbolType);
            }

            EditorUtility.SetDirty(newProgramAsset);

            newProgramAsset.SerializedProgramAsset.StoreProgram(assemblyProgram);
            EditorUtility.SetDirty(newProgramAsset.SerializedProgramAsset);

            AssetDatabase.SaveAssets();

            // This doesn't work unfortunately due to how Udon tries to locate the serialized asset when importing an assembly
            //string serializedAssetPath = $"{Path.GetDirectoryName(savePath)}/{Path.GetFileNameWithoutExtension(savePath)}_serialized.asset";

            //AssetDatabase.MoveAsset(AssetDatabase.GetAssetPath(newProgramAsset.SerializedProgramAsset), serializedAssetPath);
            //AssetDatabase.SaveAssets();

            return(newProgramAsset);
        }
Beispiel #4
0
        public void UpdateSourceHash(UdonSharpProgramAsset programAsset, string sourceText)
        {
            if (programAsset?.sourceCsScript == null)
            {
                return;
            }

            if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(programAsset, out string programAssetGuid, out long _))
            {
                return;
            }

            string newHash = UdonSharpUtils.HashString(sourceText);

            if (sourceFileHashLookup.ContainsKey(programAssetGuid))
            {
                if (sourceFileHashLookup[programAssetGuid] != newHash)
                {
                    _sourceDirty = true;
                }

                sourceFileHashLookup[programAssetGuid] = newHash;
            }
            else
            {
                sourceFileHashLookup.Add(programAssetGuid, newHash);
                _sourceDirty = true;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Clears the source hash, this is used when a script hits a compile error in order to allow an undo to compile the scripts.
        /// </summary>
        /// <param name="programAsset"></param>
        public void ClearSourceHash(UdonSharpProgramAsset programAsset)
        {
            if (programAsset?.sourceCsScript == null)
            {
                return;
            }

            if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(programAsset, out string programAssetGuid, out long _))
            {
                return;
            }

            if (sourceFileHashLookup.ContainsKey(programAssetGuid))
            {
                if (sourceFileHashLookup[programAssetGuid] != "")
                {
                    _sourceDirty = true;
                }

                sourceFileHashLookup[programAssetGuid] = "";
            }
            else
            {
                sourceFileHashLookup.Add(programAssetGuid, "");
                _sourceDirty = true;
            }
        }
Beispiel #6
0
            public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions options)
            {
                UdonSharpProgramAsset programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(assetPath);

                if (programAsset)
                {
                    Instance.ClearSourceHash(programAsset);
                }
                else if (AssetDatabase.IsValidFolder(assetPath))
                {
                    string[] assetGuids = AssetDatabase.FindAssets($"t:{nameof(UdonSharpProgramAsset)}", new string[] { assetPath });

                    foreach (string guid in assetGuids)
                    {
                        programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(guid));

                        if (programAsset)
                        {
                            Instance.ClearSourceHash(programAsset);
                        }
                    }
                }

                return(AssetDeleteResult.DidNotDelete);
            }
        static void PlayModeErrorCheck(PlayModeStateChange state)
        {
            // Prevent people from entering play mode when there are compile errors, like normal Unity C#
            if (state == PlayModeStateChange.EnteredPlayMode || state == PlayModeStateChange.ExitingEditMode)
            {
                string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

                bool foundCompileErrors = false;

                foreach (string dataGuid in udonSharpDataAssets)
                {
                    UdonSharpProgramAsset programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid));

                    if (programAsset.sourceCsScript != null && programAsset.compileErrors.Count > 0)
                    {
                        foundCompileErrors = true;
                        break;
                    }
                }

                if (foundCompileErrors)
                {
                    EditorApplication.isPlaying = false;

                    typeof(SceneView).GetMethod("ShowNotification", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, new object[] { "All U# compile errors have to be fixed before you can enter playmode!" });
                }
            }
        }
Beispiel #8
0
        static void PlayModeErrorCheck(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)
            {
                string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

                bool foundCompileErrors = false;

                foreach (string dataGuid in udonSharpDataAssets)
                {
                    UdonSharpProgramAsset programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid));

                    if (programAsset.sourceCsScript != null && programAsset.compileErrors.Count > 0)
                    {
                        foundCompileErrors = true;
                        break;
                    }
                }

                if (foundCompileErrors)
                {
                    EditorApplication.isPlaying = false;

                    typeof(SceneView).GetMethod("ShowNotification", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, new object[] { "All U# compile errors have to be fixed before you can enter playmode!" });
                }
            }
        }
 public CompilationModule(UdonSharpProgramAsset sourceAsset)
 {
     programAsset           = sourceAsset;
     resolver               = new ResolverContext();
     moduleSymbols          = new SymbolTable(resolver, null);
     moduleLabels           = new LabelTable();
     fieldsWithInitializers = new HashSet <FieldDeclarationSyntax>();
 }
        static void HandleScriptModifications()
        {
            UdonSharpSettings settings = UdonSharpSettings.GetSettings();

            if (settings != null)
            {
                if (!settings.autoCompileOnModify)
                {
                    modifiedScripts.Clear();
                    return;
                }

                if (settings.waitForFocus && !UnityEditorInternal.InternalEditorUtility.isApplicationActive)
                {
                    return;
                }
            }

            if (modifiedScripts.Count == 0)
            {
                return;
            }

            UdonSharpProgramAsset[] udonSharpPrograms = UdonSharpProgramAsset.GetAllUdonSharpPrograms();

            HashSet <UdonSharpProgramAsset> assetsToUpdate = new HashSet <UdonSharpProgramAsset>();

            foreach (MonoScript script in modifiedScripts)
            {
                foreach (UdonSharpProgramAsset programAsset in udonSharpPrograms)
                {
                    if (programAsset.sourceCsScript == script)
                    {
                        assetsToUpdate.Add(programAsset);
                    }
                }
            }

            try
            {
                if (assetsToUpdate.Count > 0)
                {
                    if (settings == null || settings.compileAllScripts)
                    {
                        UdonSharpProgramAsset.CompileAllCsPrograms();
                    }
                    else
                    {
                        UdonSharpCompiler compiler = new UdonSharpCompiler(assetsToUpdate.ToArray());
                        compiler.Compile();
                    }
                }
            }
            finally
            {
                modifiedScripts.Clear();
            }
        }
Beispiel #11
0
        public override void OnInspectorGUI()
        {
            EditorGUILayout.HelpBox("Udon Sharp Behaviours need to be converted to Udon Behaviours to work in game. Click the convert button below to automatically convert the script.", MessageType.Warning);

            if (GUILayout.Button("Convert to UdonBehaviour", GUILayout.Height(25)))
            {
                Undo.RegisterCompleteObjectUndo(targets.Select(e => (e as MonoBehaviour)).Distinct().ToArray(), "Convert to UdonBehaviour");

                foreach (Object targetObject in targets.Distinct())
                {
                    MonoScript            behaviourScript = MonoScript.FromMonoBehaviour(targetObject as MonoBehaviour);
                    UdonSharpProgramAsset programAsset    = GetUdonSharpProgram(behaviourScript);

                    if (programAsset == null)
                    {
                        string scriptPath      = AssetDatabase.GetAssetPath(behaviourScript);
                        string scriptDirectory = Path.GetDirectoryName(scriptPath);
                        string scriptFileName  = Path.GetFileNameWithoutExtension(scriptPath);

                        string assetPath = Path.Combine(scriptDirectory, $"{scriptFileName}.asset").Replace('\\', '/');

                        if (AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(assetPath) != null)
                        {
                            if (!EditorUtility.DisplayDialog("Existing file found", $"Asset file {assetPath} already exists, do you want to overwrite it?", "Ok", "Cancel"))
                            {
                                continue;
                            }
                        }

                        programAsset = ScriptableObject.CreateInstance <UdonSharpProgramAsset>();
                        programAsset.sourceCsScript = behaviourScript;
                        programAsset.CompileCsProgram();

                        AssetDatabase.CreateAsset(programAsset, assetPath);
                        AssetDatabase.SaveAssets();

                        AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
                    }

                    GameObject targetGameObject = (targetObject as MonoBehaviour).gameObject;

                    Undo.DestroyObjectImmediate(targetObject);

                    UdonBehaviour udonBehaviour = targetGameObject.AddComponent <UdonBehaviour>();

                    udonBehaviour.programSource = programAsset;

                    Undo.RegisterCreatedObjectUndo(udonBehaviour, "Convert to UdonBehaviour");
                }

                return;
            }

            EditorGUILayout.Space();

            base.OnInspectorGUI();
        }
Beispiel #12
0
 protected override void RefreshProgramImpl()
 {
     if (sourceCsScript != null &&
         !EditorApplication.isCompiling &&
         !EditorApplication.isUpdating &&
         !UdonSharpProgramAsset.AnyUdonSharpScriptHasError())
     {
         CompileAllCsPrograms(true);
     }
 }
Beispiel #13
0
        private static void CreateUSharpScript()
        {
            string folderPath = "Assets/";

            if (Selection.activeObject != null)
            {
                folderPath = AssetDatabase.GetAssetPath(Selection.activeObject);
                if (Selection.activeObject.GetType() != typeof(UnityEditor.DefaultAsset))
                {
                    folderPath = Path.GetDirectoryName(folderPath);
                }
            }
            else if (Selection.assetGUIDs.Length > 0)
            {
                folderPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
            }

            folderPath = folderPath.Replace('\\', '/');

            string chosenFilePath = EditorUtility.SaveFilePanelInProject("Save UdonSharp File", "", "cs", "Save UdonSharp file", folderPath);

            if (chosenFilePath.Length > 0)
            {
                string chosenFileName = Path.GetFileNameWithoutExtension(chosenFilePath).Replace(" ", "").Replace("#", "Sharp");
                string assetFilePath  = Path.Combine(Path.GetDirectoryName(chosenFilePath), $"{chosenFileName}.asset");

                if (AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(assetFilePath) != null)
                {
                    if (!EditorUtility.DisplayDialog("File already exists", $"Corresponding asset file '{assetFilePath}' already found for new UdonSharp script. Overwrite?", "Ok", "Cancel"))
                    {
                        return;
                    }
                }

                string fileContents = UdonSharpSettings.GetProgramTemplateString(chosenFileName);

                File.WriteAllText(chosenFilePath, fileContents);

                AssetDatabase.ImportAsset(chosenFilePath, ImportAssetOptions.ForceSynchronousImport);
                MonoScript newScript = AssetDatabase.LoadAssetAtPath <MonoScript>(chosenFilePath);

                UdonSharpProgramAsset newProgramAsset = ScriptableObject.CreateInstance <UdonSharpProgramAsset>();
                newProgramAsset.sourceCsScript = newScript;

                AssetDatabase.CreateAsset(newProgramAsset, assetFilePath);

                AssetDatabase.Refresh();
            }
        }
Beispiel #14
0
        private static UdonSharpProgramAsset GetUdonSharpProgram(MonoScript programScript)
        {
            string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

            foreach (string dataGuid in udonSharpDataAssets)
            {
                UdonSharpProgramAsset programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid));

                if (programAsset && programAsset.sourceCsScript == programScript)
                {
                    return(programAsset);
                }
            }

            return(null);
        }
Beispiel #15
0
        static void OnEditorUpdate()
        {
            SetupWatchers();

            // Prevent people from entering play mode when there are compile errors, like normal Unity C#
            if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying)
            {
                string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

                bool foundCompileErrors = false;

                foreach (string dataGuid in udonSharpDataAssets)
                {
                    UdonSharpProgramAsset programAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid));

                    if (programAsset.sourceCsScript != null && programAsset.compileErrors.Count > 0)
                    {
                        foundCompileErrors = true;
                        break;
                    }
                }

                if (foundCompileErrors)
                {
                    EditorApplication.isPlaying = false;

                    typeof(SceneView).GetMethod("ShowNotification", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, new object[] { "All U# compile errors have to be fixed before you can enter playmode!" });
                }
            }

            lock (modifiedFileLock)
            {
                if (modifiedFilePaths.Count > 0)
                {
                    foreach (string filePath in modifiedFilePaths)
                    {
                        MonoScript asset = AssetDatabase.LoadAssetAtPath <MonoScript>(filePath.Replace(Application.dataPath.Replace("/", "\\"), "Assets"));
                        modifiedScripts.Add(asset);
                    }

                    modifiedFilePaths.Clear();
                }
            }

            HandleScriptModifications();
        }
        public CompilationModule(UdonSharpProgramAsset sourceAsset)
        {
            programAsset           = sourceAsset;
            resolver               = new ResolverContext();
            moduleSymbols          = new SymbolTable(resolver, null);
            moduleLabels           = new LabelTable();
            fieldsWithInitializers = new HashSet <FieldDeclarationSyntax>();

            if (programAsset.sourceCsScript == null)
            {
                throw new System.ArgumentException($"Asset '{AssetDatabase.GetAssetPath(programAsset)}' does not have a valid program source to compile from");
            }


            sourceCode = UdonSharpUtils.ReadFileTextSync(AssetDatabase.GetAssetPath(programAsset.sourceCsScript));

            settings = UdonSharpSettings.GetSettings();
        }
        static void HandleScriptModifications(List <MonoScript> scripts)
        {
            UdonSharpSettings settings = UdonSharpSettings.GetSettings();

            if (settings != null && !settings.autoCompileOnModify)
            {
                return;
            }

            string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

            List <UdonSharpProgramAsset> udonSharpPrograms = new List <UdonSharpProgramAsset>();

            foreach (string dataGuid in udonSharpDataAssets)
            {
                udonSharpPrograms.Add(AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid)));
            }

            HashSet <UdonSharpProgramAsset> assetsToUpdate = new HashSet <UdonSharpProgramAsset>();

            foreach (MonoScript script in scripts)
            {
                foreach (UdonSharpProgramAsset programAsset in udonSharpPrograms)
                {
                    if (programAsset.sourceCsScript == script)
                    {
                        assetsToUpdate.Add(programAsset);
                    }
                }
            }

            if (assetsToUpdate.Count > 0)
            {
                if (settings == null || settings.compileAllScripts)
                {
                    UdonSharpProgramAsset.CompileAllCsPrograms();
                }
                else
                {
                    UdonSharpCompiler compiler = new UdonSharpCompiler(assetsToUpdate.ToArray());
                    compiler.Compile();
                }
            }
        }
Beispiel #18
0
        static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
        {
            bool importedUdonSharpAsset = false;

            foreach (string importedAssetPath in importedAssets)
            {
                UdonSharpProgramAsset importedAsset = AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(importedAssetPath);

                if (importedAsset != null)
                {
                    importedUdonSharpAsset = true;
                    break;
                }
            }

            UdonSharpProgramAsset.ClearProgramAssetCache();

            if (importedUdonSharpAsset)
            {
                UdonSharpEditorManager.QueueScriptCompile();
            }
        }
        public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType)
        {
            if (requestedBuildType == VRCSDKRequestedBuildType.Avatar)
            {
                return(true);
            }

            if (UdonSharpSettings.GetSettings()?.disableUploadCompile ?? false)
            {
                return(true);
            }

            UdonSharpProgramAsset.CompileAllCsPrograms(true, false);
            UdonSharpEditorCache.SaveAllCache();

            if (UdonSharpProgramAsset.AnyUdonSharpScriptHasError())
            {
                Debug.LogError("[<color=#FF00FF>UdonSharp</color>] 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);
            }

            return(true);
        }
        static void HandleScriptModifications()
        {
            UdonSharpSettings settings = UdonSharpSettings.GetSettings();

            if (settings != null)
            {
                if (!settings.autoCompileOnModify)
                {
                    modifiedScripts.Clear();
                    return;
                }

                if (settings.waitForFocus && !UnityEditorInternal.InternalEditorUtility.isApplicationActive)
                {
                    return;
                }
            }

            if (modifiedScripts.Count == 0)
            {
                return;
            }

            string[] udonSharpDataAssets = AssetDatabase.FindAssets($"t:{typeof(UdonSharpProgramAsset).Name}");

            List <UdonSharpProgramAsset> udonSharpPrograms = new List <UdonSharpProgramAsset>();

            foreach (string dataGuid in udonSharpDataAssets)
            {
                udonSharpPrograms.Add(AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(AssetDatabase.GUIDToAssetPath(dataGuid)));
            }

            HashSet <UdonSharpProgramAsset> assetsToUpdate = new HashSet <UdonSharpProgramAsset>();

            foreach (MonoScript script in modifiedScripts)
            {
                foreach (UdonSharpProgramAsset programAsset in udonSharpPrograms)
                {
                    if (programAsset.sourceCsScript == script)
                    {
                        assetsToUpdate.Add(programAsset);
                    }
                }
            }

            try
            {
                if (assetsToUpdate.Count > 0)
                {
                    if (settings == null || settings.compileAllScripts)
                    {
                        UdonSharpProgramAsset.CompileAllCsPrograms();
                    }
                    else
                    {
                        UdonSharpCompiler compiler = new UdonSharpCompiler(assetsToUpdate.ToArray());
                        compiler.Compile();
                    }
                }
            }
            finally
            {
                modifiedScripts.Clear();
            }

            modifiedScripts.Clear();
        }
 public UdonSharpCompiler(UdonSharpProgramAsset programAsset)
 {
     modules = new CompilationModule[] { new CompilationModule(programAsset) };
 }