Skip to content

Instantly share code, notes, and snippets.

@justadaniel
Forked from msklywenn/BatchBuilderSettings.cs
Last active September 4, 2018 20:22
Show Gist options
  • Save justadaniel/d39c5340d77d200dfd13a25f932e2a54 to your computer and use it in GitHub Desktop.
Save justadaniel/d39c5340d77d200dfd13a25f932e2a54 to your computer and use it in GitHub Desktop.
Unity Batch Builder
// 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;
}
}
@justadaniel
Copy link
Author

Added:

  • Show in Finder/File Explorer
  • Open The File from the Editor
  • Made the Symbols Actually Work

@msklywenn
Copy link

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