Skip to content

Instantly share code, notes, and snippets.

@Kainkun
Forked from JavadocMD/CompileIndicator.cs
Last active July 21, 2025 21:15
Show Gist options
  • Save Kainkun/9184d5e42ca26734e5889b8754edb5b2 to your computer and use it in GitHub Desktop.
Save Kainkun/9184d5e42ca26734e5889b8754edb5b2 to your computer and use it in GitHub Desktop.
A Unity script to play a sound effect when script compiling starts and ends.
#if UNITY_EDITOR
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Editor
{
[InitializeOnLoad]
public static class CompileIndicator
{
private const string DefaultStartPath = "Assets/YOUR_START_AUDIO_PATH_HERE";
private const string DefaultEndPath = "Assets/YOUR_END_AUDIO_PATH_HERE";
private const string MenuRoot = "Tools/Compile Indicator";
private const string CompileStateKey = "CompileIndicator.WasCompiling";
private const string StartSoundPathKey = "CompileIndicator.StartSoundPath";
private const string EndSoundPathKey = "CompileIndicator.EndSoundPath";
private const string EnableStartSoundKey = "CompileIndicator.EnableStartSound";
private const string EnableEndSoundKey = "CompileIndicator.EnableEndSound";
private static AudioClip _startClip;
private static AudioClip _endClip;
static CompileIndicator()
{
InitializePrefsOnce();
EditorApplication.update += OnUpdate;
LoadClips();
}
private static void InitializePrefsOnce()
{
if (!PlayerPrefs.HasKey(StartSoundPathKey))
PlayerPrefs.SetString(StartSoundPathKey, DefaultStartPath);
if (!PlayerPrefs.HasKey(EndSoundPathKey))
PlayerPrefs.SetString(EndSoundPathKey, DefaultEndPath);
if (!PlayerPrefs.HasKey(EnableStartSoundKey))
PlayerPrefs.SetInt(EnableStartSoundKey, 1);
if (!PlayerPrefs.HasKey(EnableEndSoundKey))
PlayerPrefs.SetInt(EnableEndSoundKey, 1);
}
private static void OnUpdate()
{
bool wasCompiling = PlayerPrefs.GetInt(CompileStateKey, 0) == 1;
bool isCompiling = EditorApplication.isCompiling;
if (wasCompiling == isCompiling)
return;
switch (isCompiling)
{
case true when GetBool(EnableStartSoundKey):
PlayClip(_startClip);
break;
case false when GetBool(EnableEndSoundKey):
PlayClip(_endClip);
break;
}
SetBool(CompileStateKey, isCompiling);
}
private static void PlayClip(AudioClip clip, int startSample = 0, bool loop = false)
{
if (clip == null) return;
try
{
var unityEditorAssembly = typeof(AudioImporter).Assembly;
var audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
var method = audioUtilClass?.GetMethod("PlayPreviewClip",
BindingFlags.Static | BindingFlags.Public,
null,
new[] { typeof(AudioClip), typeof(int), typeof(bool) },
null);
method?.Invoke(null, new object[] { clip, startSample, loop });
}
catch (Exception e)
{
Debug.LogWarning("CompileIndicator: Failed to play clip.\n" + e);
}
}
private static void LoadClips()
{
_startClip = AssetDatabase.LoadAssetAtPath<AudioClip>(PlayerPrefs.GetString(StartSoundPathKey,
DefaultStartPath));
_endClip = AssetDatabase.LoadAssetAtPath<AudioClip>(PlayerPrefs.GetString(EndSoundPathKey, DefaultEndPath));
}
private static string GetRelativeAssetPath(string fullPath)
{
string assetsPath = Application.dataPath;
if (fullPath.StartsWith(assetsPath))
{
return "Assets" + fullPath.Substring(assetsPath.Length).Replace("\\", "/");
}
Debug.LogWarning("CompileIndicator: Selected file is not inside the Assets folder.");
return "";
}
// ==== Menu Items ====
[MenuItem(MenuRoot + "/Enable Start Sound", priority = 0)]
private static void ToggleStartSound()
{
bool newState = !GetBool(EnableStartSoundKey);
SetBool(EnableStartSoundKey, newState);
Debug.LogFormat("CompileIndicator: Start sound {0}.", newState ? "enabled" : "disabled");
}
[MenuItem(MenuRoot + "/Enable Start Sound", true)]
private static bool ToggleStartSoundValidate()
{
Menu.SetChecked(MenuRoot + "/Enable Start Sound", GetBool(EnableStartSoundKey));
return true;
}
[MenuItem(MenuRoot + "/Enable End Sound", priority = 1)]
private static void ToggleEndSound()
{
bool newState = !GetBool(EnableEndSoundKey);
SetBool(EnableEndSoundKey, newState);
Debug.LogFormat("CompileIndicator: End sound {0}.", newState ? "enabled" : "disabled");
}
[MenuItem(MenuRoot + "/Enable End Sound", true)]
private static bool ToggleEndSoundValidate()
{
Menu.SetChecked(MenuRoot + "/Enable End Sound", GetBool(EnableEndSoundKey));
return true;
}
[MenuItem(MenuRoot + "/Set Start Sound...", priority = 50)]
private static void SetStartSound()
{
string path = EditorUtility.OpenFilePanel("Select Start Sound", "Assets", "wav,mp3,aiff");
if (!string.IsNullOrEmpty(path))
{
string relativePath = GetRelativeAssetPath(path);
if (string.IsNullOrEmpty(relativePath)) return;
PlayerPrefs.SetString(StartSoundPathKey, relativePath);
_startClip = AssetDatabase.LoadAssetAtPath<AudioClip>(relativePath);
Debug.LogFormat("CompileIndicator: Start sound set to: {0}", relativePath);
}
else
{
Debug.Log("CompileIndicator: Start sound selection canceled.");
}
}
[MenuItem(MenuRoot + "/Set End Sound...", priority = 51)]
private static void SetEndSound()
{
string path = EditorUtility.OpenFilePanel("Select End Sound", "Assets", "wav,mp3,aiff");
if (!string.IsNullOrEmpty(path))
{
string relativePath = GetRelativeAssetPath(path);
if (string.IsNullOrEmpty(relativePath)) return;
PlayerPrefs.SetString(EndSoundPathKey, relativePath);
_endClip = AssetDatabase.LoadAssetAtPath<AudioClip>(relativePath);
Debug.LogFormat("CompileIndicator: End sound set to: {0}", relativePath);
}
else
{
Debug.Log("CompileIndicator: End sound selection canceled.");
}
}
[MenuItem(MenuRoot + "/Reset to Defaults", priority = 100)]
private static void ResetToDefaults()
{
if (EditorUtility.DisplayDialog("Reset Compile Indicator",
"Are you sure you want to reset to default settings?", "Yes", "Cancel"))
{
PlayerPrefs.SetString(StartSoundPathKey, DefaultStartPath);
PlayerPrefs.SetString(EndSoundPathKey, DefaultEndPath);
SetBool(EnableStartSoundKey, true);
SetBool(EnableEndSoundKey, true);
LoadClips();
Debug.Log("CompileIndicator: Settings reset to defaults.");
}
else
{
Debug.Log("CompileIndicator: Reset to defaults canceled.");
}
}
// ==== PlayerPrefs Helpers ====
private static bool GetBool(string key) => PlayerPrefs.GetInt(key, 0) == 1;
private static void SetBool(string key, bool value) =>
PlayerPrefs.SetInt(key, value ? 1 : 0);
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment