using System; using System.IO; using UnityEngine; using UnityEditor; using UnityEditor.Compilation; using ModTool.Shared; namespace ModTool.Editor.Exporting { /// /// Main class for exporting a project as a mod. /// public class ModExporter : Singleton { /// /// Occurs when the export process is starting. /// public static event Action ExportStarting; /// /// Occurs after the export process is completed. /// public static event Action ExportComplete; /// /// Is this ModExporter currently exporting a Mod? /// public static bool isExporting { get { return instance._isExporting; } } private ExportStep[] exportSteps = new ExportStep[] { new StartExport(), new Verify(), new CreateAssemblies(), new GetContent(), new CreateBackup(), new UpdateAssemblies(), new UpdateAssets(), new Export(), }; [SerializeField] private bool _isExporting; [SerializeField] private int currentStep; [SerializeField] private ExportData data; private bool didReloadScripts; void OnEnable() { EditorApplication.playModeStateChanged += OnPlayModeStateChanged; CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; EditorApplication.update += Update; } void OnDisable() { ExportStarting = null; ExportComplete = null; EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; CompilationPipeline.assemblyCompilationFinished -= OnAssemblyCompilationFinished; EditorApplication.update += Update; } private void OnPlayModeStateChanged(PlayModeStateChange playModeState) { if (!isExporting) return; if (playModeState == PlayModeStateChange.ExitingEditMode) EditorApplication.isPlaying = false; } private void OnAssemblyCompilationFinished(string assemblyName, CompilerMessage[] messages) { if (!isExporting) return; foreach (var message in messages) { if (message.type == CompilerMessageType.Error) { Debug.LogError(message.message + " " + message.file); LogUtility.LogWarning("Export aborted due to compiler error"); StopExport(); return; } } } [UnityEditor.Callbacks.DidReloadScripts] static void OnDidReloadScripts() { instance.didReloadScripts = true; } /// /// Start exporting a Mod. /// public static void ExportMod() { if(isExporting) { LogUtility.LogError("Already exporting"); return; } instance.StartExport(); } private void Update() { if (didReloadScripts) { didReloadScripts = false; Continue(); } } private void StartExport() { data = new ExportData(); LogUtility.LogInfo("Exporting Mod: " + ExportSettings.name); ExportStarting?.Invoke(); _isExporting = true; currentStep = 0; Continue(); } private void Continue() { while (isExporting) { ExportStep step = exportSteps[currentStep]; float progress = (float)currentStep / exportSteps.Length; EditorUtility.DisplayProgressBar("Exporting", step.message + "...", progress); if (ExecuteStep(step)) currentStep++; else StopExport(); if (currentStep == exportSteps.Length) StopExport(); if (step.waitForAssemblyReload) return; } } private bool ExecuteStep(ExportStep step) { LogUtility.LogDebug(step.message); try { step.Execute(data); } catch (Exception e) { Debug.LogError(step.message + " failed: " + e.ToString()); return false; } return true; } private void StopExport() { if (!isExporting) return; _isExporting = false; Restore(); ExportComplete?.Invoke(); EditorUtility.ClearProgressBar(); } private void Restore() { if(!ExecuteStep(new RestoreProject())) Debug.LogWarning("Some assets might be corrupted. A backup has been made in " + Path.Combine(Directory.GetCurrentDirectory(), Asset.backupDirectory)); } } }