-
-
Save justadaniel/d39c5340d77d200dfd13a25f932e2a54 to your computer and use it in GitHub Desktop.
Unity Batch Builder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // DO WHAT THE CRAP YOU WANT TO PUBLIC LICENSE | |
| // Version 3, December 2018 | |
| // | |
| // Copyright (C) 2018 Daniel Christmas <[email protected]> & Sam Hocevar <[email protected]> | |
| // | |
| // Everyone is permitted to copy and distribute verbatim or modified | |
| // copies of this license document, and changing it is allowed as long | |
| // as the name is changed. | |
| // | |
| // DO WHAT THE CRAP YOU WANT TO PUBLIC LICENSE | |
| // TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
| // | |
| // 0. You just DO WHAT THE CRAP YOU WANT TO. | |
| #define FMOD // comment if you're not using fmod | |
| using UnityEditor; | |
| using UnityEngine; | |
| using System.IO; | |
| using System; | |
| using UnityEditor.Build.Reporting; | |
| class BatchBuilderSettings : ScriptableObject | |
| { | |
| [Serializable] | |
| public struct Settings | |
| { | |
| public string Name; | |
| public bool Active; | |
| public BuildTarget Target; | |
| public BuildTargetGroup Group; | |
| public string Symbols; | |
| public string Path; | |
| public string Filename; | |
| public string Extension { get { | |
| switch (Target) | |
| { | |
| case BuildTarget.StandaloneOSX: | |
| return ".app"; | |
| case BuildTarget.StandaloneWindows: | |
| case BuildTarget.StandaloneWindows64: | |
| return ".exe"; | |
| default: | |
| return ".bin"; | |
| } | |
| } | |
| } | |
| public UnityEditor.AnimatedValues.AnimBool Editing; | |
| } | |
| public Settings[] Builds = new Settings[0]; | |
| [Serializable] | |
| public struct Symbol | |
| { | |
| public bool Active; | |
| public string Name; | |
| public string DisplayName { get { return this.Name.ToUpper().Replace(" ","_"); } } | |
| public Symbol(bool _active, string _name) | |
| { | |
| this.Active = _active; | |
| this.Name = _name.ToUpper().Replace(" ", "_"); | |
| } | |
| } | |
| public Symbol[] GeneralSymbols; | |
| public bool Debug = false; | |
| public bool LZ4Compression = true; | |
| } | |
| class BatchBuilder : EditorWindow | |
| { | |
| const string settingsPath = "Assets/Editor/Resources/BatchBuild.asset"; | |
| BatchBuilderSettings settings; | |
| Vector2 scrollTargets; | |
| Vector2 scrollSymbols; | |
| enum Step | |
| { | |
| SetSymbols, | |
| #if FMOD | |
| AudioCopy, | |
| #endif | |
| Compilation, | |
| Build | |
| } | |
| int building = -1; | |
| int succeeded = 0; | |
| int failed = 0; | |
| Step step = Step.SetSymbols; | |
| System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); | |
| [MenuItem("Tools/Batch Builder")] | |
| static void Open() | |
| { | |
| EditorWindow w = GetWindow<BatchBuilder>(); | |
| w.minSize = new Vector2(750, 320); | |
| } | |
| void OnEnable() | |
| { | |
| settings = AssetDatabase.LoadAssetAtPath<BatchBuilderSettings>(settingsPath); | |
| if (settings == null) | |
| { | |
| settings = CreateInstance<BatchBuilderSettings>(); | |
| AssetDatabase.CreateAsset(settings, settingsPath); | |
| AssetDatabase.SaveAssets(); | |
| } | |
| EditorApplication.update += Update; | |
| foreach (BatchBuilderSettings.Settings s in settings.Builds) | |
| s.Editing.valueChanged.AddListener(Repaint); | |
| } | |
| void OnDisable() | |
| { | |
| EditorApplication.update -= Update; | |
| } | |
| void OnGUI() | |
| { | |
| GUI.enabled = building == -1; | |
| GUILayout.Label("Targets", EditorStyles.boldLabel); | |
| GUILayout.BeginHorizontal(); | |
| { | |
| GUILayout.Label("Name", EditorStyles.boldLabel, GUILayout.Width(200)); | |
| GUILayout.FlexibleSpace(); | |
| GUILayout.Label("Directory", EditorStyles.boldLabel, GUILayout.Width(200)); | |
| GUILayout.Label("Filename", EditorStyles.boldLabel, GUILayout.Width(200)); | |
| GUILayout.Space(60); // width of edit, X | |
| } | |
| GUILayout.EndHorizontal(); | |
| EditorGUI.BeginChangeCheck(); | |
| { | |
| Undo.RecordObject(settings, "Edit Batch Build Settings"); | |
| BatchBuilderSettings.Settings[] builds = settings.Builds; | |
| scrollTargets = EditorGUILayout.BeginScrollView(scrollTargets); | |
| { | |
| for (int i = 0; i < builds.Length; i++) | |
| { | |
| bool deleted = false; | |
| var oneLevelUp = Application.dataPath + "/../" + builds[i].Path; | |
| DirectoryInfo dirInfo = new DirectoryInfo(oneLevelUp); | |
| string currentBuildPath = dirInfo.FullName + "\\" + builds[i].Filename + builds[i].Extension; | |
| GUILayout.BeginHorizontal(); | |
| { | |
| if (builds[i].Editing.target) | |
| { | |
| builds[i].Active = EditorGUILayout.Toggle(builds[i].Active, GUILayout.Width(15)); | |
| builds[i].Name = EditorGUILayout.TextField(builds[i].Name); | |
| GUILayout.FlexibleSpace(); | |
| builds[i].Path = EditorGUILayout.TextField(builds[i].Path, GUILayout.Width(200)); | |
| builds[i].Filename = EditorGUILayout.TextField(builds[i].Filename, GUILayout.Width(200)); | |
| } | |
| else | |
| { | |
| builds[i].Active = EditorGUILayout.ToggleLeft(builds[i].Name, builds[i].Active); | |
| GUILayout.FlexibleSpace(); | |
| GUILayout.Label(builds[i].Path, GUILayout.Width(200)); | |
| GUILayout.Label(builds[i].Filename, GUILayout.Width(200)); | |
| } | |
| bool wasEditing = builds[i].Editing.target; | |
| builds[i].Editing.target = GUILayout.Toggle(builds[i].Editing.target, "Edit", "Button"); | |
| if (wasEditing && !builds[i].Editing.target) | |
| GUI.FocusControl(string.Empty); | |
| if (File.Exists(currentBuildPath)) | |
| { | |
| #if UNITY_EDITOR_WIN | |
| if (GUILayout.Button("Show in Explorer")) | |
| #elif UNITY_EDITOR_OSX | |
| if (GUILayout.Button("Reveal in Finder")) | |
| #else | |
| if (GUILayout.Button("Show")) | |
| #endif | |
| { | |
| EditorUtility.RevealInFinder(currentBuildPath);//show in explorer | |
| } | |
| if (GUILayout.Button("Open")) | |
| { | |
| Application.OpenURL(currentBuildPath);//open build | |
| } | |
| } | |
| if (GUILayout.Button("X", GUILayout.Width(20))) | |
| { | |
| deleted = true; | |
| ArrayUtility.RemoveAt(ref settings.Builds, i); | |
| GUI.FocusControl(string.Empty); | |
| i--; | |
| } | |
| } | |
| GUILayout.EndHorizontal(); | |
| if (!deleted && builds[i].Editing.target) | |
| { | |
| EditorGUILayout.BeginFadeGroup(builds[i].Editing.faded); | |
| { | |
| builds[i].Target = (BuildTarget)EditorGUILayout.EnumPopup("Target", builds[i].Target); | |
| builds[i].Group = (BuildTargetGroup)EditorGUILayout.EnumPopup("Group", builds[i].Group); | |
| builds[i].Symbols = EditorGUILayout.TextField("Symbols", builds[i].Symbols); | |
| } | |
| EditorGUILayout.EndFadeGroup(); | |
| } | |
| } | |
| } | |
| EditorGUILayout.EndScrollView(); | |
| GUILayout.BeginHorizontal(); | |
| GUILayout.FlexibleSpace(); | |
| if (GUILayout.Button("Add Build")) | |
| { | |
| ArrayUtility.Insert(ref settings.Builds, settings.Builds.Length, | |
| new BatchBuilderSettings.Settings() | |
| { | |
| Name = "New Build", | |
| Path = "Builds/New", | |
| Filename = PlayerSettings.productName, | |
| Target = BuildTarget.StandaloneWindows64, | |
| Group = BuildTargetGroup.Standalone, | |
| Symbols = "TMPPRESENT", | |
| Active = false, | |
| Editing = new UnityEditor.AnimatedValues.AnimBool(true), | |
| }); | |
| } | |
| GUILayout.EndHorizontal(); | |
| GUILayout.Label("General Symbols", EditorStyles.boldLabel); | |
| scrollSymbols = EditorGUILayout.BeginScrollView(scrollSymbols); | |
| { | |
| for (int i = 0; i < settings.GeneralSymbols.Length; i++) | |
| { | |
| GUILayout.BeginHorizontal(); | |
| { | |
| settings.GeneralSymbols[i].Active = EditorGUILayout.Toggle(settings.GeneralSymbols[i].Active, GUILayout.Width(15)); | |
| settings.GeneralSymbols[i].Name = GUILayout.TextField(settings.GeneralSymbols[i].DisplayName); | |
| if (GUILayout.Button("X", GUILayout.Width(20))) | |
| { | |
| ArrayUtility.RemoveAt(ref settings.GeneralSymbols, i); | |
| i--; | |
| } | |
| } | |
| GUILayout.EndHorizontal(); | |
| } | |
| } | |
| EditorGUILayout.EndScrollView(); | |
| GUILayout.BeginHorizontal(); | |
| GUILayout.FlexibleSpace(); | |
| if (GUILayout.Button("Add Symbol")) | |
| { | |
| BatchBuilderSettings.Symbol newSymbol = new BatchBuilderSettings.Symbol(false, "New Symbol"); | |
| ArrayUtility.Insert(ref settings.GeneralSymbols, settings.GeneralSymbols.Length, newSymbol); | |
| } | |
| GUILayout.EndHorizontal(); | |
| GUILayout.Label("Options", EditorStyles.boldLabel); | |
| GUILayout.BeginHorizontal(); | |
| { | |
| settings.Debug = EditorGUILayout.ToggleLeft("Debug", settings.Debug); | |
| settings.LZ4Compression = EditorGUILayout.ToggleLeft("LZ4 Compression", settings.LZ4Compression); | |
| GUILayout.FlexibleSpace(); | |
| } | |
| GUILayout.EndHorizontal(); | |
| } | |
| if (EditorGUI.EndChangeCheck()) | |
| EditorUtility.SetDirty(settings); | |
| if (building == -1) | |
| { | |
| if (GUILayout.Button("Build")) | |
| { | |
| timer.Start(); | |
| building = 0; | |
| succeeded = 0; | |
| failed = 0; | |
| step = Step.SetSymbols; | |
| } | |
| } | |
| else | |
| { | |
| GUI.enabled = true; | |
| Rect rect = EditorGUILayout.GetControlRect(false, 20); | |
| int totalSteps = Enum.GetNames(typeof(Step)).Length; | |
| float progress = (building * totalSteps + (int)step) / (float)(settings.Builds.Length * totalSteps); | |
| string text = string.Format("{0}: {1}", settings.Builds[building].Name, step); | |
| EditorGUI.ProgressBar(rect, progress, text); | |
| } | |
| } | |
| private void Update() | |
| { | |
| if (building >= 0) | |
| { | |
| Repaint(); | |
| if (settings.Builds[building].Active) | |
| { | |
| switch (step) | |
| { | |
| case Step.SetSymbols: | |
| { | |
| SetSymbols(settings.Builds[building]); | |
| step = Step.Compilation; | |
| break; | |
| } | |
| case Step.Compilation: | |
| { | |
| if (!EditorApplication.isCompiling) | |
| step = Step.Build; | |
| break; | |
| } | |
| case Step.Build: | |
| { | |
| if (Build(settings.Builds[building])) | |
| { | |
| building = -1; | |
| Debug.LogWarning("Builds canceled"); | |
| } | |
| else | |
| { | |
| step = Step.SetSymbols; | |
| if (building != -1) | |
| building++; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| building++; | |
| } | |
| if (building >= settings.Builds.Length) | |
| { | |
| building = -1; | |
| timer.Stop(); | |
| Debug.LogFormat("Builds complete: {0} succeeded, {1} failed ({2})", succeeded, failed, timer.Elapsed); | |
| if (succeeded > 0) | |
| { | |
| BatchBuilderSettings.Settings currentBuild = settings.Builds[0]; | |
| string currentBuildPath = currentBuild.Path + "/" + currentBuild.Filename; | |
| //Debug.Log(currentBuildPath); | |
| //EditorUtility.RevealInFinder(currentBuildPath);//show in explorer | |
| EditorApplication.Beep(); | |
| } | |
| } | |
| } | |
| } | |
| void SetSymbols(BatchBuilderSettings.Settings build) | |
| { | |
| string extraSymbols = ""; | |
| foreach (BatchBuilderSettings.Symbol symbol in settings.GeneralSymbols) | |
| if (symbol.Active) | |
| extraSymbols += ";" + symbol.Name; | |
| PlayerSettings.SetScriptingDefineSymbolsForGroup(build.Group, build.Symbols + extraSymbols); | |
| } | |
| bool Build(BatchBuilderSettings.Settings build) | |
| { | |
| if (Directory.Exists(build.Path)) | |
| Directory.Delete(build.Path, true); | |
| Directory.CreateDirectory(build.Path); | |
| string file = Path.Combine(build.Path, build.Filename); | |
| BuildOptions options = BuildOptions.StrictMode; | |
| if (settings.Debug) | |
| options |= BuildOptions.Development | BuildOptions.ConnectWithProfiler; | |
| else if (settings.LZ4Compression) | |
| options |= BuildOptions.CompressWithLz4; | |
| Debug.LogFormat("Starting build {0} ({1})", build.Name, PlayerSettings.GetScriptingDefineSymbolsForGroup(build.Group)); | |
| bool success = false, canceled = false; | |
| try | |
| { | |
| BuildReport buildReport = BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, file + build.Extension, build.Target, options); | |
| BuildSummary buildSummary = buildReport.summary; | |
| BuildResult result = buildSummary.result; | |
| if (result == BuildResult.Succeeded) | |
| success = true; | |
| if (!success) | |
| { | |
| if (result == BuildResult.Cancelled) | |
| canceled = true; | |
| else | |
| Debug.LogError("Error while building " + build.Name); | |
| } | |
| } | |
| catch (Exception ex) | |
| { | |
| Debug.LogError("Error while building " + build.Name + ": " + ex.Message); | |
| } | |
| if (success) | |
| succeeded++; | |
| else | |
| failed++; | |
| return canceled; | |
| } | |
| } |
Author
Ah, I get that the code for symbols didn't work when there was no symbol yet, correct?
Nice modifications otherwise. I'll steal you the buildreport code once I upgrade :)
One feature I'm planing also is a per-build list of files to delete after building (like, you know, Steam.dll on drm-free builds that gets automatically copied...)
Funny you added yourself as an author of the license to change fuck to crap :D
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added: