using System; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; using UnityEngine; namespace AOT.Editor.HybridCLR { /// Limit native WebGL build workers without changing player optimizations. [InitializeOnLoad] public sealed class WebGlBuildConcurrency : IPreprocessBuildWithReport, IPostprocessBuildWithReport { const string BeeVariable = "BEE_BUILD_THREADS"; const string BinaryenVariable = "BINARYEN_CORES"; const string WorkerLimit = "4"; static bool ownsBee; static bool ownsBinaryen; public int callbackOrder => int.MinValue; static WebGlBuildConcurrency() { // Postprocess callbacks may be skipped when the native build fails. EditorApplication.update += RestoreWhenIdle; AssemblyReloadEvents.beforeAssemblyReload += Restore; } public void OnPreprocessBuild(BuildReport report) { if (Application.platform != RuntimePlatform.WindowsEditor || report.summary.platform != BuildTarget.WebGL) return; ownsBee |= SetDefault(BeeVariable); ownsBinaryen |= SetDefault(BinaryenVariable); Debug.Log($"[WebGlBuildConcurrency] {BeeVariable}={Environment.GetEnvironmentVariable(BeeVariable)}, " + $"{BinaryenVariable}={Environment.GetEnvironmentVariable(BinaryenVariable)}"); } public void OnPostprocessBuild(BuildReport report) => Restore(); static bool SetDefault(string variable) { // Respect explicit values supplied by the developer or build machine. if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable))) return false; Environment.SetEnvironmentVariable(variable, WorkerLimit); return true; } static void RestoreWhenIdle() { if (!BuildPipeline.isBuildingPlayer) Restore(); } static void Restore() { RestoreVariable(BeeVariable, ref ownsBee); RestoreVariable(BinaryenVariable, ref ownsBinaryen); } static void RestoreVariable(string variable, ref bool owned) { if (!owned) return; if (Environment.GetEnvironmentVariable(variable) == WorkerLimit) Environment.SetEnvironmentVariable(variable, null); owned = false; } } }