├── .gitattributes ├── .npmrc ├── Editor.meta ├── Editor ├── Runtime.meta └── Runtime │ ├── Actions.meta │ ├── Actions │ ├── BuildActions.cs │ ├── BuildActions.cs.meta │ ├── CopyFilesOnBuild.cs │ ├── CopyFilesOnBuild.cs.meta │ ├── IBuildAction.cs │ ├── IBuildAction.cs.meta │ ├── RunOnBuild.cs │ ├── RunOnBuild.cs.meta │ ├── ZipOnBuild.cs │ └── ZipOnBuild.cs.meta │ ├── Build.meta │ ├── Build │ ├── AddressablesBuilder.cs │ ├── AddressablesBuilder.cs.meta │ ├── GameBuildOptions.cs │ ├── GameBuildOptions.cs.meta │ ├── GameBuilder.cs │ └── GameBuilder.cs.meta │ ├── GUI.meta │ ├── GUI │ ├── BuildSettings.cs │ ├── BuildSettings.cs.meta │ ├── BuildToolWindow.cs │ ├── BuildToolWindow.cs.meta │ ├── GUIStyles.cs │ └── GUIStyles.cs.meta │ ├── Settings.meta │ ├── Settings │ ├── SettingsManager.cs │ └── SettingsManager.cs.meta │ ├── UnityVoltBuilder.asmdef │ └── UnityVoltBuilder.asmdef.meta ├── LICENSE.md ├── LICENSE.md.meta ├── Media~ └── preview.jpg ├── README.md ├── README.md.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://upm-pkgs.voltstro.dev 2 | always-auth=true -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a790fec1cc1021a459d0a591eaa937a1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fbf36c5f85bb7bb47a3596dc8b3de32c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d9f1712c575807459c76aec734e559b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions/BuildActions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using JetBrains.Annotations; 5 | using UnityEditor; 6 | using UnityEngine; 7 | using UnityVoltBuilder.GUI; 8 | using UnityVoltBuilder.Settings; 9 | 10 | namespace UnityVoltBuilder.Actions 11 | { 12 | public class BuildActions 13 | { 14 | private static BuildActions instance; 15 | 16 | private static bool buildActions; 17 | private static int selectedIndex; 18 | private readonly Dictionary activeBuildActions; 19 | 20 | private readonly List availableActions; 21 | private readonly string[] dropdownOptions; 22 | 23 | private BuildActions() 24 | { 25 | activeBuildActions = new Dictionary(); 26 | availableActions = AppDomain.CurrentDomain.GetAssemblies() 27 | .SelectMany(s => s.GetTypes()) 28 | .Where(p => typeof(IBuildAction).IsAssignableFrom(p) && !p.IsInterface) 29 | .ToList(); 30 | dropdownOptions = availableActions.Select(availableAction => availableAction.Name).ToArray(); 31 | 32 | foreach (string buildAction in SettingsManager.BuildActions) AddBuildAction(buildAction); 33 | } 34 | 35 | /// 36 | /// Active instance 37 | /// 38 | private static BuildActions Instance => instance ??= new BuildActions(); 39 | 40 | /// 41 | /// Gets all active s 42 | /// 43 | /// 44 | [PublicAPI] 45 | public static List GetBuildActions() 46 | { 47 | return Instance.activeBuildActions.Values.ToList(); 48 | } 49 | 50 | internal static void DrawOptions() 51 | { 52 | GUIStyles.DrawDropdownButton("Build Actions", ref buildActions); 53 | if (buildActions) 54 | { 55 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 56 | 57 | if (Instance.availableActions.Count == 0) 58 | { 59 | EditorGUILayout.HelpBox("There are no build actions to add!", MessageType.Error, true); 60 | return; 61 | } 62 | 63 | //Drop down of available build actions 64 | EditorGUILayout.BeginHorizontal(); 65 | selectedIndex = EditorGUILayout.Popup(selectedIndex, Instance.dropdownOptions); 66 | 67 | //Add button 68 | if (GUILayout.Button("+")) Instance.AddBuildAction(Instance.dropdownOptions[selectedIndex]); 69 | 70 | EditorGUILayout.EndHorizontal(); 71 | 72 | try 73 | { 74 | //Do OnGUI for each option 75 | foreach (KeyValuePair activeBuildAction in Instance.activeBuildActions) 76 | { 77 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 78 | 79 | if (activeBuildAction.Value == null) 80 | { 81 | EditorGUILayout.HelpBox($"The action {activeBuildAction.Key} no longer exists!", 82 | MessageType.Error); 83 | if (GUILayout.Button("Delete")) 84 | Instance.DeleteBuildAction(activeBuildAction.Key); 85 | continue; 86 | } 87 | 88 | //Draw the build action's OnGUI 89 | EditorGUILayout.LabelField(activeBuildAction.Key, GUIStyles.DropdownHeaderStyle); 90 | activeBuildAction.Value.OnGUI(); 91 | 92 | //Delete button 93 | if (GUILayout.Button("Delete")) 94 | Instance.DeleteBuildAction(activeBuildAction.Key); 95 | 96 | EditorGUILayout.EndVertical(); 97 | 98 | if (!activeBuildAction.Equals(Instance.activeBuildActions.Last())) 99 | EditorGUILayout.Space(); 100 | } 101 | } 102 | catch (InvalidOperationException) 103 | { 104 | } 105 | 106 | EditorGUILayout.EndVertical(); 107 | } 108 | } 109 | 110 | private void AddBuildAction(string action) 111 | { 112 | if (activeBuildActions.ContainsKey(action)) 113 | return; 114 | 115 | //First, get if that action still exists 116 | Type actionType = availableActions.FirstOrDefault(x => x.Name == action); 117 | if (actionType == null) 118 | { 119 | activeBuildActions.Add(action, null); 120 | return; 121 | } 122 | 123 | //Now to create it 124 | IBuildAction buildAction = (IBuildAction)Activator.CreateInstance(actionType); 125 | activeBuildActions.Add(action, buildAction); 126 | 127 | List currentBuildActions = SettingsManager.BuildActions; 128 | if (currentBuildActions.Contains(action)) 129 | return; 130 | 131 | currentBuildActions.Add(action); 132 | SettingsManager.BuildActions = currentBuildActions; 133 | } 134 | 135 | private void DeleteBuildAction(string action) 136 | { 137 | if (!activeBuildActions.ContainsKey(action)) return; 138 | 139 | activeBuildActions.Remove(action); 140 | 141 | List currentBuildActions = SettingsManager.BuildActions; 142 | currentBuildActions.Remove(action); 143 | SettingsManager.BuildActions = currentBuildActions; 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /Editor/Runtime/Actions/BuildActions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0fcd07fb1e74bde4d8b565262690ef3f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions/CopyFilesOnBuild.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using JetBrains.Annotations; 4 | using UnityEditor; 5 | using UnityEditor.Build.Reporting; 6 | using UnityEngine; 7 | using UnityVoltBuilder.GUI; 8 | using UnityVoltBuilder.Settings; 9 | 10 | namespace UnityVoltBuilder.Actions 11 | { 12 | public sealed class CopyFilesOnBuild : IBuildAction 13 | { 14 | //TODO: Surely we can use a single struct for this? 15 | private const string FilesToCopyKey = "FilesToCopy"; 16 | 17 | [PublicAPI] 18 | public static List FilesToCopy 19 | { 20 | get => SettingsManager.AddOrGetOption(FilesToCopyKey, new List()); 21 | set => SettingsManager.SetOption(FilesToCopyKey, value); 22 | } 23 | 24 | private const string CopyToWhereKey = "CopyToWhere"; 25 | 26 | [PublicAPI] 27 | public static List CopyToWhere 28 | { 29 | get => SettingsManager.AddOrGetOption(CopyToWhereKey, new List()); 30 | set => SettingsManager.SetOption(CopyToWhereKey, value); 31 | } 32 | 33 | public void OnGUI() 34 | { 35 | if (GUILayout.Button("Open Files To Copy Window")) 36 | EditorWindow.GetWindow(typeof(CopyFilesWindow), true, "Files To Copy", true); 37 | } 38 | 39 | public void OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions) 40 | { 41 | } 42 | 43 | public void OnAfterBuild(string buildLocation, BuildReport report) 44 | { 45 | for (int i = 0; i < FilesToCopy.Count; i++) 46 | { 47 | if (!File.Exists(FilesToCopy[i])) continue; 48 | 49 | string fileDir = $"{buildLocation}/{CopyToWhere[i]}"; 50 | if (!Directory.Exists(Path.GetDirectoryName(fileDir))) 51 | Directory.CreateDirectory(Path.GetDirectoryName(fileDir)); 52 | 53 | File.Copy(FilesToCopy[i], fileDir, true); 54 | } 55 | } 56 | 57 | private class CopyFilesWindow : EditorWindow 58 | { 59 | private CopyFilesWindow() 60 | { 61 | minSize = new Vector2(404, 142); 62 | } 63 | 64 | private void OnGUI() 65 | { 66 | EditorGUILayout.LabelField("Copy Files On Build", GUIStyles.DropdownHeaderStyle); 67 | EditorGUILayout.Space(); 68 | 69 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 70 | EditorGUILayout.LabelField("These files will be copied to the build folder after a successful build"); 71 | EditorGUILayout.Space(); 72 | 73 | EditorGUILayout.BeginHorizontal(); 74 | 75 | EditorGUILayout.LabelField("File to copy"); 76 | EditorGUILayout.LabelField("Where to (in build)"); 77 | 78 | EditorGUILayout.EndHorizontal(); 79 | 80 | for (int i = 0; i < FilesToCopy.Count; i++) 81 | { 82 | EditorGUILayout.BeginHorizontal(); 83 | 84 | List filesToCopy = FilesToCopy; 85 | List copyToWhere = CopyToWhere; 86 | 87 | filesToCopy[i] = 88 | EditorGUILayout.TextField(filesToCopy[i]); 89 | 90 | copyToWhere[i] = 91 | EditorGUILayout.TextField(copyToWhere[i]); 92 | 93 | if (GUILayout.Button("-")) 94 | { 95 | filesToCopy.Remove(FilesToCopy[i]); 96 | copyToWhere.Remove(CopyToWhere[i]); 97 | } 98 | 99 | FilesToCopy = filesToCopy; 100 | CopyToWhere = copyToWhere; 101 | 102 | EditorGUILayout.EndHorizontal(); 103 | } 104 | 105 | EditorGUILayout.Space(); 106 | 107 | EditorGUILayout.BeginHorizontal(); 108 | 109 | if (GUILayout.Button("Add New")) 110 | { 111 | List filesToCopy = FilesToCopy; 112 | List copyToWhere = CopyToWhere; 113 | 114 | filesToCopy.Add("Assets/Example.txt"); 115 | copyToWhere.Add("Example.txt"); 116 | 117 | FilesToCopy = filesToCopy; 118 | CopyToWhere = copyToWhere; 119 | } 120 | 121 | EditorGUILayout.EndHorizontal(); 122 | EditorGUILayout.EndVertical(); 123 | } 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /Editor/Runtime/Actions/CopyFilesOnBuild.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 021e03dcad495b145a23f5243c55d9b3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions/IBuildAction.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.Build.Reporting; 3 | 4 | namespace UnityVoltBuilder.Actions 5 | { 6 | /// 7 | /// Interface for a build action 8 | /// 9 | public interface IBuildAction 10 | { 11 | void OnGUI(); 12 | 13 | void OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions); 14 | 15 | void OnAfterBuild(string buildLocation, BuildReport report); 16 | } 17 | } -------------------------------------------------------------------------------- /Editor/Runtime/Actions/IBuildAction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 00c3a927070c20d43803e8ccdcbf54bd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions/RunOnBuild.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using JetBrains.Annotations; 3 | using UnityEditor; 4 | using UnityEditor.Build.Reporting; 5 | using UnityVoltBuilder.Settings; 6 | 7 | namespace UnityVoltBuilder.Actions 8 | { 9 | public sealed class RunOnBuild : IBuildAction 10 | { 11 | public void OnGUI() 12 | { 13 | RunOnBuildSetting = EditorGUILayout.Toggle("Run on Build", RunOnBuildSetting); 14 | RunOnBuildArguments = EditorGUILayout.TextField("Arguments", RunOnBuildArguments); 15 | 16 | EditorGUILayout.Space(); 17 | } 18 | 19 | public void OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions) 20 | { 21 | } 22 | 23 | public void OnAfterBuild(string buildLocation, BuildReport report) 24 | { 25 | if (RunOnBuildSetting) 26 | Process.Start(buildLocation, RunOnBuildArguments); 27 | } 28 | 29 | private const string RunOnBuildSettingKey = "RunOnBuild"; 30 | 31 | [PublicAPI] 32 | public static bool RunOnBuildSetting 33 | { 34 | get => SettingsManager.AddOrGetOption(RunOnBuildSettingKey, true); 35 | set => SettingsManager.SetOption(RunOnBuildSettingKey, value); 36 | } 37 | 38 | private const string RunOnBuildArgumentsKey = "RunOnBuildArguments"; 39 | 40 | [PublicAPI] 41 | public static string RunOnBuildArguments 42 | { 43 | get => SettingsManager.AddOrGetOption(RunOnBuildArgumentsKey, string.Empty); 44 | set => SettingsManager.SetOption(RunOnBuildArgumentsKey, value); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Editor/Runtime/Actions/RunOnBuild.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aea5cfce9efe9bb4698d2cd935652283 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Actions/ZipOnBuild.cs: -------------------------------------------------------------------------------- 1 | #if ZIPPING_SUPPORT //We can only do this if the com.unity.sharp-zip-lib package is installed 2 | 3 | using System.Diagnostics; 4 | using System.IO; 5 | using JetBrains.Annotations; 6 | using Unity.SharpZipLib.Utils; 7 | using UnityEditor; 8 | using UnityEditor.Build.Reporting; 9 | using UnityVoltBuilder.Settings; 10 | using Debug = UnityEngine.Debug; 11 | 12 | namespace UnityVoltBuilder.Actions 13 | { 14 | public class ZipOnBuild : IBuildAction 15 | { 16 | public void OnGUI() 17 | { 18 | ZipBuild = EditorGUILayout.Toggle("Zip Build", ZipBuild); 19 | } 20 | 21 | public void OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions) 22 | { 23 | } 24 | 25 | public void OnAfterBuild(string buildLocation, BuildReport report) 26 | { 27 | if (!ZipBuild) 28 | return; 29 | 30 | Debug.Log("Compressing build..."); 31 | 32 | EditorUtility.DisplayProgressBar("Compressing build...", "Compressing build...", 0.5f); 33 | Stopwatch stopwatch = Stopwatch.StartNew(); 34 | 35 | string outPath = $"{buildLocation}/../{Path.GetFileName(buildLocation)}.zip"; 36 | ZipUtility.CompressFolderToZip(outPath, null, buildLocation); 37 | 38 | stopwatch.Stop(); 39 | EditorUtility.ClearProgressBar(); 40 | 41 | Debug.Log($"Compressed build to {outPath}. Took {stopwatch.Elapsed.Seconds}s to compress."); 42 | } 43 | 44 | private const string ZipBuildKey = "ZipBuild"; 45 | 46 | [PublicAPI] 47 | public static bool ZipBuild 48 | { 49 | get => SettingsManager.AddOrGetOption(ZipBuildKey, true); 50 | set => SettingsManager.SetOption(ZipBuildKey, value); 51 | } 52 | } 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /Editor/Runtime/Actions/ZipOnBuild.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d115e89fe3da42045ad83c5d0368c207 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Build.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3413a05e280770f40b4ab748597d6716 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime/Build/AddressablesBuilder.cs: -------------------------------------------------------------------------------- 1 | #if ADDRESSABLES_SUPPORT 2 | 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using JetBrains.Annotations; 6 | using UnityEditor; 7 | using UnityEditor.AddressableAssets; 8 | using UnityEditor.AddressableAssets.Build; 9 | using UnityEditor.AddressableAssets.Settings; 10 | using UnityEngine; 11 | using UnityVoltBuilder.GUI; 12 | using Debug = UnityEngine.Debug; 13 | 14 | namespace UnityVoltBuilder.Build 15 | { 16 | public static class AddressablesBuilder 17 | { 18 | private static AddressableAssetSettings settings; 19 | 20 | static AddressablesBuilder() 21 | { 22 | settings = AddressableAssetSettingsDefaultObject.Settings; 23 | } 24 | 25 | public static void DrawOptions() 26 | { 27 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 28 | 29 | GUILayout.Label("Addressable Commands", GUIStyles.DropdownHeaderStyle); 30 | 31 | EditorGUILayout.BeginHorizontal(); 32 | if (GUILayout.Button("Build Addressables")) 33 | BuildAddressables(); 34 | 35 | if (GUILayout.Button("Clean Build")) 36 | CleanAddressablesBuild(); 37 | 38 | EditorGUILayout.EndHorizontal(); 39 | 40 | string[] names = new string[settings.DataBuilders.Count]; 41 | for (int i = 0; i < settings.DataBuilders.Count; i++) 42 | { 43 | IDataBuilder m = settings.GetDataBuilder(i); 44 | if (m.CanBuildData()) 45 | names[i] = m.Name; 46 | } 47 | 48 | settings.ActivePlayModeDataBuilderIndex = EditorGUILayout.Popup("Play Mode Script", settings.ActivePlayModeDataBuilderIndex, names); 49 | 50 | EditorGUILayout.EndVertical(); 51 | } 52 | 53 | /// 54 | /// Builds addressables 55 | /// 56 | [PublicAPI] 57 | public static void BuildAddressables() 58 | { 59 | Debug.Log("Building addressables..."); 60 | 61 | Stopwatch stopwatch = Stopwatch.StartNew(); 62 | AddressableAssetSettings.BuildPlayerContent(); 63 | stopwatch.Stop(); 64 | 65 | Debug.Log($"Addressable Build done in {stopwatch.ElapsedMilliseconds / 1000}s!"); 66 | } 67 | 68 | /// 69 | /// Cleans addressables build 70 | /// 71 | [PublicAPI] 72 | public static void CleanAddressablesBuild() 73 | { 74 | Debug.Log("Cleaning addressables build..."); 75 | 76 | EditorUtility.DisplayProgressBar("Cleaning Addressables Build", "Cleaning addressables build...", 0.5f); 77 | Stopwatch stopwatch = Stopwatch.StartNew(); 78 | AddressableAssetSettings.CleanPlayerContent(); 79 | stopwatch.Stop(); 80 | EditorUtility.ClearProgressBar(); 81 | 82 | Debug.Log($"Build clean done in {stopwatch.ElapsedMilliseconds / 1000}s!"); 83 | } 84 | } 85 | } 86 | 87 | #endif -------------------------------------------------------------------------------- /Editor/Runtime/Build/AddressablesBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c0f4b05ef991a740b0fd84ec678a56e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Build/GameBuildOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityVoltBuilder.Actions; 4 | 5 | namespace UnityVoltBuilder.Build 6 | { 7 | /// 8 | /// Build options for 9 | /// 10 | public readonly struct GameBuildOptions 11 | { 12 | public readonly string BuildDir; 13 | 14 | public readonly BuildTarget BuildTarget; 15 | 16 | public readonly bool HeadlessBuild; 17 | 18 | public readonly bool DevBuild; 19 | 20 | public readonly bool AutoConnectProfiler; 21 | 22 | public readonly bool DeepProfiling; 23 | 24 | public readonly bool ScriptDebugging; 25 | 26 | public readonly bool CopyPdbFiles; 27 | 28 | public readonly bool ScriptsOnly; 29 | 30 | public readonly List BuildActions; 31 | 32 | public GameBuildOptions(string buildDir, BuildTarget buildTarget, List buildActions = null, 33 | bool headlessBuild = false, 34 | bool devBuild = false, 35 | bool autoConnectProfiler = false, 36 | bool deepProfiling = false, 37 | bool scriptDebugging = false, 38 | bool copyPdbFiles = false, 39 | bool scriptsOnly = false) 40 | { 41 | BuildDir = buildDir; 42 | BuildTarget = buildTarget; 43 | HeadlessBuild = headlessBuild; 44 | DevBuild = devBuild; 45 | AutoConnectProfiler = autoConnectProfiler; 46 | DeepProfiling = deepProfiling; 47 | ScriptDebugging = scriptDebugging; 48 | CopyPdbFiles = copyPdbFiles; 49 | ScriptsOnly = scriptsOnly; 50 | 51 | BuildActions = buildActions; 52 | if (buildActions == null) 53 | BuildActions = new List(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Editor/Runtime/Build/GameBuildOptions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d768959ea6a18a34bbc02fa95ee82fbc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Build/GameBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using JetBrains.Annotations; 7 | using UnityEditor; 8 | using UnityEditor.Build.Reporting; 9 | using UnityEngine; 10 | using UnityVoltBuilder.Actions; 11 | using UnityVoltBuilder.GUI; 12 | using UnityVoltBuilder.Settings; 13 | using Debug = UnityEngine.Debug; 14 | 15 | namespace UnityVoltBuilder.Build 16 | { 17 | public static class GameBuilder 18 | { 19 | private const string CopyPdbFilesEditorString = "CopyPDBFiles"; 20 | 21 | internal static void DrawOptions() 22 | { 23 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 24 | 25 | GUILayout.Label("Build Commands", GUIStyles.DropdownHeaderStyle); 26 | 27 | EditorGUILayout.BeginHorizontal(); 28 | if (GUILayout.Button("Build Player")) 29 | BuildGameGUI($"{GetBuildDirectory()}{PlayerSettings.productName}-Quick/{PlayerSettings.productName}"); 30 | if (GUILayout.Button("Scripts Only")) 31 | BuildGameGUI($"{GetBuildDirectory()}{PlayerSettings.productName}-Quick/{PlayerSettings.productName}", 32 | true); 33 | EditorGUILayout.EndHorizontal(); 34 | 35 | EditorGUILayout.BeginHorizontal(); 36 | if (GUILayout.Button("New Build")) 37 | BuildGameGUI( 38 | $"{GetBuildDirectory()}{PlayerSettings.productName}-{DateTime.Now.ToString(SettingsManager.BuildFolderNameStyle)}/{PlayerSettings.productName}"); 39 | if (GUILayout.Button("Open Build Folder")) 40 | { 41 | if (!Directory.Exists(GetBuildDirectory())) 42 | Directory.CreateDirectory(GetBuildDirectory()); 43 | 44 | Process.Start(GetBuildDirectory()); 45 | } 46 | 47 | EditorGUILayout.EndHorizontal(); 48 | 49 | EditorGUILayout.EndVertical(); 50 | } 51 | 52 | private static void BuildGameGUI(string buildDir, bool scriptsOnly = false) 53 | { 54 | BuildGame(ToGameBuildOptions(buildDir, scriptsOnly)); 55 | GUIUtility.ExitGUI(); 56 | } 57 | 58 | /// 59 | /// Takes all the options in and converts them to a 60 | /// 61 | /// 62 | [PublicAPI] 63 | public static GameBuildOptions ToGameBuildOptions(string buildLocation, bool scriptsOnly, 64 | BuildTarget? buildTarget = null, 65 | [CanBeNull] List buildActions = null) => 66 | new GameBuildOptions( 67 | buildLocation, 68 | buildTarget ?? SettingsManager.BuildTarget, 69 | buildActions ?? BuildActions.GetBuildActions(), 70 | SettingsManager.ServerBuild, 71 | SettingsManager.DevelopmentBuild, 72 | SettingsManager.AutoconnectProfiler, 73 | SettingsManager.DeepProfiling, 74 | SettingsManager.ScriptDebugging, 75 | SettingsManager.CopyPdbFiles, 76 | scriptsOnly); 77 | 78 | /// 79 | /// Builds the game 80 | /// 81 | /// 82 | /// 83 | [PublicAPI] 84 | public static void BuildGame(GameBuildOptions gameBuildOptions) 85 | { 86 | Debug.Log($"Starting game build at {DateTime.Now:G}..."); 87 | Stopwatch stopwatch = Stopwatch.StartNew(); 88 | 89 | string fullBuildDir = gameBuildOptions.BuildDir; 90 | if (gameBuildOptions.BuildTarget == BuildTarget.StandaloneWindows || gameBuildOptions.BuildTarget == BuildTarget.StandaloneWindows64) 91 | fullBuildDir += ".exe"; 92 | 93 | string buildDir = Path.GetDirectoryName(fullBuildDir); 94 | 95 | Debug.Log($"Building to '{fullBuildDir}'..."); 96 | 97 | //Set target group 98 | #region Target Group 99 | 100 | BuildTargetGroup targetGroup; 101 | switch (gameBuildOptions.BuildTarget) 102 | { 103 | case BuildTarget.StandaloneLinux64: 104 | case BuildTarget.StandaloneWindows64: 105 | case BuildTarget.StandaloneOSX: 106 | case BuildTarget.StandaloneWindows: 107 | targetGroup = BuildTargetGroup.Standalone; 108 | break; 109 | case BuildTarget.iOS: 110 | targetGroup = BuildTargetGroup.iOS; 111 | break; 112 | case BuildTarget.Android: 113 | targetGroup = BuildTargetGroup.Android; 114 | break; 115 | case BuildTarget.WebGL: 116 | targetGroup = BuildTargetGroup.WebGL; 117 | break; 118 | case BuildTarget.WSAPlayer: 119 | targetGroup = BuildTargetGroup.WSA; 120 | break; 121 | case BuildTarget.PS4: 122 | targetGroup = BuildTargetGroup.PS4; 123 | break; 124 | case BuildTarget.XboxOne: 125 | targetGroup = BuildTargetGroup.XboxOne; 126 | break; 127 | case BuildTarget.tvOS: 128 | targetGroup = BuildTargetGroup.tvOS; 129 | break; 130 | case BuildTarget.Switch: 131 | targetGroup = BuildTargetGroup.Switch; 132 | break; 133 | case BuildTarget.Lumin: 134 | targetGroup = BuildTargetGroup.Lumin; 135 | break; 136 | case BuildTarget.Stadia: 137 | targetGroup = BuildTargetGroup.Stadia; 138 | break; 139 | case BuildTarget.CloudRendering: 140 | targetGroup = BuildTargetGroup.CloudRendering; 141 | break; 142 | default: 143 | throw new ArgumentOutOfRangeException(); 144 | } 145 | 146 | #endregion 147 | 148 | //Setup build options 149 | BuildOptions options = BuildOptions.None; 150 | 151 | #if UNITY_2021_2_OR_NEWER 152 | StandaloneBuildSubtarget existingBuildSubtarget = EditorUserBuildSettings.standaloneBuildSubtarget; 153 | #endif 154 | 155 | //Server/Headless mode 156 | if (gameBuildOptions.HeadlessBuild) 157 | { 158 | #if UNITY_2021_2_OR_NEWER 159 | EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Server; 160 | #else 161 | options |= BuildOptions.EnableHeadlessMode; 162 | #endif 163 | } 164 | 165 | //Copy PDB files 166 | string existingCopyPdbFilesOptions = 167 | EditorUserBuildSettings.GetPlatformSettings("Standalone", CopyPdbFilesEditorString); 168 | 169 | if (gameBuildOptions.CopyPdbFiles) 170 | EditorUserBuildSettings.SetPlatformSettings("Standalone", CopyPdbFilesEditorString, 171 | SettingsManager.CopyPdbFiles ? "true" : "false"); 172 | 173 | //Dev build 174 | if (gameBuildOptions.DevBuild) 175 | { 176 | options |= BuildOptions.Development; 177 | 178 | if (gameBuildOptions.AutoConnectProfiler) 179 | options |= BuildOptions.ConnectWithProfiler; 180 | 181 | if (gameBuildOptions.DeepProfiling) 182 | options |= BuildOptions.EnableDeepProfilingSupport; 183 | 184 | if (gameBuildOptions.ScriptDebugging) 185 | options |= BuildOptions.AllowDebugging; 186 | } 187 | 188 | //Scripts only 189 | if (gameBuildOptions.ScriptsOnly) 190 | options |= BuildOptions.BuildScriptsOnly; 191 | 192 | //Run build action pre-build 193 | Debug.Log("Running build actions pre build..."); 194 | try 195 | { 196 | foreach (IBuildAction buildAction in gameBuildOptions.BuildActions) 197 | buildAction?.OnBeforeBuild(buildDir, gameBuildOptions.BuildTarget, ref options); 198 | } 199 | catch (Exception ex) 200 | { 201 | Debug.LogError($"An error occurred while running a build action's pre build! {ex}"); 202 | } 203 | 204 | Debug.Log("Build actions pre build done!"); 205 | 206 | Debug.Log("Building player..."); 207 | 208 | //Build the player 209 | BuildReport report = BuildPipeline.BuildPlayer(new BuildPlayerOptions 210 | { 211 | locationPathName = fullBuildDir, 212 | target = gameBuildOptions.BuildTarget, 213 | options = options, 214 | targetGroup = targetGroup, 215 | scenes = EditorBuildSettings.scenes.Select(scene => scene.path).ToArray() 216 | }); 217 | 218 | //Set CopyPDBFiles to it's original setting 219 | EditorUserBuildSettings.SetPlatformSettings("Standalone", CopyPdbFilesEditorString, 220 | existingCopyPdbFilesOptions); 221 | 222 | #if UNITY_2021_2_OR_NEWER 223 | EditorUserBuildSettings.standaloneBuildSubtarget = existingBuildSubtarget; 224 | #endif 225 | 226 | //If the build failed 227 | if (report.summary.result != BuildResult.Succeeded) 228 | { 229 | stopwatch.Stop(); 230 | Debug.LogError($"Build failed for some reason! Completed in {stopwatch.ElapsedMilliseconds / 1000}s."); 231 | return; 232 | } 233 | 234 | //Run Build Action post build 235 | try 236 | { 237 | foreach (IBuildAction buildAction in gameBuildOptions.BuildActions) 238 | buildAction?.OnAfterBuild(buildDir, report); 239 | } 240 | catch (Exception ex) 241 | { 242 | Debug.LogError($"An error occurred while running a build action's post build! {ex}"); 243 | } 244 | 245 | //End 246 | stopwatch.Stop(); 247 | Debug.Log($"Build done in {stopwatch.ElapsedMilliseconds / 1000}s!"); 248 | } 249 | 250 | /// 251 | /// Gets the set build directory 252 | /// 253 | /// 254 | [PublicAPI] 255 | public static string GetBuildDirectory() 256 | { 257 | return $"{Application.dataPath.Replace("Assets", "")}{SettingsManager.BuildLocation}"; 258 | } 259 | } 260 | } -------------------------------------------------------------------------------- /Editor/Runtime/Build/GameBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c271798b23d74304a9ac766d07e295c1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/GUI.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 77e3f1b06110d984f8a57f818408e8e6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime/GUI/BuildSettings.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using UnityVoltBuilder.Settings; 4 | 5 | namespace UnityVoltBuilder.GUI 6 | { 7 | internal static class BuildSettings 8 | { 9 | private static bool buildSetting; 10 | 11 | internal static void DrawOptions() 12 | { 13 | GUIStyles.DrawDropdownButton("Build Settings", ref buildSetting); 14 | if (buildSetting) 15 | { 16 | EditorGUILayout.BeginVertical(GUIStyles.DropdownContentStyle); 17 | DrawHeader("Build Path Settings"); 18 | 19 | SettingsManager.BuildLocation = 20 | EditorGUILayout.TextField("Build Location", SettingsManager.BuildLocation); 21 | SettingsManager.BuildFolderNameStyle = 22 | EditorGUILayout.TextField("Build Folder Name", SettingsManager.BuildFolderNameStyle); 23 | 24 | EditorGUILayout.Space(10); 25 | DrawHeader("Build Player Settings"); 26 | 27 | SettingsManager.BuildTarget = 28 | (BuildTarget)EditorGUILayout.EnumPopup("Build Target", SettingsManager.BuildTarget); 29 | SettingsManager.ServerBuild = EditorGUILayout.Toggle("Server Build", SettingsManager.ServerBuild); 30 | SettingsManager.CopyPdbFiles = EditorGUILayout.Toggle("Copy PDB Files", SettingsManager.CopyPdbFiles); 31 | 32 | EditorGUILayout.Space(10); 33 | DrawHeader("Build Development Settings"); 34 | SettingsManager.DevelopmentBuild = 35 | EditorGUILayout.Toggle("Development Build", SettingsManager.DevelopmentBuild); 36 | 37 | if (SettingsManager.DevelopmentBuild) 38 | { 39 | SettingsManager.AutoconnectProfiler = 40 | EditorGUILayout.Toggle("Autoconnect Profiler", SettingsManager.AutoconnectProfiler); 41 | SettingsManager.DeepProfiling = 42 | EditorGUILayout.Toggle("Deep Profiling", SettingsManager.DeepProfiling); 43 | SettingsManager.ScriptDebugging = 44 | EditorGUILayout.Toggle("Script Debugging", SettingsManager.ScriptDebugging); 45 | } 46 | 47 | EditorGUILayout.EndVertical(); 48 | } 49 | } 50 | 51 | private static void DrawHeader(string header) 52 | { 53 | GUILayout.Label(header, GUIStyles.DropdownHeaderStyle); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Editor/Runtime/GUI/BuildSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a08febfba61f9f46b1fcf577bd98a0f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/GUI/BuildToolWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using JetBrains.Annotations; 4 | using UnityEditor; 5 | using UnityEngine; 6 | using UnityVoltBuilder.Actions; 7 | using UnityVoltBuilder.Build; 8 | 9 | namespace UnityVoltBuilder.GUI 10 | { 11 | public sealed class BuildToolWindow : EditorWindow 12 | { 13 | private static readonly List WindowDraws = new List 14 | { 15 | BuildSettings.DrawOptions, 16 | BuildActions.DrawOptions, 17 | #if ADDRESSABLES_SUPPORT 18 | AddressablesBuilder.DrawOptions, 19 | #endif 20 | GameBuilder.DrawOptions 21 | }; 22 | 23 | public void OnGUI() 24 | { 25 | //Main title 26 | EditorGUILayout.Space(2f); 27 | EditorGUILayout.LabelField("Unity Volt Builder", GUIStyles.TitleStyle); 28 | EditorGUILayout.Space(15f); 29 | 30 | foreach (Action windowDraw in WindowDraws) 31 | { 32 | try 33 | { 34 | windowDraw.Invoke(); 35 | EditorGUILayout.Space(8f); 36 | } 37 | catch (ExitGUIException) 38 | { 39 | throw; 40 | } 41 | catch (Exception ex) 42 | { 43 | Debug.LogError($"Error occured while drawing options! {ex}"); 44 | } 45 | } 46 | } 47 | 48 | [PublicAPI] 49 | public static void AddOnDraw([NotNull] Action drawAction) 50 | { 51 | if (drawAction == null) 52 | throw new ArgumentNullException(nameof(drawAction), "Draw action cannot be null!"); 53 | 54 | if (WindowDraws.Contains(drawAction)) 55 | { 56 | Debug.LogError("Draw action has already been added!"); 57 | return; 58 | } 59 | WindowDraws.Add(drawAction); 60 | } 61 | 62 | [MenuItem("Tools/Unity Volt Builder/Volt Builder")] 63 | public static void ShowWindow() 64 | { 65 | GetWindow(typeof(BuildToolWindow), false, "Volt Builder"); 66 | } 67 | 68 | [MenuItem("Tools/Unity Volt Builder/Report an issue")] 69 | public static void OpenIssues() 70 | { 71 | Application.OpenURL("https://github.com/Voltstro-Studios/UnityVoltBuilder/issues"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Editor/Runtime/GUI/BuildToolWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ed646334227fcc4dbeb0a6adb115372 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/GUI/GUIStyles.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace UnityVoltBuilder.GUI 5 | { 6 | /// 7 | /// Has GUI styles that is used by UnityVoltBuilder 8 | /// 9 | public class GUIStyles 10 | { 11 | private static GUIStyles instance; 12 | 13 | private readonly GUIStyle dropdownButtonStyle; 14 | private readonly GUIStyle dropdownContentStyle; 15 | private readonly GUIStyle dropdownHeaderStyle; 16 | 17 | private readonly GUIStyle titleStyle; 18 | 19 | private GUIStyles() 20 | { 21 | //Title Style 22 | titleStyle = new GUIStyle(EditorStyles.boldLabel) 23 | { 24 | alignment = TextAnchor.MiddleCenter, 25 | fontSize = 18 26 | }; 27 | 28 | dropdownButtonStyle = new GUIStyle(UnityEngine.GUI.skin.button) 29 | { 30 | alignment = TextAnchor.MiddleLeft, 31 | fontStyle = FontStyle.Bold, 32 | margin = new RectOffset(5, 5, 0, 0) 33 | }; 34 | 35 | dropdownContentStyle = new GUIStyle(UnityEngine.GUI.skin.textField) 36 | { 37 | padding = new RectOffset(5, 5, 5, 5), 38 | margin = new RectOffset(5, 5, 0, 0) 39 | }; 40 | 41 | dropdownHeaderStyle = new GUIStyle(EditorStyles.helpBox) 42 | { 43 | fontStyle = FontStyle.Bold 44 | }; 45 | } 46 | 47 | #region Internal Functions 48 | 49 | /// 50 | /// Draw a dropdown button 51 | /// 52 | /// 53 | /// 54 | public static void DrawDropdownButton(string text, ref bool dropdown) 55 | { 56 | if (GUILayout.Button(text, instance.dropdownButtonStyle)) dropdown = !dropdown; 57 | } 58 | 59 | #endregion 60 | 61 | #region Internal Getters 62 | 63 | /// 64 | /// Active instance 65 | /// 66 | private static GUIStyles Instance 67 | { 68 | get 69 | { 70 | if (instance == null) 71 | instance = new GUIStyles(); 72 | 73 | return instance; 74 | } 75 | } 76 | 77 | /// 78 | /// Main title style 79 | /// 80 | public static GUIStyle TitleStyle => Instance.titleStyle; 81 | 82 | /// 83 | /// Style for dropdown content 84 | /// 85 | public static GUIStyle DropdownContentStyle => Instance.dropdownContentStyle; 86 | 87 | /// 88 | /// Style for dropdown header 89 | /// 90 | public static GUIStyle DropdownHeaderStyle => Instance.dropdownHeaderStyle; 91 | 92 | #endregion 93 | } 94 | } -------------------------------------------------------------------------------- /Editor/Runtime/GUI/GUIStyles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a8962dc195c18247b3fd21dd0167cce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/Settings.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd3fc45f32460c94da9a96f1aa92b800 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Runtime/Settings/SettingsManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using JetBrains.Annotations; 3 | using UnityEditor; 4 | 5 | namespace UnityVoltBuilder.Settings 6 | { 7 | /// 8 | /// Manages settings for VoltUnityBuilder 9 | /// 10 | /// Feel free to use this to store your settings for your custom build actions 11 | /// 12 | /// 13 | [PublicAPI] 14 | public static class SettingsManager 15 | { 16 | //Name has stayed the same for backwards compatibility 17 | private const string PackageName = "dev.voltstro.voltunitybuilder"; 18 | 19 | private static UnityEditor.SettingsManagement.Settings settings; 20 | 21 | /// 22 | /// The active instance 23 | /// 24 | public static UnityEditor.SettingsManagement.Settings Instance => 25 | settings ??= new UnityEditor.SettingsManagement.Settings(PackageName); 26 | 27 | /// 28 | /// Add or gets an option from 29 | /// 30 | /// 31 | /// 32 | /// 33 | /// 34 | public static T AddOrGetOption(string key, T defaultValue = default) 35 | { 36 | UnityEditor.SettingsManagement.Settings settingsInstance = Instance; 37 | if (!settingsInstance.ContainsKey(key)) 38 | SetOption(key, defaultValue); 39 | 40 | return settingsInstance.Get(key); 41 | } 42 | 43 | /// 44 | /// Sets an option from 45 | /// 46 | /// 47 | /// 48 | /// 49 | public static void SetOption(string key, T value) 50 | { 51 | UnityEditor.SettingsManagement.Settings settingsInstance = Instance; 52 | settingsInstance.Set(key, value); 53 | settingsInstance.Save(); 54 | } 55 | 56 | #region Properties 57 | 58 | #region Build Path Settings 59 | 60 | private const string BuildLocationKey = "BuildLocation"; 61 | 62 | public static string BuildLocation 63 | { 64 | get => AddOrGetOption(BuildLocationKey, "Builds/"); 65 | internal set => SetOption(BuildLocationKey, value); 66 | } 67 | 68 | private const string BuildFolderNameStyleKey = "BuildFolderNameStyle"; 69 | 70 | public static string BuildFolderNameStyle 71 | { 72 | get => AddOrGetOption(BuildFolderNameStyleKey, "yy-MM-dd"); 73 | internal set => SetOption(BuildFolderNameStyleKey, value); 74 | } 75 | 76 | #endregion 77 | 78 | #region Build Player Settings 79 | 80 | private const string BuildTargetKey = "BuildTarget"; 81 | 82 | public static BuildTarget BuildTarget 83 | { 84 | get => AddOrGetOption(BuildTargetKey, EditorUserBuildSettings.activeBuildTarget); 85 | internal set => SetOption(BuildTargetKey, value); 86 | } 87 | 88 | private const string ServerBuildKey = "ServerBuild"; 89 | 90 | public static bool ServerBuild 91 | { 92 | get => AddOrGetOption(ServerBuildKey); 93 | internal set => SetOption(ServerBuildKey, value); 94 | } 95 | 96 | private const string CopyPdbFilesKey = "CopyPDBFiles"; 97 | 98 | public static bool CopyPdbFiles 99 | { 100 | get => AddOrGetOption(CopyPdbFilesKey); 101 | internal set => SetOption(CopyPdbFilesKey, value); 102 | } 103 | 104 | private const string DevelopmentBuildKey = "DevelopmentBuild"; 105 | 106 | public static bool DevelopmentBuild 107 | { 108 | get => AddOrGetOption(DevelopmentBuildKey); 109 | internal set => SetOption(DevelopmentBuildKey, value); 110 | } 111 | 112 | private const string AutoconnectProfilerKey = "AutoconnectProfiler"; 113 | 114 | public static bool AutoconnectProfiler 115 | { 116 | get => AddOrGetOption(AutoconnectProfilerKey); 117 | internal set => SetOption(AutoconnectProfilerKey, value); 118 | } 119 | 120 | private const string DeepProfilingKey = "DeepProfiling"; 121 | 122 | public static bool DeepProfiling 123 | { 124 | get => AddOrGetOption(DeepProfilingKey); 125 | internal set => SetOption(DeepProfilingKey, value); 126 | } 127 | 128 | private const string ScriptDebuggingKey = "ScriptDebugging"; 129 | 130 | public static bool ScriptDebugging 131 | { 132 | get => AddOrGetOption(ScriptDebuggingKey); 133 | internal set => SetOption(ScriptDebuggingKey, value); 134 | } 135 | 136 | #endregion 137 | 138 | private const string BuildActionsKey = "BuildActions"; 139 | 140 | public static List BuildActions 141 | { 142 | get => AddOrGetOption(BuildActionsKey, new List()); 143 | internal set => SetOption(BuildActionsKey, value); 144 | } 145 | 146 | #endregion 147 | } 148 | } -------------------------------------------------------------------------------- /Editor/Runtime/Settings/SettingsManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aae5ef0074540ae4c873f4383c147063 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Runtime/UnityVoltBuilder.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnityVoltBuilder", 3 | "rootNamespace": "UnityVoltBuilder", 4 | "references": [ 5 | "GUID:49818357e697641afb75d2f8acaf1861", 6 | "GUID:8c1b5e158961445498f8a66188fbb2e3", 7 | "GUID:69448af7b92c7f342b298e06a37122aa" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "overrideReferences": false, 15 | "precompiledReferences": [], 16 | "autoReferenced": true, 17 | "defineConstraints": [], 18 | "versionDefines": [ 19 | { 20 | "name": "com.unity.sharp-zip-lib", 21 | "expression": "1.2.0", 22 | "define": "ZIPPING_SUPPORT" 23 | }, 24 | { 25 | "name": "com.unity.addressables", 26 | "expression": "1.16.0", 27 | "define": "ADDRESSABLES_SUPPORT" 28 | } 29 | ], 30 | "noEngineReferences": false 31 | } -------------------------------------------------------------------------------- /Editor/Runtime/UnityVoltBuilder.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 994e1c56bd90a2c498b2312a4664a74d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 557212973f00d5a4b8faebc6d202606f 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Media~/preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Voltstro-Studios/UnityVoltBuilder/486ab63c41228c6011f8ca80cc8db7c436bc66a0/Media~/preview.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Volt Builder 2 | 3 | [![License](https://img.shields.io/github/license/Voltstro-Studios/VoltUnityBuilder.svg)](/LICENSE.md) 4 | [![Discord](https://img.shields.io/badge/Discord-Voltstro-7289da.svg?logo=discord)](https://discord.voltstro.dev) 5 | [![YouTube](https://img.shields.io/badge/Youtube-Voltstro-red.svg?logo=youtube)](https://www.youtube.com/Voltstro) 6 | 7 | Voltstro-Studios' Unity build tool, with a modular scripting design. 8 | 9 | ## Features 10 | 11 | - Easy to get at menu of settings to build your Unity player. 12 | - Build Actions (Can add custom GUI to the tool, do something before and after a build) 13 | - Three are provided, CopyFilesOnBuild, RunOnBuild and [ZipOnBuild](#ZipOnBuild) 14 | - Easily do a "Quick" build, a new build, or a scripts only build. 15 | - Easily add additional commands to the main window 16 | - [Addressables](#addressables) commands 17 | 18 | ## Installation 19 | 20 | There are three main sources on how you can install this package. Pick which ever one suites you the best! 21 | 22 | ### Voltstro UPM 23 | 24 | You can install this package from our custom UPM registry. To setup our registry, see [here](https://github.com/Voltstro/VoltstroUPM#setup). 25 | 26 | Once you have the registry added to your project, you can install it like any other package via the package manager. 27 | 28 | ### OpenUPM 29 | 30 | You can install this package via [OpenUPM](https://openupm.com/). 31 | 32 | To install it, use their CLI: 33 | 34 | ```bash 35 | openupm-cli add dev.voltstro.unityvoltbuilder 36 | ``` 37 | 38 | ### Git 39 | 40 | To install it via the package manager with git you will need to: 41 | 42 | 1. Open up the package manager via Windows **->** Package Manager 43 | 2. Click on the little + sign **->** Add package from git URL... 44 | 3. Type `https://github.com/Voltstro-Studios/UnityVoltBuilder.git` and add it 45 | 4. Unity will now download and install the package 46 | 47 | Please note that you will have to manually check for updates, and replace the hash (or tag version) in your project's `packages-lock.json` file. 48 | 49 | ## Using the tool 50 | 51 | To use the tool, go to Tools **->** Unity Volt Builder **->** Volt Builder. It will open up a screen that looks like this: 52 | 53 | ![Preview](Media~/preview.jpg) 54 | 55 | (Note: This is the window when [Addressables](#addressables) are installed) 56 | 57 | It is recommended to dock the window somewhere for convince. 58 | 59 | ### Build Actions 60 | 61 | You can add build actions under the 'Build Actions' menu, the select what build action you want to add by selecting it in the dropdown, then press the '+' button. 62 | 63 | #### ZipOnBuild 64 | 65 | This build action requires the [`com.unity.sharp-zip-lib`](https://docs.unity3d.com/Packages/com.unity.sharp-zip-lib@latest/) package to be installed. By default, the package DOES NOT appear under the Unity Registry menu in the package manager, you will need to add it manually by either altering your `manifest.json` file, or by typing `com.unity.sharp-zip-lib` into the Add package from git URL option in the package manager. 66 | 67 | #### Custom Build Actions 68 | 69 | To add a custom Build Action, add a class to your project, and make it implement `IBuildAction`. You will then need to add the required methods: `OnGUI()`, `OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions)`, and `OnAfterBuild(string buildLocation, BuildReport report)`. 70 | 71 | In the end it should look like this: 72 | 73 | ```csharp 74 | using UnityVoltBuilder.Actions; 75 | 76 | public class CustomBuildAction : IBuildAction 77 | { 78 | public void OnGUI() 79 | { 80 | //Do your GUI stuff here 81 | } 82 | 83 | public void OnBeforeBuild(string buildLocation, BuildTarget buildTarget, ref BuildOptions buildOptions) 84 | { 85 | //Do stuff you want to do before a build, if you want to you can modify the build options here as well 86 | } 87 | 88 | public void OnAfterBuild(string buildLocation, BuildReport report) 89 | { 90 | //Do stuff here after a build 91 | } 92 | } 93 | ``` 94 | 95 | After that, the tool will automatically add it as a selectable option in the dropdown in the Build Actions. 96 | 97 | ### Addressables 98 | 99 | If you have the [Unity Addressables package](https://docs.unity3d.com/Packages/com.unity.addressables@latest/manual/index.html) installed, additional commands will be provided in the main window, which will allow you to both build the addressables and change the play mode script without needing the Addressables Groups window opened. 100 | 101 | ## Authors 102 | Voltstro – *Initial Work* – [Voltstro](https://github.com/Voltstro) 103 | 104 | ## License 105 | This project is licensed under the Apache-2.0 license – see the [LICENSE.md](/LICENSE.md) file for details. 106 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a8a340e18d515e4ba8d439cd621010e 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev.voltstro.unityvoltbuilder", 3 | "displayName": "Unity Volt Builder", 4 | "version": "4.1.2", 5 | "unity": "2020.3", 6 | "description": "Voltstro-Studios' Unity build tool, with a modular scripting design.", 7 | "author": { 8 | "name": "Voltstro", 9 | "email": "me@voltstro.dev", 10 | "url": "https://voltstro.dev" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/Voltstro-Studios/UnityVoltBuilder.git" 15 | }, 16 | "dependencies": { 17 | "com.unity.settings-manager": "1.0.3" 18 | }, 19 | "type": "tool" 20 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 520d5e82b90fd82419fef704c8671c15 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------