using UdonSharp;
using UnityEditor;
using UnityEngine;
namespace AUMSS.EditorTools
{
///
/// Makes sure AUMSS's U# programs are compiled. The package ships them uncompiled, and U# only compiles when a
/// script's source differs from what it last compiled: after an update that changes no script, the programs
/// would stay uncompiled, and editor code (U#'s own, or a world's tools) couldn't write to AUMSS components.
/// So they're checked whenever the editor loads, and whenever the package's program assets are reimported (an
/// update while the editor is open, which reloads nothing if no script changed).
///
[InitializeOnLoad]
public static class AUMSSProgramCheck
{
const string PackagePath = "Packages/dev.av2x.aumss/";
static AUMSSProgramCheck()
{
EditorApplication.delayCall += CheckOnLoad;
}
class ImportCheck : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFrom)
{
foreach (string path in imported)
{
if (!path.StartsWith(PackagePath) || !path.EndsWith(".asset")) continue;
// U#'s own compile saves these too; by then they're compiled, so the check does nothing
EditorApplication.delayCall -= CheckOnLoad;
EditorApplication.delayCall += CheckOnLoad;
return;
}
}
}
static void CheckOnLoad()
{
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
if (EditorApplication.isCompiling || EditorApplication.isUpdating)
{
EditorApplication.delayCall += CheckOnLoad;
return;
}
// U# can't compile while C# has errors; it gets compiled once they're fixed (a script change, so U# does)
if (EditorUtility.scriptCompilationFailed || !NeedsCompile()) return;
Debug.Log("[AUMSS] Compiling UdonSharp programs: the package's arrived uncompiled.");
UdonSharpProgramAsset.CompileAllCsPrograms(forceCompile: true);
}
/// True if any of the package's U# programs hasn't been compiled yet.
public static bool NeedsCompile()
{
foreach (UdonSharpProgramAsset program in UdonSharpProgramAsset.GetAllUdonSharpPrograms())
{
if (program == null || program.sourceCsScript == null) continue;
if (!AssetDatabase.GetAssetPath(program).StartsWith(PackagePath)) continue;
if (!IsCompiled(program)) return true;
}
return false;
}
static bool IsCompiled(UdonSharpProgramAsset program)
{
// The field definitions alone aren't enough: reimporting an uncompiled program (an update while the editor is
// open) clears its compiled program but leaves the field definitions from before in memory
if (program.fieldDefinitions == null) return false;
using (var serialized = new SerializedObject(program))
return serialized.FindProperty("serializedUdonProgramAsset")?.objectReferenceValue != null;
}
}
}