diff --git a/BuildConstants.cs b/BuildConstants.cs new file mode 100644 index 0000000..f2d8675 --- /dev/null +++ b/BuildConstants.cs @@ -0,0 +1,32 @@ +// This file is auto-generated. Do not modify or move this file. + +public static class BuildConstants +{ + public enum ReleaseType + { + None, + } + + public enum Platform + { + None, + } + + public enum Architecture + { + None, + } + + public enum Distribution + { + None, + } + + public static readonly System.DateTime buildDate = System.DateTime.Now; + public const string version = ""; + public const ReleaseType releaseType = ReleaseType.None; + public const Platform platform = Platform.None; + public const Architecture architecture = Architecture.None; + public const Distribution distribution = Distribution.None; +} + diff --git a/Editor/Build/Generator.cs.meta b/BuildConstants.cs.meta similarity index 75% rename from Editor/Build/Generator.cs.meta rename to BuildConstants.cs.meta index 9ae4cd8..3317114 100644 --- a/Editor/Build/Generator.cs.meta +++ b/BuildConstants.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 9c5721e9e55f8b34289a5b42cf759704 -timeCreated: 1460734696 +guid: ed22b223c14d34746a7830068b0fcf3e +timeCreated: 1483541154 licenseType: Pro MonoImporter: serializedVersion: 2 diff --git a/Editor/AssetBundles/BuildAssetBundles.cs b/Editor/AssetBundles/BuildAssetBundles.cs deleted file mode 100644 index 58cd787..0000000 --- a/Editor/AssetBundles/BuildAssetBundles.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace UnityBuild -{ - -public sealed class BuildAssetBundles : PostBuildAction -{ - #region MenuItems - - [MenuItem("Build/AssetBundles/Build AssetBundles", false, 50)] - private static void BuildAllAssetBundles() - { - BuildAll(); - } - - [MenuItem("Build/AssetBundles/Clear Cache", false, 51)] - private static void ClearCache() - { - Caching.CleanCache(); - } - - [MenuItem("Build/AssetBundles/Delete Bundles", false, 52)] - private static void DeleteBundles() - { - if (Directory.Exists(BuildAssetBundlesSettings.buildPath)) - FileUtil.DeleteFileOrDirectory(BuildAssetBundlesSettings.buildPath); - } - - #endregion - - #region Public Methods - - public override void Execute(BuildPlatform platform) - { - Build(platform); - } - - #endregion - - #region Private Methods - - private static void BuildAll() - { - for (int i = 0; i < BuildProject.platforms.Count; i++) - { - BuildPlatform platform = BuildProject.platforms[i]; - Build(platform); - } - } - - private static void Build(BuildPlatform platform) - { - if (!platform.buildEnabled) - return; - - // Path where this platform's AssetBundles will be built. - string platformBundlePath = BuildAssetBundlesSettings.buildPath + Path.DirectorySeparatorChar + platform.name; - - // Create build destination directory if it does not exist. - if (!Directory.Exists(platformBundlePath)) - Directory.CreateDirectory(platformBundlePath); - - // Build AssetBundles. - BuildPipeline.BuildAssetBundles(platformBundlePath, BuildAssetBundleOptions.None, platform.target); - - // Copy AssetBundles to platform's data directory. - if (BuildAssetBundlesSettings.copyToBuild && Directory.Exists(platformBundlePath)) - { - string bundleDirectory = platform.dataDirectory + "Bundles" + Path.DirectorySeparatorChar; - string targetPath = bundleDirectory + platform.name; - - if (Directory.Exists(bundleDirectory)) - FileUtil.DeleteFileOrDirectory(bundleDirectory); - - Directory.CreateDirectory(bundleDirectory); - FileUtil.CopyFileOrDirectory(platformBundlePath + Path.DirectorySeparatorChar, targetPath); - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/AssetBundles/BuildAssetBundlesSettings.cs b/Editor/AssetBundles/BuildAssetBundlesSettings.cs deleted file mode 100644 index 63df6e1..0000000 --- a/Editor/AssetBundles/BuildAssetBundlesSettings.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace UnityBuild -{ - -[InitializeOnLoad] -public class BuildAssetBundlesSettings : BaseSettings -{ - #region Singleton - - private static BuildAssetBundlesSettings instance = null; - - public static BuildAssetBundlesSettings Instance - { - get - { - if (instance == null) - { - instance = CreateAsset("BuildAssetBundlesSettings"); - } - - return instance; - } - } - - #endregion - - #region MenuItems - - [MenuItem("Build/AssetBundles/Edit Settings", priority = 0)] - public static void EditSettings() - { - Selection.activeObject = Instance; - EditorApplication.ExecuteMenuItem("Window/Inspector"); - } - - #endregion - - #region Variables - - [Header("AssetBundle Build Settings (Field Info in Tooltips)")] - - /// - /// The path where AssetBundles are built. {0} = binPath - /// - [SerializeField] - [Tooltip("The path where AssetBundles are built. {0} = binPath")] - private string _buildPath = "{0}/Bundles"; - - /// - /// Flag indicating if the AssetBundles should be copied into the game's data directory. - /// - [SerializeField] - [Tooltip("Flag indicating if the AssetBundles should be copied into the game's data directory.")] - private bool _copyToBuild = true; - - #endregion - - #region Public Properties - - public static string buildPath - { - get - { - return string.Format(Instance._buildPath, BuildSettings.binPath); - } - } - - public static bool copyToBuild - { - get - { - return Instance._copyToBuild; - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Build/Action/BuildAction.cs b/Editor/Build/Action/BuildAction.cs index 15a8a9d..642228e 100644 --- a/Editor/Build/Action/BuildAction.cs +++ b/Editor/Build/Action/BuildAction.cs @@ -1,49 +1,105 @@ -using System; +using UnityEditor; using UnityEngine; -using UnityEditor; -namespace UnityBuild +namespace SuperSystems.UnityBuild { -public abstract class BuildAction : IComparable +[System.Serializable] +public class BuildAction : ScriptableObject // This really should be an abstract class but needs to be concrete to work with Unity serialization. { + public enum ActionType + { + SingleRun, + PerPlatform + } + + public ActionType actionType = ActionType.PerPlatform; + public string actionName = string.Empty; + public string note = string.Empty; + public BuildFilter filter = new BuildFilter(); + /// - /// Build action. + /// This will be exectued once before/after all players are built. /// public virtual void Execute() { } /// - /// Platform-specific build action. + /// This will be executed before/after each individual player is built. /// - /// - public virtual void Execute(BuildPlatform platform) + public virtual void PerBuildExecute( + BuildReleaseType releaseType, + BuildPlatform platform, + BuildArchitecture architecture, + BuildDistribution distribution, + System.DateTime buildTime, ref BuildOptions options, string configKey, string buildPath) { } - /// - /// Priority of this build action. Lower values execute earlier. - /// - public virtual int priority + public void Draw(SerializedObject obj) { - get + DrawProperties(obj); + + System.Type myType = this.GetType(); + bool actionTypeSelectable = false; + if (typeof(IPreBuildAction).IsAssignableFrom(myType) && + typeof(IPreBuildPerPlatformAction).IsAssignableFrom(myType)) { - return 100; + actionTypeSelectable = true; + } + else if (typeof(IPostBuildAction).IsAssignableFrom(myType) && + typeof(IPostBuildPerPlatformAction).IsAssignableFrom(myType)) + { + actionTypeSelectable = true; + } + else if (typeof(IPreBuildAction).IsAssignableFrom(myType) || + typeof(IPostBuildAction).IsAssignableFrom(myType)) + { + actionType = ActionType.SingleRun; + } + else if (typeof(IPreBuildPerPlatformAction).IsAssignableFrom(myType) || + typeof(IPostBuildPerPlatformAction).IsAssignableFrom(myType)) + { + actionType = ActionType.PerPlatform; } - } - #region IComparable + if (actionTypeSelectable) + { + actionType = (ActionType)EditorGUILayout.EnumPopup("Action Type", actionType); + } + EditorGUILayout.PropertyField(obj.FindProperty("note")); + EditorGUILayout.PropertyField(obj.FindProperty("filter"), GUILayout.Height(0)); + obj.ApplyModifiedProperties(); + } - public int CompareTo(BuildAction other) + protected virtual void DrawProperties(SerializedObject obj) { - if (other == null) - return 1; - else - return priority.CompareTo(other.priority); - } + SerializedProperty prop = obj.GetIterator(); + bool done = false; - #endregion + while (!done && prop != null) + { + if (prop.name == "actionName" || + prop.name == "actionType" || + prop.name == "note" || + prop.name == "filter") + { + // Already drawn these. Go to next, don't enter into object. + done = !prop.NextVisible(false); + } + else if (prop.name == "Base") + { + // Valid property we want to enter, but don't want to draw the parent node. + done = !prop.NextVisible(true); + } + else + { + EditorGUILayout.PropertyField(prop); + done = !prop.NextVisible(true); + } + } + } } -} \ No newline at end of file +} diff --git a/Editor/Build/Action/BuildActionList.cs b/Editor/Build/Action/BuildActionList.cs new file mode 100644 index 0000000..2dee686 --- /dev/null +++ b/Editor/Build/Action/BuildActionList.cs @@ -0,0 +1,11 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildActionList +{ + public BuildAction[] buildActions = new BuildAction[] { }; +} + +} diff --git a/Editor/AssetBundles/BuildAssetBundlesSettings.cs.meta b/Editor/Build/Action/BuildActionList.cs.meta similarity index 75% rename from Editor/AssetBundles/BuildAssetBundlesSettings.cs.meta rename to Editor/Build/Action/BuildActionList.cs.meta index 76569f3..0e743f4 100644 --- a/Editor/AssetBundles/BuildAssetBundlesSettings.cs.meta +++ b/Editor/Build/Action/BuildActionList.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 19340d8daaff4f14d98ca88d6348cc3f -timeCreated: 1461244919 +guid: 0183546484d8b2d4ba9664b56d8ad7bb +timeCreated: 1483573606 licenseType: Pro MonoImporter: serializedVersion: 2 diff --git a/Editor/Build/Action/BuildActionListUtility.cs b/Editor/Build/Action/BuildActionListUtility.cs new file mode 100644 index 0000000..97fca1b --- /dev/null +++ b/Editor/Build/Action/BuildActionListUtility.cs @@ -0,0 +1,52 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[InitializeOnLoad] +public sealed class BuildActionListUtility +{ + public static List preBuildActions = new List(); + public static List postBuildActions = new List(); + + #region Contructor + + /// + /// Constructor + /// + static BuildActionListUtility() + { + // Find all classes that inherit from PostBuildAction and register them. + Type ti = typeof(BuildAction); + + foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (Type t in asm.GetTypes()) + { + if (ti.IsAssignableFrom(t) && ti != t) + { + // We've found a BuildAction, now check what interfaces it implements. + if (typeof(IPreBuildAction).IsAssignableFrom(t) || + typeof(IPreBuildPerPlatformAction).IsAssignableFrom(t)) + { + preBuildActions.Add(t); + } + + if (typeof(IPostBuildAction).IsAssignableFrom(t) || + typeof(IPostBuildPerPlatformAction).IsAssignableFrom(t)) + { + postBuildActions.Add(t); + } + } + } + } + } + + #endregion +} + +} diff --git a/Editor/Build/Action/PostBuildAction.cs.meta b/Editor/Build/Action/BuildActionListUtility.cs.meta similarity index 100% rename from Editor/Build/Action/PostBuildAction.cs.meta rename to Editor/Build/Action/BuildActionListUtility.cs.meta diff --git a/Editor/Build/Action/BuildFilter.cs b/Editor/Build/Action/BuildFilter.cs new file mode 100644 index 0000000..b731a9e --- /dev/null +++ b/Editor/Build/Action/BuildFilter.cs @@ -0,0 +1,145 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildFilter +{ + #region Constants and Enums + + public enum FilterCondition + { + Any, + ExactlyOne, + All, + None + } + + public enum FilterType + { + ReleaseType, + Platform, + Architecture, + Distribution, + FullConfigurationKey + } + + public enum FilterComparison + { + Equals, + Contains + } + + #endregion + + public FilterCondition condition; + public FilterClause[] clauses; + + public bool Evaluate(BuildReleaseType releaseType, BuildPlatform platform, BuildArchitecture architecture, BuildDistribution distribution, string configKeychain) + { + if (clauses == null || clauses.Length == 0) + return true; + + // Set default state for success based on condition type. + bool success = true; + if (condition == FilterCondition.Any || + condition == FilterCondition.ExactlyOne) + { + success = false; + } + + for (int i = 0; i < clauses.Length; i++) + { + if (condition == FilterCondition.Any) + { + // Succeed as soon as any test evaluates true. + success |= clauses[i].Evaluate(releaseType, platform, architecture, distribution, configKeychain); + if (success) + break; + } + else if (condition == FilterCondition.All) + { + // Succeed only if all tests evaluate true. + success &= clauses[i].Evaluate(releaseType, platform, architecture, distribution, configKeychain); + if (!success) + break; + } + else if (condition == FilterCondition.None) + { + // Succeed only if all tests fail. + success &= !(clauses[i].Evaluate(releaseType, platform, architecture, distribution, configKeychain)); + if (!success) + break; + } + else if (condition == FilterCondition.ExactlyOne) + { + // Succeed only if exactly one test evaluates true. + if (clauses[i].Evaluate(releaseType, platform, architecture, distribution, configKeychain)) + { + if (success) + { + // Another test already succeeded, so this is a failure. + success = false; + break; + } + else + { + success = true; + } + } + } + } + + return success; + } + + [System.Serializable] + public class FilterClause + { + public FilterType type; + public FilterComparison comparison; + public string test; + + public bool Evaluate(BuildReleaseType releaseType, BuildPlatform platform, BuildArchitecture architecture, BuildDistribution distribution, string configKeychain) + { + bool success = false; + + test = test.Trim().ToUpper(); + + switch (type) + { + case FilterType.ReleaseType: + success = PerformTest(releaseType.typeName); + break; + case FilterType.Platform: + success = PerformTest(platform.platformName); + break; + case FilterType.Architecture: + success = PerformTest(architecture.name); + break; + case FilterType.Distribution: + success = PerformTest(distribution.distributionName); + break; + case FilterType.FullConfigurationKey: + success = PerformTest(configKeychain); + break; + } + + return success; + } + + private bool PerformTest(string targetString) + { + if (comparison == FilterComparison.Equals) + { + return targetString.Equals(test, System.StringComparison.OrdinalIgnoreCase); + } + else + { + return targetString.ToUpper().Contains(test); + } + } + } +} + +} diff --git a/Editor/AssetBundles/BuildAssetBundles.cs.meta b/Editor/Build/Action/BuildFilter.cs.meta similarity index 75% rename from Editor/AssetBundles/BuildAssetBundles.cs.meta rename to Editor/Build/Action/BuildFilter.cs.meta index 5c500f7..36ca999 100644 --- a/Editor/AssetBundles/BuildAssetBundles.cs.meta +++ b/Editor/Build/Action/BuildFilter.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 247b8125b49f93e49a12e3673f0d67ae -timeCreated: 1460728312 +guid: 7389136ee67103749a841811586a0764 +timeCreated: 1483487186 licenseType: Pro MonoImporter: serializedVersion: 2 diff --git a/Editor/AssetBundles.meta b/Editor/Build/Action/Interfaces.meta similarity index 67% rename from Editor/AssetBundles.meta rename to Editor/Build/Action/Interfaces.meta index e6de942..3c34e52 100644 --- a/Editor/AssetBundles.meta +++ b/Editor/Build/Action/Interfaces.meta @@ -1,7 +1,7 @@ fileFormatVersion: 2 -guid: b4a3643570d803941b01fd0d1e82c807 +guid: 32a6ad6f49fe80b45a4ca1651b95c907 folderAsset: yes -timeCreated: 1460729239 +timeCreated: 1484097596 licenseType: Pro DefaultImporter: userData: diff --git a/Editor/Build/Action/Interfaces/IPostBuildAction.cs b/Editor/Build/Action/Interfaces/IPostBuildAction.cs new file mode 100644 index 0000000..401232d --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPostBuildAction.cs @@ -0,0 +1,4 @@ + +public interface IPostBuildAction +{ +} diff --git a/Editor/Build/Action/PreBuildAction.cs.meta b/Editor/Build/Action/Interfaces/IPostBuildAction.cs.meta similarity index 75% rename from Editor/Build/Action/PreBuildAction.cs.meta rename to Editor/Build/Action/Interfaces/IPostBuildAction.cs.meta index 39a9841..67ae566 100644 --- a/Editor/Build/Action/PreBuildAction.cs.meta +++ b/Editor/Build/Action/Interfaces/IPostBuildAction.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: c6fb88c3dec54c14cab1f5b873bc2e04 -timeCreated: 1460729240 +guid: 5c50bbb415df9df48a72b9086fd70ae6 +timeCreated: 1484097596 licenseType: Pro MonoImporter: serializedVersion: 2 diff --git a/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs b/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs new file mode 100644 index 0000000..b8d4025 --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs @@ -0,0 +1,4 @@ + +public interface IPostBuildPerPlatformAction +{ +} diff --git a/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs.meta b/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs.meta new file mode 100644 index 0000000..b095a9f --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPostBuildPerPlatformAction.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 44ba0611b92ee6d47a1dc8245ddbf53c +timeCreated: 1484097596 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Action/Interfaces/IPreBuildAction.cs b/Editor/Build/Action/Interfaces/IPreBuildAction.cs new file mode 100644 index 0000000..35ecb46 --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPreBuildAction.cs @@ -0,0 +1,4 @@ + +public interface IPreBuildAction +{ +} diff --git a/Editor/Build/Action/Interfaces/IPreBuildAction.cs.meta b/Editor/Build/Action/Interfaces/IPreBuildAction.cs.meta new file mode 100644 index 0000000..eaa666d --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPreBuildAction.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1c22f9c2806366845b22829cdd93f379 +timeCreated: 1484097596 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs b/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs new file mode 100644 index 0000000..d8f9ddd --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs @@ -0,0 +1,4 @@ + +public interface IPreBuildPerPlatformAction +{ +} diff --git a/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs.meta b/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs.meta new file mode 100644 index 0000000..252f1c8 --- /dev/null +++ b/Editor/Build/Action/Interfaces/IPreBuildPerPlatformAction.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f1cd2c380e3ff934a9e7dc62d99f507c +timeCreated: 1484097596 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Action/PostBuildAction.cs b/Editor/Build/Action/PostBuildAction.cs deleted file mode 100644 index 17bec93..0000000 --- a/Editor/Build/Action/PostBuildAction.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Reflection; -using UnityEditor; - -namespace UnityBuild -{ - -[InitializeOnLoad] -public abstract class PostBuildAction : BuildAction -{ - #region Contructor - - /// - /// Constructor - /// - static PostBuildAction() - { - // Find all classes that inherit from BuildPlatform and register them with BuildProject. - Type ti = typeof(PostBuildAction); - - foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (Type t in asm.GetTypes()) - { - if (ti.IsAssignableFrom(t) && ti != t) - { - BuildProject.RegisterPostBuildAction((BuildAction)Activator.CreateInstance(t)); - } - } - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Build/Action/PreBuildAction.cs b/Editor/Build/Action/PreBuildAction.cs deleted file mode 100644 index 4b47a06..0000000 --- a/Editor/Build/Action/PreBuildAction.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Reflection; -using UnityEditor; - -namespace UnityBuild -{ - -[InitializeOnLoad] -public abstract class PreBuildAction : BuildAction -{ - #region Contructor - - /// - /// Constructor - /// - static PreBuildAction() - { - // Find all classes that inherit from BuildPlatform and register them with BuildProject. - Type ti = typeof(PreBuildAction); - - foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (Type t in asm.GetTypes()) - { - if (ti.IsAssignableFrom(t) && ti != t) - { - BuildProject.RegisterPreBuildAction((BuildAction)Activator.CreateInstance(t)); - } - } - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Build/Action/UI/BuildActionListDrawer.cs b/Editor/Build/Action/UI/BuildActionListDrawer.cs new file mode 100644 index 0000000..02cfe28 --- /dev/null +++ b/Editor/Build/Action/UI/BuildActionListDrawer.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildActionList))] +public class BuildActionListDrawer : PropertyDrawer +{ + private int index = 0; + private SerializedProperty list = null; + + [SerializeField] + private BuildAction buildAction; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + EditorGUILayout.BeginHorizontal(); + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader(label.text, ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#build-actions"); + EditorGUILayout.EndHorizontal(); + + list = property.FindPropertyRelative("buildActions"); + + List actionTypes; + if (property.name.ToUpper().Contains("PRE")) + { + actionTypes = BuildActionListUtility.preBuildActions; + } + else + { + actionTypes = BuildActionListUtility.postBuildActions; + } + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = 0; i < list.arraySize; i++) + { + SerializedProperty listEntry = list.GetArrayElementAtIndex(i); + + BuildAction buildAction = listEntry.objectReferenceValue as BuildAction; + SerializedObject serializedBuildAction = new SerializedObject(buildAction); + + EditorGUILayout.BeginHorizontal(); + show = listEntry.isExpanded; + UnityBuildGUIUtility.DropdownHeader(buildAction.actionName, ref show, false, GUILayout.ExpandWidth(true)); + listEntry.isExpanded = show; + + EditorGUI.BeginDisabledGroup(i == 0); + if (GUILayout.Button("↑↑", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, 0); + } + if (GUILayout.Button("↑", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, i - 1); + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.BeginDisabledGroup(i == list.arraySize - 1); + if (GUILayout.Button("↓", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, i + 1); + } + EditorGUI.EndDisabledGroup(); + + if (GUILayout.Button("X", UnityBuildGUIUtility.helpButtonStyle)) + { + BuildAction[] buildActions; + if (property.name.ToUpper().Contains("PRE")) + { + buildActions = BuildSettings.preBuildActions.buildActions; + } + else + { + buildActions = BuildSettings.postBuildActions.buildActions; + } + + // Destroy underlying object. + ScriptableObject.DestroyImmediate(buildActions[i], true); + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(BuildSettings.instance)); + + // Remove object reference from list. + // TODO: Why do I need to call this twice? First call nulls reference, second one then deletes null entry. + list.DeleteArrayElementAtIndex(i); + list.DeleteArrayElementAtIndex(i); + show = false; + } + + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + buildAction.Draw(serializedBuildAction); + EditorGUILayout.EndVertical(); + } + } + + if (list.arraySize > 0) + { + GUILayout.Space(20); + } + + if (actionTypes.Count > 0) + { + GUILayout.BeginHorizontal(); + + string[] buildActionNameList = new string[actionTypes.Count]; + for (int i = 0; i < buildActionNameList.Length; i++) + { + buildActionNameList[i] = actionTypes[i].Name; + } + + index = EditorGUILayout.Popup(index, buildActionNameList, UnityBuildGUIUtility.popupStyle, GUILayout.ExpandWidth(true)); + if (GUILayout.Button("Add Build Action", GUILayout.ExpandWidth(false), GUILayout.MaxWidth(150)) && index < actionTypes.Count) + { + Type addedType = actionTypes[index]; + + int addedIndex = list.arraySize; + list.InsertArrayElementAtIndex(addedIndex); + list.serializedObject.ApplyModifiedProperties(); + + BuildAction[] buildActions; + if (property.name.ToUpper().Contains("PRE")) + { + buildActions = BuildSettings.preBuildActions.buildActions; + } + else + { + buildActions = BuildSettings.postBuildActions.buildActions; + } + + //buildActions[addedIndex] = Activator.CreateInstance(addedType) as BuildAction; + buildActions[addedIndex] = ScriptableObject.CreateInstance(addedType) as BuildAction; + buildActions[addedIndex].name = addedType.Name; + buildActions[addedIndex].actionName = addedType.Name; + buildActions[addedIndex].filter = new BuildFilter(); + + AssetDatabase.AddObjectToAsset(buildActions[addedIndex], BuildSettings.instance); + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(BuildSettings.instance)); + + index = 0; + } + + GUILayout.EndHorizontal(); + } + else + { + EditorGUILayout.HelpBox("No Build Actions found.", MessageType.Info); + } + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Action/UI/BuildActionListDrawer.cs.meta b/Editor/Build/Action/UI/BuildActionListDrawer.cs.meta new file mode 100644 index 0000000..5febb3e --- /dev/null +++ b/Editor/Build/Action/UI/BuildActionListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1c629e1cb4293be46bc35142bfedad02 +timeCreated: 1483573607 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Action/UI/BuildFilterDrawer.cs b/Editor/Build/Action/UI/BuildFilterDrawer.cs new file mode 100644 index 0000000..5567b43 --- /dev/null +++ b/Editor/Build/Action/UI/BuildFilterDrawer.cs @@ -0,0 +1,106 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildFilter))] +public class BuildFilterDrawer : PropertyDrawer +{ + private SerializedProperty list; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + + list = property.FindPropertyRelative("clauses"); + + // If no clauses present, only display a button to add one. + if (list.arraySize == 0) + { + if (GUILayout.Button("Add Filter", GUILayout.ExpandWidth(true))) + { + AddClause(); + property.isExpanded = true; + } + + return; + } + + EditorGUILayout.BeginHorizontal(); + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Filter", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + EditorGUILayout.BeginHorizontal(); + SerializedProperty condition = property.FindPropertyRelative("condition"); + + EditorGUILayout.LabelField("Run this BuildAction if", GUILayout.Width(130)); + BuildFilter.FilterCondition modifiedCondition = (BuildFilter.FilterCondition)EditorGUILayout.EnumPopup((BuildFilter.FilterCondition)condition.enumValueIndex, GUILayout.Width(95)); + condition.enumValueIndex = (int)modifiedCondition; + EditorGUILayout.LabelField("of these conditions is/are true.", GUILayout.ExpandWidth(false)); + + EditorGUILayout.EndHorizontal(); + + GUILayout.Space(20); + + for (int i = 0; i < list.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + + SerializedProperty listEntry = list.GetArrayElementAtIndex(i); + SerializedProperty testType = listEntry.FindPropertyRelative("type"); + SerializedProperty testComparison = listEntry.FindPropertyRelative("comparison"); + SerializedProperty testValue = listEntry.FindPropertyRelative("test"); + + BuildFilter.FilterType modifiedType = (BuildFilter.FilterType)EditorGUILayout.EnumPopup((BuildFilter.FilterType)testType.enumValueIndex, GUILayout.ExpandWidth(false), GUILayout.Width(140)); + BuildFilter.FilterComparison modifiedComparison = (BuildFilter.FilterComparison)EditorGUILayout.EnumPopup((BuildFilter.FilterComparison)testComparison.enumValueIndex, GUILayout.ExpandWidth(false), GUILayout.Width(100)); + testType.enumValueIndex = (int)modifiedType; + testComparison.enumValueIndex = (int)modifiedComparison; + + testValue.stringValue = GUILayout.TextField(testValue.stringValue); + + if (GUILayout.Button("X", UnityBuildGUIUtility.helpButtonStyle)) + { + list.DeleteArrayElementAtIndex(i); + list.serializedObject.ApplyModifiedProperties(); + } + + EditorGUILayout.EndHorizontal(); + } + + if (GUILayout.Button("Add Condition", GUILayout.ExpandWidth(true))) + { + AddClause(); + } + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } + + private void AddClause() + { + // Add. + int addedIndex = list.arraySize; + list.InsertArrayElementAtIndex(addedIndex); + + // Initialize. + SerializedProperty addedClause = list.GetArrayElementAtIndex(addedIndex); + addedClause.FindPropertyRelative("type").enumValueIndex = 0; + addedClause.FindPropertyRelative("comparison").enumValueIndex = 0; + addedClause.FindPropertyRelative("test").stringValue = string.Empty; + + // Apply. + list.serializedObject.ApplyModifiedProperties(); + } +} + +} diff --git a/Editor/Build/Action/UI/BuildFilterDrawer.cs.meta b/Editor/Build/Action/UI/BuildFilterDrawer.cs.meta new file mode 100644 index 0000000..577cd19 --- /dev/null +++ b/Editor/Build/Action/UI/BuildFilterDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 282fa16bf78b2124a836b446f4587bed +timeCreated: 1483740021 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildCLI.cs b/Editor/Build/BuildCLI.cs index ded7fb0..76136ea 100644 --- a/Editor/Build/BuildCLI.cs +++ b/Editor/Build/BuildCLI.cs @@ -1,7 +1,5 @@ -using UnityEngine; -using UnityEditor; - -namespace UnityBuild + +namespace SuperSystems.UnityBuild { public static class BuildCLI diff --git a/Editor/Build/BuildProject.cs b/Editor/Build/BuildProject.cs index 0724b83..e99e414 100644 --- a/Editor/Build/BuildProject.cs +++ b/Editor/Build/BuildProject.cs @@ -1,216 +1,419 @@ -using UnityEngine; -using System.Collections; -using UnityEditor; -using System.IO; +using System; using System.Collections.Generic; +using System.IO; +using System.Reflection; using System.Text; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; -namespace UnityBuild +namespace SuperSystems.UnityBuild { public static class BuildProject { - #region Public Variables & Auto-Properties - - public static List platforms { get; private set; } - public static List preBuildActions { get; private set; } - public static List postBuildActions { get; private set; } + #region Public Methods - #endregion + public static void BuildAll() + { + string[] buildConfigs = BuildSettings.projectConfigurations.BuildAllKeychains(); + PerformBuild(buildConfigs); + } - #region MenuItems + public static void BuildSingle(string keyChain, BuildOptions options = BuildOptions.None) + { + string[] buildConfigs = new string[] { keyChain }; + PerformBuild(buildConfigs, options); + } - /// - /// Build all enabled platforms. - /// - [MenuItem("Build/Run Build", false, 1)] - public static void BuildAll() + public static string GenerateDefaultDefines(BuildReleaseType releaseType, BuildPlatform buildPlatform, BuildArchitecture arch, BuildDistribution dist) { - if (preBuildActions != null) - preBuildActions.Sort(); + List defines = new List(); + + if (releaseType != null) + defines.Add("BUILD_TYPE_" + SanitizeCodeString(releaseType.typeName.ToUpper().Replace(" ", ""))); - if (postBuildActions != null) - postBuildActions.Sort(); + if (buildPlatform != null) + defines.Add("BUILD_PLATFORM_" + SanitizeCodeString(buildPlatform.platformName.ToUpper().Replace(" ", ""))); - PerformPreBuild(); + if (arch != null) + defines.Add("BUILD_ARCH_" + SanitizeCodeString(arch.name.ToUpper().Replace(" ", ""))); - for (int i = 0; i < platforms.Count; i++) + if (dist != null) + defines.Add("BUILD_DIST_" + SanitizeCodeString(dist.distributionName.ToUpper().Replace(" ", ""))); + + if (releaseType != null && !string.IsNullOrEmpty(releaseType.customDefines)) { - BuildPlatform platform = platforms[i]; - if (platform.buildEnabled) + string[] customDefines = releaseType.customDefines.Split(';', ','); + for (int i = 0; i < customDefines.Length; i++) { - PerformPreBuild(platform); - platform.Build(); - PerformPostBuild(platform); + defines.Add(SanitizeCodeString(customDefines[i]).ToUpper()); } } - PerformPostBuild(); + return string.Join(";", defines.ToArray()); } - /// - /// Enable building of all platforms. - /// - [MenuItem("Build/Platforms/Enable All", false, 50)] - private static void EnableAllPlatforms() + public static string GenerateVersionString(ProductParameters productParameters, DateTime buildTime) { - SetAllBuildPlatforms(true); - } + string prototypeString = productParameters.version; + StringBuilder sb = new StringBuilder(prototypeString); - /// - /// Disable building of all platforms. - /// - [MenuItem("Build/Platforms/Disable All", false, 50)] - private static void DisableAllPlatforms() - { - SetAllBuildPlatforms(false); - } + // Regex = (?:\$DAYSSINCE\(")([^"]*)(?:"\)) + Match match = Regex.Match(prototypeString, "(?:\\$DAYSSINCE\\(\")([^\"]*)(?:\"\\))"); + while (match.Success) + { + DateTime parsedTime; + int daysSince = 0; + if (DateTime.TryParse(match.Groups[1].Value, out parsedTime)) + { + daysSince = buildTime.Subtract(parsedTime).Days; + } + + sb.Replace(match.Captures[0].Value, daysSince.ToString()); + match = match.NextMatch(); + } - #endregion + ReplaceFromFile(sb, "$NOUN", "nouns.txt"); + ReplaceFromFile(sb, "$ADJECTIVE", "adjectives.txt"); - #region Register Methods + sb.Replace("$SECONDS", (buildTime.TimeOfDay.TotalSeconds / 15f).ToString("F0")); - /// - /// Register a platform that can be built. - /// - /// - public static void RegisterPlatform(BuildPlatform platform) - { - if (platforms == null) - platforms = new List(); + sb.Replace("$YEAR", buildTime.ToString("yyyy")); + sb.Replace("$MONTH", buildTime.ToString("MM")); + sb.Replace("$DAY", buildTime.ToString("dd")); + sb.Replace("$TIME", buildTime.ToString("hhmmss")); - platforms.Add(platform); + sb.Replace("$BUILD", (++productParameters.buildCounter).ToString()); + + string retVal = sb.ToString(); + productParameters.lastGeneratedVersion = retVal; + + return retVal; } - /// - /// Register a pre-build action. - /// - /// - public static void RegisterPreBuildAction(BuildAction action) + public static string GenerateBuildPath(string prototype, BuildReleaseType releaseType, BuildPlatform buildPlatform, BuildArchitecture arch, BuildDistribution dist, DateTime buildTime) { - if (preBuildActions == null) - preBuildActions = new List(); + string resolvedProto = ResolvePath(prototype, releaseType, buildPlatform, arch, dist, buildTime); + string buildPath = Path.Combine(BuildSettings.basicSettings.baseBuildFolder, resolvedProto); + buildPath = Path.GetFullPath(buildPath); - preBuildActions.Add(action); + return buildPath; } - /// - /// Register a post-build action. - /// - /// - public static void RegisterPostBuildAction(BuildAction action) + public static string ResolvePath(string prototype, BuildReleaseType releaseType, BuildPlatform buildPlatform, BuildArchitecture arch, BuildDistribution dist, DateTime buildTime) { - if (postBuildActions == null) - postBuildActions = new List(); + StringBuilder sb = new StringBuilder(prototype); + + sb.Replace("$YEAR", buildTime.ToString("yyyy")); + sb.Replace("$MONTH", buildTime.ToString("MM")); + sb.Replace("$DAY", buildTime.ToString("dd")); + sb.Replace("$TIME", buildTime.ToString("hhmmss")); + + sb.Replace("$RELEASE_TYPE", SanitizeFolderName(releaseType.typeName)); + sb.Replace("$PLATFORM", SanitizeFolderName(buildPlatform.platformName)); + sb.Replace("$ARCHITECTURE", SanitizeFolderName(arch.name)); + sb.Replace("$DISTRIBUTION", SanitizeFolderName(dist != null ? dist.distributionName : BuildConstantsGenerator.NONE)); + sb.Replace("$VERSION", SanitizeFolderName(BuildSettings.productParameters.lastGeneratedVersion)); + sb.Replace("$BUILD", BuildSettings.productParameters.buildCounter.ToString()); + sb.Replace("$PRODUCT_NAME", SanitizeFolderName(releaseType.productName)); + + return sb.ToString(); + } - postBuildActions.Add(action); + // TODO: Convert sanitize string methods into extensions. + public static string SanitizeCodeString(string str) + { + str = Regex.Replace(str, "[^a-zA-Z0-9_]", "_", RegexOptions.Compiled); + if (char.IsDigit(str[0])) + { + str = "_" + str; + } + return str; } - #endregion + public static string SanitizeFolderName(string folderName) + { + string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())); + string invalidRegStr = string.Format(@"[{0}]", invalidChars); - #region Public Methods + return Regex.Replace(folderName, invalidRegStr, ""); + } - /// - /// Perform build of a platform. - /// - /// - public static void PerformBuild(BuildPlatform platform) + public static string SanitizeFileName(string fileName) { - // Build player. - Debug.Log("Building " + platform.name); - FileUtil.DeleteFileOrDirectory(platform.buildPath); + string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars())); + string invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars); - switch (platform.target) - { - case BuildTarget.Android: - Directory.CreateDirectory(platform.buildPath + platform.exeName); - break; - } + return Regex.Replace(fileName, invalidRegStr, "_"); + } - BuildPipeline.BuildPlayer(BuildSettings.scenesInBuild, platform.buildPath + platform.exeName, platform.target, BuildOptions.None); + #endregion - // Copy any other data. - for (int i = 0; i < BuildSettings.copyToBuild.Length; i++) - { - string item = BuildSettings.copyToBuild[i]; + #region Private Methods - // Log an error if file/directory does not exist. - if (!File.Exists(item) && !Directory.Exists(item)) + private static void ReplaceFromFile(StringBuilder sb, string keyString, string filename) + { + if (sb.ToString().IndexOf(keyString) > -1) + { + string[] fileSearchResults = Directory.GetFiles(Application.dataPath, filename, SearchOption.AllDirectories); + string filePath = null; + string desiredFilePath = string.Format("UnityBuild{0}Editor{0}{1}", Path.DirectorySeparatorChar, filename); + for (int i = 0; i < fileSearchResults.Length; i++) { - Debug.LogError("Item to copy does not exist: " + item); - continue; + if (fileSearchResults[i].EndsWith(desiredFilePath)) + { + filePath = fileSearchResults[i]; + break; + } } - // Copy the file/directory. - if (Path.HasExtension(item)) - { - string filename = Path.GetFileName(item); - FileUtil.CopyFileOrDirectory(item, platform.dataDirectory + filename); - } - else + if (!string.IsNullOrEmpty(filePath)) { - string dirname = Path.GetFileName(item.TrimEnd('/').TrimEnd('\\')); - FileUtil.CopyFileOrDirectory(item, platform.dataDirectory + dirname); + string[] lines = File.ReadAllLines(filePath); + + int index = sb.ToString().IndexOf(keyString, 0); + while (index > -1) + { + string noun = lines[UnityEngine.Random.Range(0, lines.Length - 1)].ToUpper(); + sb.Replace(keyString, noun, index, keyString.Length); + index = sb.ToString().IndexOf(keyString, index + 1); + } } } } - #endregion + private static void PerformBuild(string[] buildConfigs, BuildOptions options = BuildOptions.None) + { + int successCount = 0; + int failCount = 0; - #region Private Methods + DateTime buildTime; + PerformPreBuild(out buildTime); + + for (int i = 0; i < buildConfigs.Length; i++) + { + BuildReleaseType releaseType; + BuildPlatform platform; + BuildArchitecture arch; + BuildDistribution dist; + string configKey = buildConfigs[i]; + + // Parse build config and perform build. + string notification = string.Format("Building ({0}/{1}): ", i + 1, buildConfigs.Length); + BuildSettings.projectConfigurations.ParseKeychain(configKey, out releaseType, out platform, out arch, out dist); + bool success = BuildPlayer(notification, releaseType, platform, arch, dist, buildTime, options, configKey); + + if (success) + ++successCount; + else + ++failCount; + } - private static void SetAllBuildPlatforms(bool enabled) + PerformPostBuild(); + + // Report success/failure. + StringBuilder sb = new StringBuilder(); + if (failCount == 0) + { + sb.AppendFormat("{0} successful build{1}. No failures. ✔️", + successCount, successCount > 1 ? "s" : ""); + } + else if (successCount == 0) + { + sb.AppendFormat("No successful builds. {0} failure{1}. ✖️", + failCount, failCount > 1 ? "s" : ""); + } + else + { + sb.AppendFormat("{0} successful build{1}. {2} failure{3}.", + successCount, successCount > 1 ? "s" : "", + failCount, failCount > 1 ? "s" : ""); + } + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + "Build Complete.", sb.ToString(), + true, null)); + + // Open output folder if option is enabled. + if (BuildSettings.basicSettings.openFolderPostBuild) + { + System.Diagnostics.Process.Start(BuildSettings.basicSettings.baseBuildFolder); + } + } + + private static bool BuildPlayer(string notification, BuildReleaseType releaseType, BuildPlatform platform, BuildArchitecture architecture, BuildDistribution distribution, DateTime buildTime, BuildOptions options, string configKey) { - for (int i = 0; i < platforms.Count; i++) + bool success = true; + + // Get build options. + if (releaseType.developmentBuild) + options |= BuildOptions.Development; + if (releaseType.allowDebugging) + options |= BuildOptions.AllowDebugging; + + // Generate build path. + string buildPath = GenerateBuildPath(BuildSettings.basicSettings.buildPath, releaseType, platform, architecture, distribution, buildTime); + string exeName = string.Format(platform.binaryNameFormat, SanitizeFileName(releaseType.productName)); + + // Pre-build actions. + PerformPreBuild(releaseType, platform, architecture, distribution, buildTime, ref options, configKey, buildPath); + + // Generate BuildConstants. + BuildConstantsGenerator.Generate(buildTime, BuildSettings.productParameters.lastGeneratedVersion, releaseType, platform, architecture, distribution); + + // Refresh scene list to make sure nothing has been deleted or moved. + releaseType.sceneList.Refresh(); + + // Report build starting. + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + notification, configKey, + true, null)); + + // Build player. + FileUtil.DeleteFileOrDirectory(buildPath); + string error = BuildPipeline.BuildPlayer(releaseType.sceneList.GetSceneList(), Path.Combine(buildPath, exeName), architecture.target, options); + + if (!string.IsNullOrEmpty(error)) { - EditorPrefs.SetBool("buildGame" + platforms[i].name, enabled); + success = false; + + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Error, + "Build Failed:", configKey.ToString() + "\n" + error, + true, null)); } + + // Post-build actions. + PerformPostBuild(releaseType, platform, architecture, distribution, buildTime, ref options, configKey, buildPath); + + return success; } - private static void PerformPreBuild() + private static void PerformPreBuild(out DateTime buildTime) { - if (preBuildActions != null) + buildTime = DateTime.Now; + + // Clear any old notifications. + BuildNotificationList.instance.RefreshAll(); + + // Generate version string. + if (BuildSettings.productParameters.autoGenerate) { - for (int i = 0; i < preBuildActions.Count; i++) + GenerateVersionString(BuildSettings.productParameters, buildTime); + } + + // Run pre-build actions. + BuildAction[] buildActions = BuildSettings.preBuildActions.buildActions; + if (buildActions != null) + { + for (int i = 0; i < buildActions.Length; i++) { - Debug.Log("Executing PreBuild: " + preBuildActions[i].GetType().Name + " (" + preBuildActions[i].priority + ")"); - preBuildActions[i].Execute(); + BuildAction action = buildActions[i]; + + // Check if execute method has been overriden. + MethodInfo m = action.GetType().GetMethod("Execute"); + if (m.GetBaseDefinition().DeclaringType != m.DeclaringType && action.actionType == BuildAction.ActionType.SingleRun) + { + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + string.Format("Performing Pre-Build Action ({0}/{1}).", i + 1, buildActions.Length), action.actionName, + true, null)); + + action.Execute(); + } } } } - private static void PerformPostBuild() + private static void PerformPreBuild( + BuildReleaseType releaseType, + BuildPlatform platform, + BuildArchitecture architecture, + BuildDistribution distribution, + DateTime buildTime, ref BuildOptions options, string configKey, string buildPath) { - if (postBuildActions != null) + BuildAction[] buildActions = BuildSettings.preBuildActions.buildActions; + if (buildActions != null) { - for (int i = 0; i < postBuildActions.Count; i++) + for (int i = 0; i < buildActions.Length; i++) { - Debug.Log("Executing PostBuild: " + postBuildActions[i].GetType().Name + " (" + postBuildActions[i].priority + ")"); - postBuildActions[i].Execute(); + BuildAction action = buildActions[i]; + + // Check if execute method has been overriden. + MethodInfo m = action.GetType().GetMethod("PerBuildExecute"); + if (m.GetBaseDefinition().DeclaringType != m.DeclaringType && action.actionType == BuildAction.ActionType.PerPlatform) + { + // Check build filter and execute if true. + if (action.filter == null || action.filter.Evaluate(releaseType, platform, architecture, distribution, configKey)) + { + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + string.Format("Performing Pre-Build Action ({0}/{1}).", i + 1, buildActions.Length), string.Format("{0}: {1}", action.actionName, configKey), + true, null)); + + action.PerBuildExecute(releaseType, platform, architecture, distribution, buildTime, ref options, configKey, buildPath); + } + } } } } - private static void PerformPreBuild(BuildPlatform platform) + private static void PerformPostBuild() { - if (preBuildActions != null) + // Run post-build actions. + BuildAction[] buildActions = BuildSettings.postBuildActions.buildActions; + if (buildActions != null) { - for (int i = 0; i < preBuildActions.Count; i++) + for (int i = 0; i < buildActions.Length; i++) { - Debug.Log("Executing PreBuild (" + platform.name + "): " + preBuildActions[i].GetType().Name + " (" + preBuildActions[i].priority + ")"); - preBuildActions[i].Execute(platform); + BuildAction action = buildActions[i]; + + // Check if execute method has been overriden. + MethodInfo m = action.GetType().GetMethod("Execute"); + if (m.GetBaseDefinition().DeclaringType != m.DeclaringType && action.actionType == BuildAction.ActionType.SingleRun) + { + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + string.Format("Performing Post-Build Action ({0}/{1}).", i + 1, buildActions.Length), action.actionName, + true, null)); + + action.Execute(); + } } } } - private static void PerformPostBuild(BuildPlatform platform) + private static void PerformPostBuild( + BuildReleaseType releaseType, + BuildPlatform platform, + BuildArchitecture architecture, + BuildDistribution distribution, + DateTime buildTime, ref BuildOptions options, string configKey, string buildPath) { - if (postBuildActions != null) + BuildAction[] buildActions = BuildSettings.postBuildActions.buildActions; + if (buildActions != null) { - for (int i = 0; i < postBuildActions.Count; i++) + for (int i = 0; i < buildActions.Length; i++) { - Debug.Log("Executing PostBuild (" + platform.name + "): " + postBuildActions[i].GetType().Name + " (" + postBuildActions[i].priority + ")"); - postBuildActions[i].Execute(platform); + BuildAction action = buildActions[i]; + + // Check if execute method has been overriden. + MethodInfo m = action.GetType().GetMethod("PerBuildExecute"); + if (m.GetBaseDefinition().DeclaringType != m.DeclaringType && action.actionType == BuildAction.ActionType.PerPlatform) + { + // Check build filter and execute if true. + if (action.filter == null || action.filter.Evaluate(releaseType, platform, architecture, distribution, configKey)) + { + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Notification, + string.Format("Performing Post-Build Action ({0}/{1}).", i + 1, buildActions.Length), string.Format("{0}: {1}", action.actionName, configKey), + true, null)); + + action.PerBuildExecute(releaseType, platform, architecture, distribution, buildTime, ref options, configKey, buildPath); + } + } } } } diff --git a/Editor/Build/Generator.cs b/Editor/Build/Generator.cs deleted file mode 100644 index 3034f49..0000000 --- a/Editor/Build/Generator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace UnityBuild -{ - -public static class Generator -{ - public static void Generate(string outputFilename, string className, string templateFilename) - { - string directory = EditorUtility.OpenFolderPanel("Choose location for " + outputFilename + " (MUST BE AN EDITOR DIRECTORY)", Application.dataPath, ""); - - // If user cancelled, we can't do anything. - if (string.IsNullOrEmpty(directory)) - { - return; - } - else if (!directory.Contains(Path.AltDirectorySeparatorChar + "Editor") && !directory.Contains(Path.DirectorySeparatorChar + "Editor" + Path.DirectorySeparatorChar)) - { - Debug.LogError(className + " must be in an Editor directory/sub-directory"); - return; - } - - string filePath = Path.Combine(directory, outputFilename); - - string templateFilePath = string.Empty; - foreach (var file in Directory.GetFiles(Application.dataPath, "*.txt", SearchOption.AllDirectories)) - { - if (Path.GetFileNameWithoutExtension(file) == templateFilename) - { - templateFilePath = file; - break; - } - } - - File.WriteAllText(filePath, File.ReadAllText(templateFilePath)); - - AssetDatabase.Refresh(); - } -} - -} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildAndroid.cs b/Editor/Build/Platform/BuildAndroid.cs index 5d02445..7663023 100644 --- a/Editor/Build/Platform/BuildAndroid.cs +++ b/Editor/Build/Platform/BuildAndroid.cs @@ -1,53 +1,58 @@ -using UnityEditor; - -namespace UnityBuild -{ - -public class BuildAndroid : BuildPlatform -{ - #region Constants (SET VALUES) - - private const BuildTarget _target = BuildTarget.Android; - private const string _name = "android"; - private const string _binaryNameFormat = "{0}.apk"; - private const string _dataDirNameFormat = "{0}_Data"; - - #endregion - - #region Methods & Properties (DO NOT EDIT) - - public override BuildTarget target - { - get { return _target; } - } - - public override string name - { - get { return _name; } - } - - public override string binaryNameFormat - { - get { return _binaryNameFormat; } - } - - public override string dataDirNameFormat - { - get { return _dataDirNameFormat; } - } - - [MenuItem("Build/Platforms/" + _name)] - private static void Toggle() - { - Toggle(_name); - } - [MenuItem("Build/Platforms/" + _name, true)] - private static bool ToggleValidate() - { - return ToggleValidate(_name); - } - - #endregion -} - -} \ No newline at end of file +//using UnityEditor; + +//namespace SuperSystems.UnityBuild +//{ + +//[System.Serializable] +//public class BuildAndroid : BuildPlatform +//{ +// #region Constants + +// private const string _name = "Android"; +// private const string _binaryNameFormat = "{0}.apk"; +// private const string _dataDirNameFormat = "{0}_Data"; +// private const BuildTargetGroup _targetGroup = BuildTargetGroup.Android; + +// #endregion + +// public BuildAndroid() +// { +// enabled = false; +// Init(); +// } + +// public override void Init() +// { +// platformName = _name; +// binaryNameFormat = _binaryNameFormat; +// dataDirNameFormat = _dataDirNameFormat; +// targetGroup = _targetGroup; + +// if (architectures == null || architectures.Length == 0) +// { +// architectures = new BuildArchitecture[] { +// new BuildArchitecture(BuildTarget.Android, "Android", true) +// }; +// } +// if (variants == null || variants.Length == 0) +// { +// variants = new BuildVariant[] { +// new BuildVariant("Device Type", "FAT", true), +// new BuildVariant("Device Type", "ARMv7", false), +// new BuildVariant("Device Type", "x86", false), +// new BuildVariant("Texture Compression", "ETC (Default)", true), +// new BuildVariant("Texture Compression", "ETC2", false), +// new BuildVariant("Texture Compression", "ASTC", false), +// new BuildVariant("Texture Compression", "DXT", false), +// new BuildVariant("Texture Compression", "PVRTC", false), +// new BuildVariant("Texture Compression", "ATC", false), +// new BuildVariant("Texture Compression", "Generic", false), +// new BuildVariant("Build System", "Internal (Default)", true), +// new BuildVariant("Build System", "Gradle", false), +// new BuildVariant("Build System", "ADT (Legacy)", false) +// }; +// } +// } +//} + +//} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildAndroid.cs.meta b/Editor/Build/Platform/BuildAndroid.cs.meta index c6db3f8..4a513e8 100644 --- a/Editor/Build/Platform/BuildAndroid.cs.meta +++ b/Editor/Build/Platform/BuildAndroid.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 guid: 89df54eebccd0704dbbe96915fbb9a6f -timeCreated: 1465515841 +timeCreated: 1483490161 licenseType: Pro MonoImporter: serializedVersion: 2 diff --git a/Editor/Build/Platform/BuildArchitecture.cs b/Editor/Build/Platform/BuildArchitecture.cs new file mode 100644 index 0000000..cfa1140 --- /dev/null +++ b/Editor/Build/Platform/BuildArchitecture.cs @@ -0,0 +1,22 @@ +using UnityEngine; +using UnityEditor; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildArchitecture +{ + public BuildTarget target; + public string name; + public bool enabled; + + public BuildArchitecture(BuildTarget target, string name, bool enabled) + { + this.target = target; + this.name = name; + this.enabled = enabled; + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildArchitecture.cs.meta b/Editor/Build/Platform/BuildArchitecture.cs.meta new file mode 100644 index 0000000..801f8fa --- /dev/null +++ b/Editor/Build/Platform/BuildArchitecture.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6fd48d943b085a04788425235928448d +timeCreated: 1463225904 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/BuildIOS.cs b/Editor/Build/Platform/BuildIOS.cs new file mode 100644 index 0000000..e0cef91 --- /dev/null +++ b/Editor/Build/Platform/BuildIOS.cs @@ -0,0 +1,50 @@ +//using UnityEditor; + +//namespace SuperSystems.UnityBuild +//{ + +//[System.Serializable] +//public class BuildIOS : BuildPlatform +//{ +// #region Constants + +// // TODO: Fix iOS binary/data dir name. +// private const string _name = "iOS"; +// private const string _binaryNameFormat = "{0}.apk"; +// private const string _dataDirNameFormat = "{0}_Data"; +// private const BuildTargetGroup _targetGroup = BuildTargetGroup.iOS; + +// #endregion + +// public BuildIOS() +// { +// enabled = false; +// Init(); +// } + +// public override void Init() +// { +// platformName = _name; +// binaryNameFormat = _binaryNameFormat; +// dataDirNameFormat = _dataDirNameFormat; +// targetGroup = _targetGroup; + +// if (architectures == null || architectures.Length == 0) +// { +// architectures = new BuildArchitecture[] { +// new BuildArchitecture(BuildTarget.iOS, "iOS", true) +// }; +// } +// if (variants == null || variants.Length == 0) +// { +// variants = new BuildVariant[] { +// new BuildVariant("XCode", "Release", true), +// new BuildVariant("XCode", "Debug", false), +// new BuildVariant("Symlink Unity Libraries", "Disabled", true), +// new BuildVariant("Symlink Unity Libraries", "Enabled", false) +// }; +// } +// } +//} + +//} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildIOS.cs.meta b/Editor/Build/Platform/BuildIOS.cs.meta new file mode 100644 index 0000000..70f6185 --- /dev/null +++ b/Editor/Build/Platform/BuildIOS.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bef8779c491f5c644abe870eaa46e52c +timeCreated: 1483490161 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/BuildLinux.cs b/Editor/Build/Platform/BuildLinux.cs index 061613c..30a5ed2 100644 --- a/Editor/Build/Platform/BuildLinux.cs +++ b/Editor/Build/Platform/BuildLinux.cs @@ -1,53 +1,42 @@ using UnityEditor; -namespace UnityBuild +namespace SuperSystems.UnityBuild { +[System.Serializable] public class BuildLinux : BuildPlatform { - #region Constants (SET VALUES) + #region Constants - private const BuildTarget _target = BuildTarget.StandaloneLinux; private const string _name = "Linux"; private const string _binaryNameFormat = "{0}.x86"; private const string _dataDirNameFormat = "{0}_Data"; + private const BuildTargetGroup _targetGroup = BuildTargetGroup.Standalone; #endregion - #region Methods & Properties (DO NOT EDIT) - - public override BuildTarget target - { - get { return _target; } - } - - public override string name - { - get { return _name; } - } - - public override string binaryNameFormat + public BuildLinux() { - get { return _binaryNameFormat; } + enabled = false; + Init(); } - public override string dataDirNameFormat + public override void Init() { - get { return _dataDirNameFormat; } + platformName = _name; + binaryNameFormat = _binaryNameFormat; + dataDirNameFormat = _dataDirNameFormat; + targetGroup = _targetGroup; + + if (architectures == null || architectures.Length == 0) + { + architectures = new BuildArchitecture[] { + new BuildArchitecture(BuildTarget.StandaloneLinuxUniversal, "Linux Universal", true), + new BuildArchitecture(BuildTarget.StandaloneLinux, "Linux x86", false), + new BuildArchitecture(BuildTarget.StandaloneLinux64, "Linux x64", false) + }; + } } - - [MenuItem("Build/Platforms/" + _name)] - private static void Toggle() - { - Toggle(_name); - } - [MenuItem("Build/Platforms/" + _name, true)] - private static bool ToggleValidate() - { - return ToggleValidate(_name); - } - - #endregion } } \ No newline at end of file diff --git a/Editor/Build/Platform/BuildOSX.cs b/Editor/Build/Platform/BuildOSX.cs index 52dd61e..8cbd490 100644 --- a/Editor/Build/Platform/BuildOSX.cs +++ b/Editor/Build/Platform/BuildOSX.cs @@ -1,53 +1,42 @@ using UnityEditor; -namespace UnityBuild +namespace SuperSystems.UnityBuild { +[System.Serializable] public class BuildOSX : BuildPlatform { - #region Constants (SET VALUES) + #region Constants - private const BuildTarget _target = BuildTarget.StandaloneOSXIntel; private const string _name = "OSX"; private const string _binaryNameFormat = "{0}.app"; private const string _dataDirNameFormat = "{0}.app/Contents"; + private const BuildTargetGroup _targetGroup = BuildTargetGroup.Standalone; #endregion - #region Methods & Properties (DO NOT EDIT) - - public override BuildTarget target - { - get { return _target; } - } - - public override string name - { - get { return _name; } - } - - public override string binaryNameFormat + public BuildOSX() { - get { return _binaryNameFormat; } + enabled = false; + Init(); } - public override string dataDirNameFormat + public override void Init() { - get { return _dataDirNameFormat; } + platformName = _name; + binaryNameFormat = _binaryNameFormat; + dataDirNameFormat = _dataDirNameFormat; + targetGroup = _targetGroup; + + if (architectures == null || architectures.Length == 0) + { + architectures = new BuildArchitecture[] { + new BuildArchitecture(BuildTarget.StandaloneOSXUniversal, "OSX Universal", true), + new BuildArchitecture(BuildTarget.StandaloneOSXIntel, "OSX Intel", false), + new BuildArchitecture(BuildTarget.StandaloneOSXIntel64, "OSX Intel64", false) + }; + } } - - [MenuItem("Build/Platforms/" + _name)] - private static void Toggle() - { - Toggle(_name); - } - [MenuItem("Build/Platforms/" + _name, true)] - private static bool ToggleValidate() - { - return ToggleValidate(_name); - } - - #endregion } } \ No newline at end of file diff --git a/Editor/Build/Platform/BuildPC.cs b/Editor/Build/Platform/BuildPC.cs index 504a704..2e36439 100644 --- a/Editor/Build/Platform/BuildPC.cs +++ b/Editor/Build/Platform/BuildPC.cs @@ -1,53 +1,41 @@ using UnityEditor; -namespace UnityBuild +namespace SuperSystems.UnityBuild { +[System.Serializable] public class BuildPC : BuildPlatform { - #region Constants (SET VALUES) + #region Constants - private const BuildTarget _target = BuildTarget.StandaloneWindows; private const string _name = "PC"; private const string _binaryNameFormat = "{0}.exe"; private const string _dataDirNameFormat = "{0}_Data"; + private const BuildTargetGroup _targetGroup = BuildTargetGroup.Standalone; #endregion - #region Methods & Properties (DO NOT EDIT) - - public override BuildTarget target - { - get { return _target; } - } - - public override string name - { - get { return _name; } - } - - public override string binaryNameFormat + public BuildPC() { - get { return _binaryNameFormat; } + enabled = false; + Init(); } - public override string dataDirNameFormat + public override void Init() { - get { return _dataDirNameFormat; } + platformName = _name; + binaryNameFormat = _binaryNameFormat; + dataDirNameFormat = _dataDirNameFormat; + targetGroup = _targetGroup; + + if (architectures == null || architectures.Length == 0) + { + architectures = new BuildArchitecture[] { + new BuildArchitecture(BuildTarget.StandaloneWindows, "Windows x86", true), + new BuildArchitecture(BuildTarget.StandaloneWindows64, "Windows x64", false) + }; + } } - - [MenuItem("Build/Platforms/" + _name)] - private static void Toggle() - { - Toggle(_name); - } - [MenuItem("Build/Platforms/" + _name, true)] - private static bool ToggleValidate() - { - return ToggleValidate(_name); - } - - #endregion } } \ No newline at end of file diff --git a/Editor/Build/Platform/BuildPlatform.cs b/Editor/Build/Platform/BuildPlatform.cs index f5d63cb..68eb562 100644 --- a/Editor/Build/Platform/BuildPlatform.cs +++ b/Editor/Build/Platform/BuildPlatform.cs @@ -1,129 +1,53 @@ -using System; -using System.IO; -using System.Reflection; +using System.IO; using UnityEditor; -namespace UnityBuild +namespace SuperSystems.UnityBuild { -[InitializeOnLoad] -public abstract class BuildPlatform +[System.Serializable] +public class BuildPlatform { - #region Abstract + public bool enabled = false; + public BuildDistributionList distributionList = new BuildDistributionList(); + public BuildArchitecture[] architectures = new BuildArchitecture[0]; + public BuildVariant[] variants = new BuildVariant[0]; - /// - /// Unity build target definition. - /// - public abstract BuildTarget target { get; } - - /// - /// Platform name. - /// - public abstract string name { get; } - - /// - /// The format of the binary executable name (e.g. {0}.exe). {0} = Executable name specified in BuildSettings. - /// - public abstract string binaryNameFormat { get; } - - /// - /// The format of the data directory (e.g. {0}_Data). {0} = Executable name specified in BuildSettings. - /// - public abstract string dataDirNameFormat { get; } - - #endregion - - #region Contructor - - /// - /// Constructor - /// - static BuildPlatform() - { - // Find all classes that inherit from BuildPlatform and register them with BuildProject. - Type ti = typeof(BuildPlatform); - - foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (Type t in asm.GetTypes()) - { - if (ti.IsAssignableFrom(t) && ti != t) - { - BuildProject.RegisterPlatform((BuildPlatform)Activator.CreateInstance(t)); - } - } - } - } - - #endregion - - #region Public Methods - - /// - /// Perform build for platform. - /// - public void Build() + public string platformName; + public string binaryNameFormat; + public string dataDirNameFormat; + public BuildTargetGroup targetGroup; + + public virtual void Init() { - BuildProject.PerformBuild(this); } - #endregion - - #region Protected Methods - - /// - /// Toggle if a target platform should be built. - /// - /// Platform name. Passed in from descendant class. - protected static void Toggle(string targetName) - { - EditorPrefs.SetBool("buildGame" + targetName, !EditorPrefs.GetBool("buildGame" + targetName, false)); - } - - /// - /// UI Validation for platform build setting. - /// - /// Platform name. Passed in from descendant class. - /// - protected static bool ToggleValidate(string targetName) - { - Menu.SetChecked("Build/Platforms/" + targetName, EditorPrefs.GetBool("buildGame" + targetName, false)); - return true; - } - - #endregion - #region Public Properties - public bool buildEnabled + public bool atLeastOneArch { get { - return EditorPrefs.GetBool("buildGame" + name, false); - } - } + bool atLeastOneArch = false; + for (int i = 0; i < architectures.Length && !atLeastOneArch; i++) + { + atLeastOneArch |= architectures[i].enabled; + } - public string buildPath - { - get - { - return BuildSettings.binPath + Path.DirectorySeparatorChar + name + Path.DirectorySeparatorChar; + return atLeastOneArch; } } - public string dataDirectory + public bool atLeastOneDistribution { get { - return buildPath + string.Format(dataDirNameFormat, BuildSettings.binName) + Path.DirectorySeparatorChar; - } - } + bool atLeastOneDist = false; + for (int i = 0; i < distributionList.distributions.Length && !atLeastOneDist; i++) + { + atLeastOneDist |= distributionList.distributions[i].enabled; + } - public string exeName - { - get - { - return string.Format(binaryNameFormat, BuildSettings.binName); + return atLeastOneDist; } } diff --git a/Editor/Build/Platform/BuildPlatformGenerator.cs b/Editor/Build/Platform/BuildPlatformGenerator.cs deleted file mode 100644 index 06f52b1..0000000 --- a/Editor/Build/Platform/BuildPlatformGenerator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using UnityEditor; - -namespace UnityBuild -{ - -public static class BuildPlatformGenerator -{ - [MenuItem("Build/Generate/BuildPlatform", false, 100)] - private static void GenerateBuildSettings() - { - Generator.Generate("BuildCustomPlatform.cs", "BuildPlatform", "BuildPlatformTemplate"); - } -} - -} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildPlatformGenerator.cs.meta b/Editor/Build/Platform/BuildPlatformGenerator.cs.meta deleted file mode 100644 index 6732fbc..0000000 --- a/Editor/Build/Platform/BuildPlatformGenerator.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 367aa42bb44dd5546840486eeb0afd34 -timeCreated: 1460734696 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Build/Platform/BuildPlatformList.cs b/Editor/Build/Platform/BuildPlatformList.cs new file mode 100644 index 0000000..dfccee6 --- /dev/null +++ b/Editor/Build/Platform/BuildPlatformList.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildPlatformList +{ + public BuildPlatform[] platforms = new BuildPlatform[0]; +} + +} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildPlatformList.cs.meta b/Editor/Build/Platform/BuildPlatformList.cs.meta new file mode 100644 index 0000000..977c307 --- /dev/null +++ b/Editor/Build/Platform/BuildPlatformList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a102a73cb7aaefb47b9e0584245616d2 +timeCreated: 1463151306 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/BuildPlatformTemplate.txt b/Editor/Build/Platform/BuildPlatformTemplate.txt deleted file mode 100644 index 09a0538..0000000 --- a/Editor/Build/Platform/BuildPlatformTemplate.txt +++ /dev/null @@ -1,53 +0,0 @@ -using UnityEditor; - -namespace UnityBuild -{ - -public class BuildCustomPlatform : BuildPlatform -{ - #region Constants (SET VALUES) - - private const BuildTarget _target = BuildTarget.StandaloneWindows; - private const string _name = "PC"; - private const string _binaryNameFormat = "{0}.exe"; - private const string _dataDirNameFormat = "{0}_Data"; - - #endregion - - #region Methods & Properties (DO NOT EDIT) - - public override BuildTarget target - { - get { return _target; } - } - - public override string name - { - get { return _name; } - } - - public override string binaryNameFormat - { - get { return _binaryNameFormat; } - } - - public override string dataDirNameFormat - { - get { return _dataDirNameFormat; } - } - - [MenuItem("Build/Platforms/" + _name)] - private static void Toggle() - { - Toggle(_name); - } - [MenuItem("Build/Platforms/" + _name, true)] - private static bool ToggleValidate() - { - return ToggleValidate(_name); - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildVariant.cs b/Editor/Build/Platform/BuildVariant.cs new file mode 100644 index 0000000..6c097ab --- /dev/null +++ b/Editor/Build/Platform/BuildVariant.cs @@ -0,0 +1,20 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildVariant +{ + public string type; + public string name; + public bool enabled; + + public BuildVariant(string type, string name, bool enabled) + { + this.type = type; + this.name = name; + this.enabled = enabled; + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Platform/BuildVariant.cs.meta b/Editor/Build/Platform/BuildVariant.cs.meta new file mode 100644 index 0000000..2989e4f --- /dev/null +++ b/Editor/Build/Platform/BuildVariant.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0fcc9aa48be0458448a2721abafa3822 +timeCreated: 1483491405 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/UI.meta b/Editor/Build/Platform/UI.meta new file mode 100644 index 0000000..b169b36 --- /dev/null +++ b/Editor/Build/Platform/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c9f38bd1a1d4d5a4f8a6ae59da4207d2 +folderAsset: yes +timeCreated: 1463204367 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/UI/BuildPlatformDrawer.cs b/Editor/Build/Platform/UI/BuildPlatformDrawer.cs new file mode 100644 index 0000000..0d1bf13 --- /dev/null +++ b/Editor/Build/Platform/UI/BuildPlatformDrawer.cs @@ -0,0 +1,102 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildPlatform))] +public class BuildPlatformDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, GUIContent.none, property); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader(property.FindPropertyRelative("platformName").stringValue, ref show, false); + property.isExpanded = show; + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + SerializedProperty archList = property.FindPropertyRelative("architectures"); + + if (archList.arraySize > 1) + { + GUILayout.Label("Architectures", UnityBuildGUIUtility.midHeaderStyle); + for (int i = 0; i < archList.arraySize; i++) + { + SerializedProperty archProperty = archList.GetArrayElementAtIndex(i); + SerializedProperty archName = archProperty.FindPropertyRelative("name"); + SerializedProperty archEnabled = archProperty.FindPropertyRelative("enabled"); + + archEnabled.boolValue = GUILayout.Toggle(archEnabled.boolValue, archName.stringValue); + archProperty.serializedObject.ApplyModifiedProperties(); + } + } + + SerializedProperty distList = property.FindPropertyRelative("distributionList.distributions"); + + if (distList.arraySize > 0) + { + GUILayout.Space(20); + GUILayout.Label("Distributions", UnityBuildGUIUtility.midHeaderStyle); + + for (int i = 0; i < distList.arraySize; i++) + { + SerializedProperty dist = distList.GetArrayElementAtIndex(i); + SerializedProperty distEnabled = dist.FindPropertyRelative("enabled"); + SerializedProperty distName = dist.FindPropertyRelative("distributionName"); + + GUILayout.BeginHorizontal(); + + distEnabled.boolValue = GUILayout.Toggle(distEnabled.boolValue, GUIContent.none, GUILayout.ExpandWidth(false)); + distName.stringValue = BuildProject.SanitizeFolderName(GUILayout.TextField(distName.stringValue)); + + if (GUILayout.Button("X", UnityBuildGUIUtility.helpButtonStyle)) + { + distList.DeleteArrayElementAtIndex(i); + } + + dist.serializedObject.ApplyModifiedProperties(); + + GUILayout.EndHorizontal(); + } + } + + GUILayout.Space(10); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + if (GUILayout.Button("Add Distribution", GUILayout.MaxWidth(150))) + { + int addedIndex = distList.arraySize; + distList.InsertArrayElementAtIndex(addedIndex); + + SerializedProperty addedProperty = distList.GetArrayElementAtIndex(addedIndex); + addedProperty.FindPropertyRelative("enabled").boolValue = true; + addedProperty.FindPropertyRelative("distributionName").stringValue = "DistributionName"; + + addedProperty.serializedObject.ApplyModifiedProperties(); + distList.serializedObject.ApplyModifiedProperties(); + property.serializedObject.ApplyModifiedProperties(); + GUIUtility.keyboardControl = 0; + } + if (GUILayout.Button("Delete", GUILayout.MaxWidth(150))) + { + property.FindPropertyRelative("enabled").boolValue = false; + } + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + EditorGUILayout.EndVertical(); + } + + property.serializedObject.ApplyModifiedProperties(); + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Platform/UI/BuildPlatformDrawer.cs.meta b/Editor/Build/Platform/UI/BuildPlatformDrawer.cs.meta new file mode 100644 index 0000000..25528c0 --- /dev/null +++ b/Editor/Build/Platform/UI/BuildPlatformDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4544ed9d41307634cbd34da86e28b78a +timeCreated: 1463164846 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs b/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs new file mode 100644 index 0000000..9852b80 --- /dev/null +++ b/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildPlatformList))] +public class BuildPlatformListDrawer : PropertyDrawer +{ + private int index = 0; + private SerializedProperty list = null; + private BuildPlatformList platformList = null; + private List availablePlatformList = new List(); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + EditorGUILayout.BeginHorizontal(); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Build Platforms", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#build-platforms"); + EditorGUILayout.EndHorizontal(); + + //if (list == null) + //{ + platformList = fieldInfo.GetValue(property.serializedObject.targetObject) as BuildPlatformList; + PopulateList(); + list = property.FindPropertyRelative("platforms"); + //} + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + int enabledCount = 0; + for (int i = 0; i < list.arraySize; i++) + { + SerializedProperty platformProperty = list.GetArrayElementAtIndex(i); + SerializedProperty platformEnabled = platformProperty.FindPropertyRelative("enabled"); + + string platformName = platformList.platforms[i].platformName; + + if (platformEnabled.boolValue) + { + ++enabledCount; + EditorGUILayout.PropertyField(platformProperty, GUILayout.MaxHeight(0)); + if (availablePlatformList.Contains(platformName)) + availablePlatformList.Remove(platformName); + } + else if (!availablePlatformList.Contains(platformName)) + { + availablePlatformList.Add(platformName); + } + } + + if (availablePlatformList.Count > 0) + { + if (enabledCount > 0) + { + GUILayout.Space(20); + } + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + index = EditorGUILayout.Popup(index, availablePlatformList.ToArray(), UnityBuildGUIUtility.popupStyle, GUILayout.ExpandWidth(false), GUILayout.MaxWidth(250)); + if (GUILayout.Button("Add Platform", GUILayout.ExpandWidth(false), GUILayout.MaxWidth(150))) + { + for (int i = 0; i < list.arraySize; i++) + { + SerializedProperty platformProperty = list.GetArrayElementAtIndex(i); + string platformName = platformList.platforms[i].platformName; + + if (availablePlatformList[index] == platformName) + { + SerializedProperty platformEnabled = platformProperty.FindPropertyRelative("enabled"); + platformEnabled.boolValue = true; + + platformProperty.serializedObject.ApplyModifiedProperties(); + } + } + + index = 0; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } + + private void PopulateList() + { + Type ti = typeof(BuildPlatform); + List platforms = new List(platformList.platforms); + foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (Type t in asm.GetTypes()) + { + if (ti.IsAssignableFrom(t) && ti != t) + { + BuildPlatform instance = (BuildPlatform)Activator.CreateInstance(t); + bool alreadyPresent = false; + for (int i = 0; i < platforms.Count; i++) + { + if (platforms[i].platformName.Equals(instance.platformName)) + { + alreadyPresent = true; + BuildPlatform oldInstance = platforms[i]; + + instance.enabled = oldInstance.enabled; + + if (instance.enabled) + { + instance.architectures = oldInstance.architectures; + instance.variants = oldInstance.variants; + instance.distributionList = oldInstance.distributionList; + } + + platforms[i] = instance; + break; + } + } + + if (!alreadyPresent) + { + platforms.Add(instance); + } + } + } + } + + platformList.platforms = platforms.ToArray(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs.meta b/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs.meta new file mode 100644 index 0000000..39f7c4d --- /dev/null +++ b/Editor/Build/Platform/UI/BuildPlatformListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4c0c8d7a7e3e63e4c8296bb4053739b0 +timeCreated: 1463156632 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BaseSettings.cs b/Editor/Build/Settings/BaseSettings.cs index 4279dd0..44b7b27 100644 --- a/Editor/Build/Settings/BaseSettings.cs +++ b/Editor/Build/Settings/BaseSettings.cs @@ -1,30 +1,29 @@ -using UnityEngine; +using System.IO; using UnityEditor; -using System.IO; +using UnityEngine; -namespace UnityBuild +namespace SuperSystems.UnityBuild { public class BaseSettings : ScriptableObject { - protected const string SettingsPath = "Assets/Editor Default Resources/UnityBuildSettings/"; + protected const string SettingsPath = "Assets/UnityBuildSettings/{0}.asset"; protected static T CreateAsset(string assetName) where T : BaseSettings { - T instance = EditorGUIUtility.Load("UnityBuildSettings/" + assetName + ".asset") as T; + string assetPath = string.Format(SettingsPath, assetName); + T instance = AssetDatabase.LoadAssetAtPath(assetPath) as T; + if (instance == null) { - Debug.Log("UnityBuild: Creating settings file - " + SettingsPath + assetName + ".asset"); + Debug.Log("UnityBuild: Creating settings file - " + assetPath); instance = CreateInstance(); instance.name = assetName; - if (!Directory.Exists("Assets/Editor Default Resources")) - AssetDatabase.CreateFolder("Assets", "Editor Default Resources"); - - if (!Directory.Exists("Assets/Editor Default Resources/UnityBuildSettings")) - AssetDatabase.CreateFolder("Assets/Editor Default Resources", "UnityBuildSettings"); + if (!Directory.Exists("Assets/UnityBuildSettings")) + AssetDatabase.CreateFolder("Assets", "UnityBuildSettings"); - AssetDatabase.CreateAsset(instance, SettingsPath + assetName + ".asset"); + AssetDatabase.CreateAsset(instance, assetPath); } return instance; diff --git a/Editor/Build/Settings/BasicSettings.cs b/Editor/Build/Settings/BasicSettings.cs new file mode 100644 index 0000000..e2d92e0 --- /dev/null +++ b/Editor/Build/Settings/BasicSettings.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BasicSettings +{ + [FilePath(true, true, "Choose location for build output")] + public string baseBuildFolder = "bin"; + public string buildPath = "$YEAR-$MONTH-$DAY/$BUILD/$RELEASE_TYPE/$PLATFORM/$ARCHITECTURE/$DISTRIBUTION"; + public bool openFolderPostBuild = true; +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/BasicSettings.cs.meta b/Editor/Build/Settings/BasicSettings.cs.meta new file mode 100644 index 0000000..5425556 --- /dev/null +++ b/Editor/Build/Settings/BasicSettings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6db4605d595c25445b64252cedb99379 +timeCreated: 1462483816 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BuildDistribution.cs b/Editor/Build/Settings/BuildDistribution.cs new file mode 100644 index 0000000..173a42e --- /dev/null +++ b/Editor/Build/Settings/BuildDistribution.cs @@ -0,0 +1,24 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildDistribution +{ + public string distributionName; + public bool enabled; + + public BuildDistribution() + { + this.distributionName = string.Empty; + this.enabled = true; + } + + public BuildDistribution(string distributionName, bool enabled) + { + this.distributionName = distributionName; + this.enabled = enabled; + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/BuildDistribution.cs.meta b/Editor/Build/Settings/BuildDistribution.cs.meta new file mode 100644 index 0000000..c0b3d39 --- /dev/null +++ b/Editor/Build/Settings/BuildDistribution.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cf82d434e3e3d5d4ea5f610d2da8aed8 +timeCreated: 1463220231 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BuildDistributionList.cs b/Editor/Build/Settings/BuildDistributionList.cs new file mode 100644 index 0000000..fd0f7c1 --- /dev/null +++ b/Editor/Build/Settings/BuildDistributionList.cs @@ -0,0 +1,11 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildDistributionList +{ + public BuildDistribution[] distributions = new BuildDistribution[] { }; +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/BuildDistributionList.cs.meta b/Editor/Build/Settings/BuildDistributionList.cs.meta new file mode 100644 index 0000000..37ec5cb --- /dev/null +++ b/Editor/Build/Settings/BuildDistributionList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5de1357338dbdfb4889575a989b0cd12 +timeCreated: 1463221226 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BuildReleaseType.cs b/Editor/Build/Settings/BuildReleaseType.cs new file mode 100644 index 0000000..883a08c --- /dev/null +++ b/Editor/Build/Settings/BuildReleaseType.cs @@ -0,0 +1,19 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildReleaseType +{ + public string typeName = string.Empty; + public string bundleIndentifier = string.Empty; + public string productName = string.Empty; + + public bool developmentBuild = false; + public bool allowDebugging = false; + public string customDefines = string.Empty; + + public SceneList sceneList = new SceneList(); +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/BuildReleaseType.cs.meta b/Editor/Build/Settings/BuildReleaseType.cs.meta new file mode 100644 index 0000000..6ab28da --- /dev/null +++ b/Editor/Build/Settings/BuildReleaseType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7da0de12143629546ba800f0d84e39ef +timeCreated: 1463204367 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BuildReleaseTypeList.cs b/Editor/Build/Settings/BuildReleaseTypeList.cs new file mode 100644 index 0000000..3e6b371 --- /dev/null +++ b/Editor/Build/Settings/BuildReleaseTypeList.cs @@ -0,0 +1,11 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildReleaseTypeList +{ + public BuildReleaseType[] releaseTypes = new BuildReleaseType[] { }; +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/BuildReleaseTypeList.cs.meta b/Editor/Build/Settings/BuildReleaseTypeList.cs.meta new file mode 100644 index 0000000..687daa0 --- /dev/null +++ b/Editor/Build/Settings/BuildReleaseTypeList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 24a72950fb9d0584d9763c729715fad9 +timeCreated: 1463205314 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/BuildSettings.cs b/Editor/Build/Settings/BuildSettings.cs index 478dcfd..56f1cd9 100644 --- a/Editor/Build/Settings/BuildSettings.cs +++ b/Editor/Build/Settings/BuildSettings.cs @@ -1,101 +1,119 @@ using System; -using System.IO; -using System.Reflection; -using UnityEditor; using UnityEngine; -namespace UnityBuild +namespace SuperSystems.UnityBuild { -[InitializeOnLoad] +[Serializable] public class BuildSettings : BaseSettings { #region Singleton - private static BuildSettings instance = null; + private static BuildSettings _instance = null; - public static BuildSettings Instance + public static BuildSettings instance { get { - if (instance == null) + if (_instance == null) { - instance = CreateAsset("BuildSettings"); + _instance = CreateAsset("UnityBuildSettings"); } - return instance; + return _instance; } } #endregion - #region MenuItems + #region Variables - [MenuItem("Build/Edit Settings", priority = 0)] - public static void EditSettings() - { - Selection.activeObject = Instance; - EditorApplication.ExecuteMenuItem("Window/Inspector"); - } + [SerializeField] + private BasicSettings _basicSettings = new BasicSettings(); + [SerializeField] + private ProductParameters _productParameters = new ProductParameters(); + [SerializeField] + private BuildReleaseTypeList _releaseTypeList = new BuildReleaseTypeList(); + [SerializeField] + private BuildPlatformList _platformList = new BuildPlatformList(); + [SerializeField] + private ProjectConfigurations _projectConfigurations = new ProjectConfigurations(); + [SerializeField] + private BuildActionList _preBuildActions = new BuildActionList(); + [SerializeField] + private BuildActionList _postBuildActions = new BuildActionList(); #endregion - #region Variables + #region Public Methods - [Header("Build Settings (Field Info in Tooltips)")] + public static void Init() + { + if (_instance._preBuildActions == null) + _instance._preBuildActions = new BuildActionList(); - // The name of executable file (e.g. mygame.exe, mygame.app) - [SerializeField] - [Tooltip("The name of executable file (e.g. mygame.exe, mygame.app)")] - private string _binName = Application.productName; + if (_instance._postBuildActions == null) + _instance._postBuildActions = new BuildActionList(); + } - // The base path where builds are output. - // Path is relative to the Unity project's base folder unless an absolute path is given. - [SerializeField] - [Tooltip("The base path where builds are output.")] - private string _binPath = "bin"; + #endregion - // A list of scenes (filepaths) to include in the build. The first listed scene will be loaded first. - [SerializeField] - [Tooltip("A list of scenes to include in the build. First listed scene will be loaded first. ")] - private string[] _scenesInBuild = new string[] { - // @"Assets/Scenes/scene1.unity", - // @"Assets/Scenes/scene2.unity", - // ... - }; - - // A list of files/directories to include with the build. - // Paths are relative to Unity project's base folder unless an absolute path is given. - [SerializeField] - [Tooltip("A list of files/directories to include with the build.")] - private string[] _copyToBuild = new string[] { - // @"DirectoryToInclude/", - // @"FileToInclude.txt", - // ... - }; + #region Properties - #endregion + public static BasicSettings basicSettings + { + get + { + return instance._basicSettings; + } + } - #region Methods & Properties + public static ProductParameters productParameters + { + get + { + return instance._productParameters; + } + } - public static string binName + public static BuildReleaseTypeList releaseTypeList { - get { return Instance._binName; } + get + { + return instance._releaseTypeList; + } } - public static string binPath + public static BuildPlatformList platformList { - get { return Instance._binPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } + get + { + return instance._platformList; + } } - public static string[] scenesInBuild + public static ProjectConfigurations projectConfigurations { - get { return Instance._scenesInBuild; } + get + { + return instance._projectConfigurations; + } } - public static string[] copyToBuild + public static BuildActionList preBuildActions { - get { return Instance._copyToBuild; } + get + { + return instance._preBuildActions; + } + } + + public static BuildActionList postBuildActions + { + get + { + return instance._postBuildActions; + } } #endregion diff --git a/Editor/Build/Settings/Configuration.cs b/Editor/Build/Settings/Configuration.cs new file mode 100644 index 0000000..a2bbdd2 --- /dev/null +++ b/Editor/Build/Settings/Configuration.cs @@ -0,0 +1,15 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class Configuration +{ + public bool enabled = true; + public string[] childKeys = null; +} + +[System.Serializable] +public class ConfigDictionary : SerializableDictionary { } + +} \ No newline at end of file diff --git a/Editor/Build/Settings/Configuration.cs.meta b/Editor/Build/Settings/Configuration.cs.meta new file mode 100644 index 0000000..6dbae91 --- /dev/null +++ b/Editor/Build/Settings/Configuration.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a42ba71dc39f37d4d8e85ebbe0ee198c +timeCreated: 1463235829 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/ProductParameters.cs b/Editor/Build/Settings/ProductParameters.cs new file mode 100644 index 0000000..bea28b8 --- /dev/null +++ b/Editor/Build/Settings/ProductParameters.cs @@ -0,0 +1,17 @@ +using System; + +namespace SuperSystems.UnityBuild +{ + +[Serializable] +public class ProductParameters +{ + public int buildCounter = 0; + public string lastGeneratedVersion = string.Empty; + + // $NOUN, $ADJECTIVE, $DAYSSINCE("DATE"), $SECONDS, $BUILDS + public string version = "1.0.$DAYSSINCE(\"January 1, 2015\").$SECONDS"; + public bool autoGenerate = true; +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/ProductParameters.cs.meta b/Editor/Build/Settings/ProductParameters.cs.meta new file mode 100644 index 0000000..95ffe5e --- /dev/null +++ b/Editor/Build/Settings/ProductParameters.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 678cc89df6600be42b5a8525107d9c0a +timeCreated: 1463217936 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/ProjectConfigurations.cs b/Editor/Build/Settings/ProjectConfigurations.cs new file mode 100644 index 0000000..30d0502 --- /dev/null +++ b/Editor/Build/Settings/ProjectConfigurations.cs @@ -0,0 +1,316 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class ProjectConfigurations +{ + // Data + public ConfigDictionary configSet; + + // View + public bool showViewOptions = false; + public bool showConfigs = false; + public bool showBuildInfo = false; + + public bool hideDisabled = false; + public bool treeView = false; + + public string selectedKeyChain = string.Empty; + + public void Refresh() + { + ConfigDictionary refreshedConfigSet = new ConfigDictionary(); + + BuildReleaseType[] releaseTypes = BuildSettings.releaseTypeList.releaseTypes; + for (int i = 0; i < releaseTypes.Length; i++) + { + string key = releaseTypes[i].typeName; + Configuration relConfig = new Configuration(); + + // Check for duplicate. + if (refreshedConfigSet.ContainsKey(key)) + continue; + + // Copy old setting if it exists. + if (configSet != null && configSet.ContainsKey(key)) + { + relConfig.enabled = configSet[key].enabled; + } + + // Get child keys. + relConfig.childKeys = RefreshPlatforms(key, refreshedConfigSet, configSet); + + // Save configuration. + refreshedConfigSet.Add(key, relConfig); + } + + configSet = refreshedConfigSet; + } + + public string[] BuildAllKeychains() + { + List keychains = new List(); + + foreach (string key in configSet.Keys) + { + Configuration config = configSet[key]; + BuildKeychainsRecursive(ref keychains, config, key, 0); + } + + return keychains.ToArray(); + } + + public int GetEnabledBuildsCount() + { + int count = 0; + + BuildReleaseType[] releaseTypes = BuildSettings.releaseTypeList.releaseTypes; + for (int i = 0; i < releaseTypes.Length; i++) + { + string key = releaseTypes[i].typeName; + + if (configSet.ContainsKey(key)) + { + Configuration config = configSet[key]; + NavigateTree(key, config, 0, ref count); + } + } + + return count; + } + + private void NavigateTree(string key, Configuration config, int depth, ref int count) + { + if (depth >= 2 && config.enabled && (config.childKeys == null || config.childKeys.Length == 0)) + { + ++count; + } + else if (config.enabled && config.childKeys != null) + { + foreach (string childKey in config.childKeys) + { + NavigateTree(childKey, configSet[childKey], depth + 1, ref count); + } + } + } + + private void BuildKeychainsRecursive(ref List keychains, Configuration config, string key, int depth) + { + if (depth >= 2 && config.enabled && (config.childKeys == null || config.childKeys.Length == 0)) + { + keychains.Add(key); + } + else if (config.childKeys != null && config.childKeys.Length > 0 && config.enabled) + { + foreach (string childKey in config.childKeys) + { + BuildKeychainsRecursive(ref keychains, configSet[childKey], childKey, depth + 1); + } + } + } + + public bool ParseKeychain(string keychain, out BuildReleaseType releaseType, out BuildPlatform platform, out BuildArchitecture architecture, out BuildDistribution distribution) + { + bool success = false; + string[] keys = keychain.Split('/'); + int keyCount = keys.Length; + int targetKey = 0; + + releaseType = null; + platform = null; + architecture = null; + distribution = null; + + // Parse release type. + if (keyCount > targetKey) + { + for (int i = 0; i < BuildSettings.releaseTypeList.releaseTypes.Length; i++) + { + BuildReleaseType rt = BuildSettings.releaseTypeList.releaseTypes[i]; + + if (keys[targetKey] == rt.typeName) + { + releaseType = rt; + break; + } + } + } + + if (releaseType == null) + return false; + + // Parse platform. + if (keyCount > ++targetKey) + { + for (int i = 0; i < BuildSettings.platformList.platforms.Length; i++) + { + BuildPlatform p = BuildSettings.platformList.platforms[i]; + + if (keys[targetKey] == p.platformName) + { + platform = p; + break; + } + } + } + + if (platform == null) + return false; + + // Parse architecture. + if (platform.architectures.Length == 1) + { + // Only one architecture, so it won't even appear in dictionary. Just get it directly. + architecture = platform.architectures[0]; + success = true; + } + else if (keyCount > ++targetKey) + { + for (int i = 0; i < platform.architectures.Length; i++) + { + BuildArchitecture arch = platform.architectures[i]; + + if (keys[targetKey] == arch.name) + { + architecture = arch; + success = true; + break; + } + } + } + + if (architecture == null) + return false; + + // TODO: Parse variants. + + // Parse distribution. + if (keyCount > ++targetKey) + { + success = false; + for (int i = 0; i < platform.distributionList.distributions.Length; i++) + { + BuildDistribution dist = platform.distributionList.distributions[i]; + + if (keys[targetKey] == dist.distributionName) + { + distribution = dist; + success = true; + break; + } + } + } + + return success; + } + + private string[] RefreshPlatforms(string keyChain, ConfigDictionary refreshedConfigSet, ConfigDictionary prevConfigSet) + { + List childKeys = new List(); + + BuildPlatform[] platforms = BuildSettings.platformList.platforms; + for (int i = 0; i < platforms.Length; i++) + { + // Skip if platform is disabled or if it doesn't have any enabled architectures. + if (!platforms[i].enabled || !platforms[i].atLeastOneArch) + continue; + + string key = keyChain + "/" + platforms[i].platformName; + Configuration relConfig = new Configuration(); + + // Check for duplicate key. + if (refreshedConfigSet.ContainsKey(key)) + continue; + + // Copy previous settings if they exist. + if (prevConfigSet != null && prevConfigSet.ContainsKey(key)) + { + relConfig.enabled = prevConfigSet[key].enabled; + } + + // Refresh architectures. + BuildArchitecture[] architectures = platforms[i].architectures; + if (architectures.Length > 0) + relConfig.childKeys = RefreshArchitectures(key, refreshedConfigSet, architectures, platforms[i].distributionList.distributions, prevConfigSet); + + // Save configuration. + refreshedConfigSet.Add(key, relConfig); + + // Add key to list to send back to parent. + childKeys.Add(key); + } + + return childKeys.ToArray(); + } + + private string[] RefreshArchitectures(string keyChain, ConfigDictionary refreshedConfigSet, BuildArchitecture[] architectures, BuildDistribution[] distributions, ConfigDictionary prevConfigSet) + { + List childKeys = new List(); + + for (int i = 0; i < architectures.Length; i++) + { + // Skip if architecture is disabled. + if (!architectures[i].enabled) + continue; + + string key = keyChain + "/" + architectures[i].name; + Configuration relConfig = new Configuration(); + + // Check for a duplicate key. + if (refreshedConfigSet.ContainsKey(key)) + continue; + + // Copy previous settings if they exist. + if (prevConfigSet != null && prevConfigSet.ContainsKey(key)) + { + relConfig.enabled = prevConfigSet[key].enabled; + } + + // Refresh distributions. + if (distributions.Length > 0) + relConfig.childKeys = RefreshDistributions(key, refreshedConfigSet, distributions, prevConfigSet); + + // Save configuration. + refreshedConfigSet.Add(key, relConfig); + + // Add key to list to send back to parent. + childKeys.Add(key); + } + + return childKeys.ToArray(); + } + + private string[] RefreshDistributions(string keyChain, ConfigDictionary refreshedConfigSet, BuildDistribution[] distributions, ConfigDictionary prevConfigSet) + { + List childKeys = new List(); + + for (int i = 0; i < distributions.Length; i++) + { + if (!distributions[i].enabled) + continue; + + string key = keyChain + "/" + distributions[i].distributionName; + Configuration relConfig = new Configuration(); + + if (refreshedConfigSet.ContainsKey(key)) + continue; + + if (prevConfigSet != null && prevConfigSet.ContainsKey(key)) + { + relConfig.enabled = prevConfigSet[key].enabled; + } + + refreshedConfigSet.Add(key, relConfig); + + // Add key to list to send back to parent. + childKeys.Add(key); + } + + return childKeys.ToArray(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/ProjectConfigurations.cs.meta b/Editor/Build/Settings/ProjectConfigurations.cs.meta new file mode 100644 index 0000000..7141c9a --- /dev/null +++ b/Editor/Build/Settings/ProjectConfigurations.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 475989c3bb2cae54e9597f528c1079ff +timeCreated: 1463225904 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/SceneList.cs b/Editor/Build/Settings/SceneList.cs new file mode 100644 index 0000000..9ced9dd --- /dev/null +++ b/Editor/Build/Settings/SceneList.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using UnityEditor; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class SceneList +{ + public List enabledScenes = new List(); + + public SceneList() + { + } + + public void Refresh() + { + string[] allScenes = GetListOfAllScenes(); + + // Verify that all scenes in list still exist. + for (int i = 0; i < enabledScenes.Count; i++) + { + string sceneName = enabledScenes[i].filePath; + bool sceneExists = false; + for (int j = 0; j < allScenes.Length; j++) + { + if (string.Equals(sceneName, allScenes[j])) + { + sceneExists = true; + break; + } + } + + if (!sceneExists) + { + enabledScenes.RemoveAt(i); + --i; + } + } + } + + public string[] GetSceneList() + { + List scenes = new List(); + for (int i = 0; i < enabledScenes.Count; i++) + { + scenes.Add(enabledScenes[i].filePath); + } + + return scenes.ToArray(); + } + + public static string[] GetListOfAllScenes() + { + string[] allScenesGUID = AssetDatabase.FindAssets("t:scene"); + string[] allScenes = new string[allScenesGUID.Length]; + for (int i = 0; i < allScenesGUID.Length; i++) + { + allScenes[i] = AssetDatabase.GUIDToAssetPath(allScenesGUID[i]); + } + + return allScenes; + } + + [System.Serializable] + public class Scene + { + public string filePath = string.Empty; + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/SceneList.cs.meta b/Editor/Build/Settings/SceneList.cs.meta new file mode 100644 index 0000000..b976818 --- /dev/null +++ b/Editor/Build/Settings/SceneList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c3299cce98ebd4e4695a760f0249e16e +timeCreated: 1483469259 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI.meta b/Editor/Build/Settings/UI.meta new file mode 100644 index 0000000..56e57fb --- /dev/null +++ b/Editor/Build/Settings/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 11a13a1f3f4016d499ac37a5cf8c36c6 +folderAsset: yes +timeCreated: 1463149880 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/BasicSettingsDrawer.cs b/Editor/Build/Settings/UI/BasicSettingsDrawer.cs new file mode 100644 index 0000000..65d27df --- /dev/null +++ b/Editor/Build/Settings/UI/BasicSettingsDrawer.cs @@ -0,0 +1,72 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BasicSettings))] +public class BasicSettingsDrawer : PropertyDrawer +{ + private string lastBuildPath = string.Empty; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, GUIContent.none, property); + + EditorGUILayout.BeginHorizontal(); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Basic Settings", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#basic-settings"); + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + GUILayout.Label("Build Path Options", UnityBuildGUIUtility.midHeaderStyle); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("baseBuildFolder")); + EditorGUILayout.PropertyField(property.FindPropertyRelative("buildPath")); + + GUILayout.Space(20); + GUILayout.Label("Post-Build Options", UnityBuildGUIUtility.midHeaderStyle); + + SerializedProperty openBuildFolderAfterBuild = property.FindPropertyRelative("openFolderPostBuild"); + openBuildFolderAfterBuild.boolValue = EditorGUILayout.ToggleLeft(" Open output folder after build", openBuildFolderAfterBuild.boolValue); + + string buildPath = Path.GetFullPath(Path.Combine(BuildSettings.basicSettings.baseBuildFolder, BuildSettings.basicSettings.buildPath)); + if (!string.Equals(buildPath, lastBuildPath)) + { + lastBuildPath = buildPath; + + if (buildPath.Contains(Path.GetFullPath(Application.dataPath))) + { + BuildNotificationList.instance.AddNotification(new BuildNotification( + BuildNotification.Category.Warning, + "Build Folder in Assets.", + "Putting build output in Assets is generally a bad idea.", + true, null)); + } + } + + if (GUILayout.Button("Open Build Folder", GUILayout.ExpandWidth(true))) + { + string path = BuildSettings.basicSettings.baseBuildFolder; + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + System.Diagnostics.Process.Start(path); + } + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/BasicSettingsDrawer.cs.meta b/Editor/Build/Settings/UI/BasicSettingsDrawer.cs.meta new file mode 100644 index 0000000..a4f49f9 --- /dev/null +++ b/Editor/Build/Settings/UI/BasicSettingsDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7575893b87d7c3644a8b788c56109cde +timeCreated: 1463149880 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs b/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs new file mode 100644 index 0000000..7a9a23d --- /dev/null +++ b/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs @@ -0,0 +1,79 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildReleaseType))] +public class BuildReleaseTypeDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + // Limit valid characters. + // TODO: This might not be necessary since name will need to be sanitized for different needs later (as an enum entry, pre-processor define, etc.) + //char chr = Event.current.character; + //if ((chr < 'a' || chr > 'z') && (chr < 'A' || chr > 'Z') && (chr < '0' || chr > '9') && chr != '-' && chr != '_' && chr != ' ') + //{ + // Event.current.character = '\0'; + //} + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader(property.FindPropertyRelative("typeName").stringValue, ref show, false); + property.isExpanded = show; + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + GUILayout.Label("Basic Info", UnityBuildGUIUtility.midHeaderStyle); + + SerializedProperty typeName = property.FindPropertyRelative("typeName"); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Type Name"); + typeName.stringValue = BuildProject.SanitizeFolderName(GUILayout.TextArea(typeName.stringValue)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("bundleIndentifier")); + EditorGUILayout.PropertyField(property.FindPropertyRelative("productName")); + + GUILayout.Space(20); + GUILayout.Label("Build Options", UnityBuildGUIUtility.midHeaderStyle); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("customDefines")); + + SerializedProperty developmentBuild = property.FindPropertyRelative("developmentBuild"); + SerializedProperty allowDebugging = property.FindPropertyRelative("allowDebugging"); + developmentBuild.boolValue = EditorGUILayout.ToggleLeft(" Development Build", developmentBuild.boolValue); + allowDebugging.boolValue = EditorGUILayout.ToggleLeft(" Script Debugging", allowDebugging.boolValue); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("sceneList")); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Delete", GUILayout.MaxWidth(150))) + { + BuildReleaseType[] types = BuildSettings.releaseTypeList.releaseTypes; + for (int i = 0; i < types.Length; i++) + { + if (types[i].typeName == property.FindPropertyRelative("typeName").stringValue) + { + ArrayUtility.RemoveAt(ref BuildSettings.releaseTypeList.releaseTypes, i); + GUIUtility.keyboardControl = 0; + break; + } + } + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs.meta b/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs.meta new file mode 100644 index 0000000..9bca66b --- /dev/null +++ b/Editor/Build/Settings/UI/BuildReleaseTypeDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1508189a983722649a04582020710e08 +timeCreated: 1463205314 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs b/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs new file mode 100644 index 0000000..4f8bc03 --- /dev/null +++ b/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs @@ -0,0 +1,67 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildReleaseTypeList))] +public class BuildReleaseTypeListDrawer : PropertyDrawer +{ + private SerializedProperty list = null; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + EditorGUILayout.BeginHorizontal(); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Release Types", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#release-types"); + EditorGUILayout.EndHorizontal(); + + list = property.FindPropertyRelative("releaseTypes"); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = 0; i < list.arraySize; i++) + { + SerializedProperty typeProperty = list.GetArrayElementAtIndex(i); + EditorGUILayout.PropertyField(typeProperty, GUILayout.MaxHeight(0)); + } + + GUILayout.Space(20); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Add Release Type", GUILayout.ExpandWidth(false), GUILayout.MaxWidth(150))) + { + // Add new entry. + int addedIndex = list.arraySize; + list.InsertArrayElementAtIndex(addedIndex); + + // Set default values. + SerializedProperty addedEntry = list.GetArrayElementAtIndex(addedIndex); + addedEntry.FindPropertyRelative("typeName").stringValue = "NewReleaseType"; + addedEntry.FindPropertyRelative("productName").stringValue = Application.productName; + + list.serializedObject.ApplyModifiedProperties(); + + BuildSettings.releaseTypeList.releaseTypes[BuildSettings.releaseTypeList.releaseTypes.Length - 1].sceneList = new SceneList(); + + GUIUtility.keyboardControl = 0; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs.meta b/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs.meta new file mode 100644 index 0000000..102bf5a --- /dev/null +++ b/Editor/Build/Settings/UI/BuildReleaseTypeListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4ea6df4e924d47c4686e753307b6af43 +timeCreated: 1463212050 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/BuildSettingsEditor.cs b/Editor/Build/Settings/UI/BuildSettingsEditor.cs new file mode 100644 index 0000000..b8795cb --- /dev/null +++ b/Editor/Build/Settings/UI/BuildSettingsEditor.cs @@ -0,0 +1,24 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomEditor(typeof(BuildSettings))] +public class BuildSettingsEditor : Editor +{ + public override void OnInspectorGUI() + { + Color defaultBackgroundColor = GUI.backgroundColor; + GUI.backgroundColor = Color.green; + + if (GUILayout.Button("Open SuperUnityBuild", GUILayout.ExpandWidth(true), GUILayout.MinHeight(30))) + { + UnityBuildWindow.ShowWindow(); + } + + GUI.backgroundColor = defaultBackgroundColor; + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/BuildSettingsEditor.cs.meta b/Editor/Build/Settings/UI/BuildSettingsEditor.cs.meta new file mode 100644 index 0000000..6e9e896 --- /dev/null +++ b/Editor/Build/Settings/UI/BuildSettingsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7f3d1fe395581a944b600ce1a7cbd953 +timeCreated: 1463149881 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/ProductParametersDrawer.cs b/Editor/Build/Settings/UI/ProductParametersDrawer.cs new file mode 100644 index 0000000..76e10cf --- /dev/null +++ b/Editor/Build/Settings/UI/ProductParametersDrawer.cs @@ -0,0 +1,58 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(ProductParameters))] +public class ProductParametersDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, GUIContent.none, property); + + EditorGUILayout.BeginHorizontal(); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Product Parameters", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#product-parameters"); + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("version")); + + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.PropertyField(property.FindPropertyRelative("lastGeneratedVersion")); + EditorGUI.EndDisabledGroup(); + + SerializedProperty autoGenerate = property.FindPropertyRelative("autoGenerate"); + autoGenerate.boolValue = EditorGUILayout.ToggleLeft("Auto-Generate Version", autoGenerate.boolValue); + + EditorGUILayout.PropertyField(property.FindPropertyRelative("buildCounter")); + + if (GUILayout.Button("Reset Build Counter", GUILayout.ExpandWidth(true))) + { + property.FindPropertyRelative("buildCounter").intValue = 0; + } + + if (!autoGenerate.boolValue && GUILayout.Button("Generate Version String Now", GUILayout.ExpandWidth(true))) + { + BuildProject.GenerateVersionString(BuildSettings.productParameters, DateTime.Now); + } + + property.serializedObject.ApplyModifiedProperties(); + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/ProductParametersDrawer.cs.meta b/Editor/Build/Settings/UI/ProductParametersDrawer.cs.meta new file mode 100644 index 0000000..6f340ac --- /dev/null +++ b/Editor/Build/Settings/UI/ProductParametersDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 45817ba856e9843418962274fce786a6 +timeCreated: 1463217936 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs b/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs new file mode 100644 index 0000000..5bc797b --- /dev/null +++ b/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs @@ -0,0 +1,257 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(ProjectConfigurations))] +public class ProjectConfigurationsDrawer : PropertyDrawer +{ + private bool show; + + private SerializedProperty showViewOptions; + private SerializedProperty showConfigs; + private SerializedProperty showBuildInfo; + private SerializedProperty hideDisabled; + private SerializedProperty treeView; + private SerializedProperty selectedKeyChain; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + showViewOptions = property.FindPropertyRelative("showViewOptions"); + showConfigs = property.FindPropertyRelative("showConfigs"); + showBuildInfo = property.FindPropertyRelative("showBuildInfo"); + hideDisabled = property.FindPropertyRelative("hideDisabled"); + treeView = property.FindPropertyRelative("treeView"); + selectedKeyChain = property.FindPropertyRelative("selectedKeyChain"); + + EditorGUI.BeginProperty(position, label, property); + + EditorGUILayout.BeginHorizontal(); + + show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Build Configurations", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + UnityBuildGUIUtility.HelpButton("Parameter-Details#build-configurations"); + EditorGUILayout.EndHorizontal(); + + Color defaultBackgroundColor = GUI.backgroundColor; + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + EditorGUILayout.BeginHorizontal(); + show = showViewOptions.isExpanded; + UnityBuildGUIUtility.DropdownHeader("View Options", ref show, false, GUILayout.ExpandWidth(true)); + showViewOptions.isExpanded = show; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + hideDisabled.boolValue = EditorGUILayout.ToggleLeft("Hide disabled configurations", hideDisabled.boolValue); + treeView.boolValue = EditorGUILayout.ToggleLeft("Show full configurations tree", treeView.boolValue); + + EditorGUILayout.EndVertical(); + } + + GUILayout.Space(5); + EditorGUILayout.BeginHorizontal(); + show = showConfigs.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Configurations", ref show, false, GUILayout.ExpandWidth(true)); + showConfigs.isExpanded = show; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + if (BuildSettings.projectConfigurations.configSet.Keys.Count > 0) + { + BuildReleaseType[] releaseTypes = BuildSettings.releaseTypeList.releaseTypes; + for (int i = 0; i < releaseTypes.Length; i++) + { + string key = releaseTypes[i].typeName; + Configuration config = BuildSettings.projectConfigurations.configSet[key]; + DisplayConfigTree(key, config, 0); + } + } + else + { + EditorGUILayout.HelpBox("No Configuration info. Please add a Release Type.", MessageType.Error); + } + + + EditorGUILayout.EndVertical(); + } + + GUILayout.Space(5); + EditorGUILayout.BeginHorizontal(); + show = showBuildInfo.isExpanded; + UnityBuildGUIUtility.DropdownHeader("Build Info", ref show, false, GUILayout.ExpandWidth(true)); + showBuildInfo.isExpanded = show; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + if (string.IsNullOrEmpty(selectedKeyChain.stringValue)) + { + EditorGUILayout.HelpBox("Click a build configuration above in \"Configurations\" to view full details.", MessageType.Info); + } + else + { + BuildReleaseType releaseType; + BuildPlatform platform; + BuildArchitecture arch; + BuildDistribution dist; + + bool parseSuccess = BuildSettings.projectConfigurations.ParseKeychain(selectedKeyChain.stringValue, out releaseType, out platform, out arch, out dist); + + if (parseSuccess) + { + string defines = BuildProject.GenerateDefaultDefines(releaseType, platform, arch, dist); + + EditorGUILayout.LabelField("Misc Info", UnityBuildGUIUtility.midHeaderStyle); + EditorGUILayout.LabelField("Defines:"); + EditorGUILayout.LabelField(defines, EditorStyles.wordWrappedLabel); + + if (releaseType != null) + { + EditorGUILayout.LabelField("Release Type", UnityBuildGUIUtility.midHeaderStyle); + EditorGUILayout.LabelField("Type Name:\t" + releaseType.typeName); + + if (!string.IsNullOrEmpty(releaseType.bundleIndentifier)) + EditorGUILayout.LabelField("Bundle Identifier:\t" + releaseType.bundleIndentifier); + + EditorGUILayout.LabelField("Product Name:\t" + releaseType.productName); + } + + if (platform != null) + { + EditorGUILayout.LabelField("Platform", UnityBuildGUIUtility.midHeaderStyle); + EditorGUILayout.LabelField("Name:\t\t" + platform.platformName); + } + + if (arch != null) + { + EditorGUILayout.LabelField("Architecture", UnityBuildGUIUtility.midHeaderStyle); + EditorGUILayout.LabelField("Name:\t\t" + arch.name); + } + + if (dist != null) + { + EditorGUILayout.LabelField("Distribution", UnityBuildGUIUtility.midHeaderStyle); + EditorGUILayout.LabelField("Name:\t\t" + dist.distributionName); + } + + GUILayout.Space(20); + GUI.backgroundColor = Color.green; + if (GUILayout.Button("Build", GUILayout.ExpandWidth(true))) + { + EditorApplication.delayCall += () => + BuildProject.BuildSingle(selectedKeyChain.stringValue); + } + if (GUILayout.Button("Build and Run", GUILayout.ExpandWidth(true))) + { + EditorApplication.delayCall += () => + BuildProject.BuildSingle(selectedKeyChain.stringValue, BuildOptions.AutoRunPlayer); + } + + EditorGUI.BeginDisabledGroup(!releaseType.developmentBuild); + if (GUILayout.Button("Build and Run w/ Profiler", GUILayout.ExpandWidth(true))) + { + EditorApplication.delayCall += () => + BuildProject.BuildSingle(selectedKeyChain.stringValue, BuildOptions.AutoRunPlayer | BuildOptions.ConnectWithProfiler); + } + EditorGUI.EndDisabledGroup(); + GUI.backgroundColor = defaultBackgroundColor; + + if (GUILayout.Button("Refresh BuildConstants and Apply Defines", GUILayout.ExpandWidth(true))) + { + EditorUserBuildSettings.SwitchActiveBuildTarget(arch.target); + PlayerSettings.SetScriptingDefineSymbolsForGroup(platform.targetGroup, defines); + BuildConstantsGenerator.Generate(DateTime.Now, BuildSettings.productParameters.lastGeneratedVersion, releaseType, platform, arch, dist); + } + } + else + { + EditorGUILayout.HelpBox("Could not parse selected configuration. It may no longer be valid due to a changes. Select again.", MessageType.Info); + } + } + + EditorGUILayout.EndVertical(); + } + + property.serializedObject.ApplyModifiedProperties(); + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } + + private void DisplayConfigTree(string key, Configuration config, int depth, bool enabled = true) + { + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginDisabledGroup(!enabled); + + bool displayButton = (depth >= 2 && (config.childKeys == null || config.childKeys.Length == 0)); + + if (treeView.boolValue) + { + GUILayout.Space(20 * depth); + + config.enabled = EditorGUILayout.Toggle(config.enabled, GUILayout.ExpandWidth(false), GUILayout.MaxWidth(10)); + } + + if (displayButton) + { + string displayText; + + if (treeView.boolValue) + { + string[] split = key.Split('/'); + displayText = split[split.Length - 1]; + } + else + { + displayText = key; + config.enabled = EditorGUILayout.Toggle(config.enabled, GUILayout.ExpandWidth(false), GUILayout.MaxWidth(10)); + } + + if (GUILayout.Button(displayText, UnityBuildGUIUtility.dropdownHeaderStyle)) + { + selectedKeyChain.stringValue = key; + } + } + else if (treeView.boolValue) + { + EditorGUILayout.LabelField(key, UnityBuildGUIUtility.midHeaderStyle); + } + + EditorGUI.EndDisabledGroup(); + EditorGUILayout.EndHorizontal(); + + if (!treeView.boolValue && displayButton) + { + GUILayout.Space(5); + } + + if (config.childKeys != null && config.childKeys.Length > 0 && (!hideDisabled.boolValue || config.enabled)) + { + foreach (string childKey in config.childKeys) + { + Configuration childConfig = BuildSettings.projectConfigurations.configSet[childKey]; + DisplayConfigTree(childKey, childConfig, depth + 1, config.enabled && enabled); + } + } + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs.meta b/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs.meta new file mode 100644 index 0000000..408ccc7 --- /dev/null +++ b/Editor/Build/Settings/UI/ProjectConfigurationsDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1c1e1aa95fa191641952537fede55b4f +timeCreated: 1463227987 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Settings/UI/SceneListDrawer.cs b/Editor/Build/Settings/UI/SceneListDrawer.cs new file mode 100644 index 0000000..ccff2cd --- /dev/null +++ b/Editor/Build/Settings/UI/SceneListDrawer.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(SceneList))] +public class SceneListDrawer : PropertyDrawer +{ + private int index = 0; + private List availableScenesList = null; + private SerializedProperty list; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + EditorGUILayout.BeginHorizontal(); + + bool show = property.isExpanded; + UnityBuildGUIUtility.DropdownHeader("SceneList", ref show, false, GUILayout.ExpandWidth(true)); + property.isExpanded = show; + + EditorGUILayout.EndHorizontal(); + + //Refresh all scene lists. + for (int i = 0; i < BuildSettings.releaseTypeList.releaseTypes.Length; i++) + { + BuildReleaseType rt = BuildSettings.releaseTypeList.releaseTypes[i]; + rt.sceneList.Refresh(); + } + + list = property.FindPropertyRelative("enabledScenes"); + PopulateSceneList(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = 0; i < list.arraySize; i++) + { + SerializedProperty platformProperty = list.GetArrayElementAtIndex(i); + + string filePath = platformProperty.FindPropertyRelative("filePath").stringValue; + string sceneName = Path.GetFileNameWithoutExtension(filePath); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.TextArea(sceneName + " (" + filePath + ")"); + + EditorGUI.BeginDisabledGroup(i == 0); + if (GUILayout.Button("↑↑", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, 0); + } + if (GUILayout.Button("↑", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, i - 1); + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.BeginDisabledGroup(i == list.arraySize - 1); + if (GUILayout.Button("↓", UnityBuildGUIUtility.helpButtonStyle)) + { + list.MoveArrayElement(i, i + 1); + } + EditorGUI.EndDisabledGroup(); + + if (GUILayout.Button("X", UnityBuildGUIUtility.helpButtonStyle)) + { + list.DeleteArrayElementAtIndex(i); + } + + property.serializedObject.ApplyModifiedProperties(); + + PopulateSceneList(); + + EditorGUILayout.EndHorizontal(); + } + + if (list.arraySize > 0) + { + GUILayout.Space(20); + } + + if (availableScenesList.Count > 0) + { + GUILayout.BeginHorizontal(); + + string[] sceneStringList = new string[availableScenesList.Count]; + for (int i = 0; i < sceneStringList.Length; i++) + { + sceneStringList[i] = Path.GetFileNameWithoutExtension(availableScenesList[i].filePath) + " (" + availableScenesList[i].filePath.Replace("/", "\\") + ")"; + } + + index = EditorGUILayout.Popup(index, sceneStringList, UnityBuildGUIUtility.popupStyle, GUILayout.ExpandWidth(true)); + if (GUILayout.Button("Add Scene", GUILayout.ExpandWidth(false), GUILayout.MaxWidth(150)) && index < availableScenesList.Count) + { + int addedIndex = list.arraySize; + SceneList.Scene scene = availableScenesList[index]; + list.InsertArrayElementAtIndex(addedIndex); + list.GetArrayElementAtIndex(addedIndex).FindPropertyRelative("filePath").stringValue = scene.filePath; + + availableScenesList.RemoveAt(index); + + index = 0; + } + + GUILayout.EndHorizontal(); + } + + list.serializedObject.ApplyModifiedProperties(); + property.serializedObject.ApplyModifiedProperties(); + + if (GUILayout.Button("Refresh Scene List", GUILayout.ExpandWidth(true))) + { + PopulateSceneList(); + } + + EditorGUILayout.EndVertical(); + } + + EditorGUI.EndProperty(); + } + + private void PopulateSceneList() + { + if (availableScenesList == null) + availableScenesList = new List(); + else + availableScenesList.Clear(); + + string[] allScenes = SceneList.GetListOfAllScenes(); + + for (int i = 0; i < allScenes.Length; i++) + { + bool sceneAlreadyAdded = false; + for (int j = 0; j < list.arraySize; j++) + { + if (Path.Equals(list.GetArrayElementAtIndex(j).FindPropertyRelative("filePath").stringValue, allScenes[i])) + { + sceneAlreadyAdded = true; + break; + } + } + + if (!sceneAlreadyAdded) + { + SceneList.Scene scene = new SceneList.Scene(); + scene.filePath = allScenes[i]; + availableScenesList.Add(scene); + } + } + } +} + +} \ No newline at end of file diff --git a/Editor/Build/Settings/UI/SceneListDrawer.cs.meta b/Editor/Build/Settings/UI/SceneListDrawer.cs.meta new file mode 100644 index 0000000..dff970b --- /dev/null +++ b/Editor/Build/Settings/UI/SceneListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e6a433e6f905fd44aa43a35a593c64fc +timeCreated: 1483469765 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/UI.meta b/Editor/Build/UI.meta new file mode 100644 index 0000000..35e65cc --- /dev/null +++ b/Editor/Build/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 24a2dffcb208d294296c133ea1c09a7b +folderAsset: yes +timeCreated: 1463204367 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/UI/UnityBuildGUIUtility.cs b/Editor/Build/UI/UnityBuildGUIUtility.cs new file mode 100644 index 0000000..61f4921 --- /dev/null +++ b/Editor/Build/UI/UnityBuildGUIUtility.cs @@ -0,0 +1,183 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +public class UnityBuildGUIUtility +{ + private const string HELP_URL = @"https://github.com/Chaser324/unity-build/wiki/{0}"; + + #region Singleton + + private static UnityBuildGUIUtility _instance = null; + + public static UnityBuildGUIUtility instance + { + get + { + if (_instance == null) + { + _instance = new UnityBuildGUIUtility(); + } + + return _instance; + } + } + + #endregion + + private GUIStyle _dropdownHeaderStyle; + private GUIStyle _dropdownContentStyle; + private GUIStyle _helpButtonStyle; + private GUIStyle _midHeaderStyle; + private GUIStyle _popupStyle; + private GUIStyle _mainTitleStyle; + private GUIStyle _subTitleStyle; + + private Color32 _defaultBackgroundColor = GUI.backgroundColor; + private Color32 _mainHeaderColor = new Color32(180, 180, 255, 255); + + private GUIContent helpButtonContent; + + private UnityBuildGUIUtility() + { + _dropdownHeaderStyle = new GUIStyle(GUI.skin.button); + _dropdownHeaderStyle.alignment = TextAnchor.MiddleLeft; + _dropdownHeaderStyle.fontStyle = FontStyle.Bold; + _dropdownHeaderStyle.margin = new RectOffset(5, 5, 0, 0); + + _popupStyle = new GUIStyle(EditorStyles.popup); + _popupStyle.fontSize = 11; + _popupStyle.alignment = TextAnchor.MiddleLeft; + _popupStyle.margin = new RectOffset(0, 0, 4, 0); + _popupStyle.fixedHeight = 18; + + _helpButtonStyle = new GUIStyle(_dropdownHeaderStyle); + _helpButtonStyle.alignment = TextAnchor.MiddleCenter; + _helpButtonStyle.fontStyle = FontStyle.Normal; + _helpButtonStyle.margin = new RectOffset(0, 5, 0, 0); + _helpButtonStyle.fixedWidth = 30; + + _midHeaderStyle = new GUIStyle(EditorStyles.helpBox); + _midHeaderStyle.fontStyle = FontStyle.Bold; + + _dropdownContentStyle = new GUIStyle(GUI.skin.textField); + _dropdownContentStyle.padding = new RectOffset(5, 5, 5, 5); + _dropdownContentStyle.margin = new RectOffset(5, 5, 0, 0); + + _mainTitleStyle = new GUIStyle(EditorStyles.miniBoldLabel); + _mainTitleStyle.fontSize = 18; + _mainTitleStyle.fontStyle = FontStyle.Bold; + _mainTitleStyle.alignment = TextAnchor.MiddleCenter; + _mainTitleStyle.fixedHeight = 35; + _mainTitleStyle.normal.textColor = new Color32(255, 55, 85, 255); + + _subTitleStyle = new GUIStyle(_mainTitleStyle); + _subTitleStyle.fontSize = 9; + _subTitleStyle.fontStyle = FontStyle.Normal; + _subTitleStyle.normal.textColor = new Color32(83, 229, 255, 255); + + helpButtonContent = new GUIContent("?", "Help"); + } + + public static void OpenHelp(string anchor = "") + { + Application.OpenURL(string.Format(HELP_URL, anchor)); + } + + public static void DropdownHeader(string content, ref bool showDropdown, bool noColor, params GUILayoutOption[] options) + { + if (!noColor) + GUI.backgroundColor = instance._mainHeaderColor; + + if (GUILayout.Button(content, UnityBuildGUIUtility.dropdownHeaderStyle, options)) + { + showDropdown = !showDropdown; + GUIUtility.keyboardControl = 0; + } + + if (!noColor) + GUI.backgroundColor = instance._defaultBackgroundColor; + } + + public static void HelpButton(string anchor = "") + { + if (GUILayout.Button(_instance.helpButtonContent, UnityBuildGUIUtility.helpButtonStyle)) + OpenHelp(anchor); + } + + public static GUIStyle helpButtonStyle + { + get + { + return instance._helpButtonStyle; + } + } + + public static GUIStyle midHeaderStyle + { + get + { + return instance._midHeaderStyle; + } + } + + public static GUIStyle dropdownHeaderStyle + { + get + { + return instance._dropdownHeaderStyle; + } + } + + public static GUIStyle dropdownContentStyle + { + get + { + return instance._dropdownContentStyle; + } + } + + public static GUIStyle popupStyle + { + get + { + return instance._popupStyle; + } + } + + public static GUIStyle mainTitleStyle + { + get + { + return instance._mainTitleStyle; + } + } + + public static GUIStyle subTitleStyle + { + get + { + return instance._subTitleStyle; + } + } + + public static Color defaultBackgroundColor + { + get + { + return instance._defaultBackgroundColor; + } + } + + public static Color mainHeaderColor + { + get + { + return instance._mainHeaderColor; + } + } +} + +} \ No newline at end of file diff --git a/Editor/Build/UI/UnityBuildGUIUtility.cs.meta b/Editor/Build/UI/UnityBuildGUIUtility.cs.meta new file mode 100644 index 0000000..c604251 --- /dev/null +++ b/Editor/Build/UI/UnityBuildGUIUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5410a041ada7760408a8035f82735bc6 +timeCreated: 1463149880 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/UI/UnityBuildWindow.cs b/Editor/Build/UI/UnityBuildWindow.cs new file mode 100644 index 0000000..c1d048b --- /dev/null +++ b/Editor/Build/UI/UnityBuildWindow.cs @@ -0,0 +1,136 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class UnityBuildWindow : EditorWindow +{ + public BuildNotificationList notifications = BuildNotificationList.instance; + private Vector2 scrollPos = Vector2.zero; + + private SerializedObject settings; + private SerializedObject go; + + #region MenuItems + + [MenuItem("Window/SuperUnityBuild")] + public static void ShowWindow() + { + // Get Inspector type, so we can try to autodock beside it. + Assembly editorAsm = typeof(Editor).Assembly; + Type inspWndType = editorAsm.GetType("UnityEditor.InspectorWindow"); + + // Get and show window. + UnityBuildWindow window; + if (inspWndType != null) + { + window = EditorWindow.GetWindow(inspWndType); + } + else + { + window = EditorWindow.GetWindow(); + } + + window.Show(); + } + + #endregion + + #region Unity Events + + protected void OnEnable() + { +#if UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4_OR_NEWER + GUIContent title = new GUIContent("SuperUnityBuild"); + titleContent = title; +#else + title = "SuperUnityBuild"; +#endif + + BuildNotificationList.instance.InitializeErrors(); + } + + protected void OnInspectorUpdate() + { + Repaint(); + } + + protected void OnGUI() + { + Init(); + + settings.Update(); + go.Update(); + + DrawTitle(); + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false); + + DrawProperties(); + DrawBuildButtons(); + GUILayout.Space(30); + + EditorGUILayout.EndScrollView(); + } + + #endregion + + #region Private Methods + + private void Init() + { + if (go == null) + go = new SerializedObject(this); + + if (settings == null) + settings = new SerializedObject(BuildSettings.instance); + + BuildSettings.Init(); + } + + private void DrawTitle() + { + EditorGUILayout.LabelField("Super Unity Build", UnityBuildGUIUtility.mainTitleStyle); + EditorGUILayout.LabelField("by Super Systems Softworks", UnityBuildGUIUtility.subTitleStyle); + GUILayout.Space(15); + } + + private void DrawProperties() + { + EditorGUILayout.PropertyField(settings.FindProperty("_basicSettings"), GUILayout.MaxHeight(0)); + EditorGUILayout.PropertyField(settings.FindProperty("_productParameters"), GUILayout.MaxHeight(10)); + EditorGUILayout.PropertyField(settings.FindProperty("_releaseTypeList"), GUILayout.MaxHeight(10)); + EditorGUILayout.PropertyField(settings.FindProperty("_platformList"), GUILayout.MaxHeight(10)); + EditorGUILayout.PropertyField(settings.FindProperty("_preBuildActions"), new GUIContent("Pre-Build Actions"), GUILayout.MaxHeight(10)); + EditorGUILayout.PropertyField(settings.FindProperty("_postBuildActions"), new GUIContent("Post-Build Actions"), GUILayout.MaxHeight(10)); + + BuildSettings.projectConfigurations.Refresh(); + EditorGUILayout.PropertyField(settings.FindProperty("_projectConfigurations"), GUILayout.MaxHeight(10)); + + EditorGUILayout.PropertyField(go.FindProperty("notifications"), GUILayout.MaxHeight(10)); + + settings.ApplyModifiedProperties(); + } + + private void DrawBuildButtons() + { + int totalBuildCount = BuildSettings.projectConfigurations.GetEnabledBuildsCount(); + + EditorGUI.BeginDisabledGroup(totalBuildCount < 1); + GUI.backgroundColor = Color.green; + if (GUILayout.Button("Perform All Enabled Builds (" + totalBuildCount + " Builds)", GUILayout.ExpandWidth(true), GUILayout.MinHeight(30))) + { + EditorApplication.delayCall += BuildProject.BuildAll; + } + GUI.backgroundColor = UnityBuildGUIUtility.defaultBackgroundColor; + EditorGUI.EndDisabledGroup(); + } + + #endregion +} + +} diff --git a/Editor/Build/UI/UnityBuildWindow.cs.meta b/Editor/Build/UI/UnityBuildWindow.cs.meta new file mode 100644 index 0000000..676fa5e --- /dev/null +++ b/Editor/Build/UI/UnityBuildWindow.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e133503ddc20204418e0b185a06a39ee +timeCreated: 1462480530 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildConstantsGenerator.cs b/Editor/BuildConstantsGenerator.cs new file mode 100644 index 0000000..db38626 --- /dev/null +++ b/Editor/BuildConstantsGenerator.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +public static class BuildConstantsGenerator +{ + public const string NONE = "None"; + + public static void Generate( + DateTime buildTime, + string currentVersion = "", + BuildReleaseType currentReleaseType = null, + BuildPlatform currentBuildPlatform = null, + BuildArchitecture currentBuildArchitecture = null, + BuildDistribution currentBuildDistribution = null) + { + // Find the BuildConstants file. + string[] fileSearchResults = Directory.GetFiles(Application.dataPath, "BuildConstants.cs", SearchOption.AllDirectories); + string filePath = null; + string desiredFilePath = string.Format("UnityBuild{0}BuildConstants.cs", Path.DirectorySeparatorChar); + for (int i = 0; i < fileSearchResults.Length; i++) + { + if (fileSearchResults[i].EndsWith(desiredFilePath)) + { + filePath = fileSearchResults[i]; + break; + } + } + + if (string.IsNullOrEmpty(filePath)) + { + return; + } + + // Cache any current values if needed. + string versionString = string.IsNullOrEmpty(currentVersion) ? BuildConstants.version.ToString() : currentVersion; + string releaseTypeString = currentReleaseType == null ? BuildConstants.releaseType.ToString() : SanitizeString(currentReleaseType.typeName); + string platformString = currentBuildPlatform == null ? BuildConstants.platform.ToString() : SanitizeString(currentBuildPlatform.platformName); + string archString = currentBuildArchitecture == null ? BuildConstants.architecture.ToString() : SanitizeString(currentBuildArchitecture.name); + + string distributionString = string.Empty; + if (currentBuildDistribution == null) + { + if (currentReleaseType == null) + { + // No new parameter specified, so use the old value. + distributionString = BuildConstants.architecture.ToString(); + } + else + { + // There are new parameters but no distribution. Should be intentional, so distribution is NONE. + distributionString = NONE; + } + } + else + { + distributionString = SanitizeString(currentBuildDistribution.distributionName); + } + + // Delete any existing version. + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + + // Create a buffer that we'll use to check for any duplicated names. + List enumBuffer = new List(); + + using (StreamWriter writer = new StreamWriter(filePath)) + { + // Start of file and class. + writer.WriteLine("// This file is auto-generated. Do not modify or move this file."); + writer.WriteLine(); + writer.WriteLine("public static class BuildConstants"); + writer.WriteLine("{"); + + // Write ReleaseType enum. + writer.WriteLine(" public enum ReleaseType"); + writer.WriteLine(" {"); + writer.WriteLine(" {0},", NONE); + enumBuffer.Add(NONE); + foreach (BuildReleaseType releaseType in BuildSettings.releaseTypeList.releaseTypes) + { + string addedString = SanitizeString(releaseType.typeName); + + if (!enumBuffer.Contains(addedString)) + { + enumBuffer.Add(addedString); + writer.WriteLine(" {0},", addedString); + } + } + writer.WriteLine(" }"); + writer.WriteLine(); + + // Validate ReleaseType string. + if (!enumBuffer.Contains(releaseTypeString)) + releaseTypeString = NONE; + + // Write Platform enum. + enumBuffer.Clear(); + writer.WriteLine(" public enum Platform"); + writer.WriteLine(" {"); + writer.WriteLine(" {0},", NONE); + enumBuffer.Add(NONE); + foreach (BuildPlatform platform in BuildSettings.platformList.platforms) + { + string addedString = SanitizeString(platform.platformName); + + if (platform.enabled && !enumBuffer.Contains(addedString)) + { + enumBuffer.Add(addedString); + writer.WriteLine(" {0},", addedString); + } + } + writer.WriteLine(" }"); + writer.WriteLine(); + + // Validate Platform string. + if (!enumBuffer.Contains(platformString)) + platformString = NONE; + + // Write Architecture enum. + enumBuffer.Clear(); + writer.WriteLine(" public enum Architecture"); + writer.WriteLine(" {"); + writer.WriteLine(" {0},", NONE); + enumBuffer.Add(NONE); + foreach (BuildPlatform platform in BuildSettings.platformList.platforms) + { + if (platform.enabled) + { + foreach (BuildArchitecture arch in platform.architectures) + { + string addedString = SanitizeString(arch.name); + + if (arch.enabled && !enumBuffer.Contains(addedString)) + { + enumBuffer.Add(addedString); + writer.WriteLine(" {0},", addedString); + } + } + } + } + writer.WriteLine(" }"); + writer.WriteLine(); + + // Validate Architecture string. + if (!enumBuffer.Contains(archString)) + archString = NONE; + + // Write Distribution enum. + enumBuffer.Clear(); + writer.WriteLine(" public enum Distribution"); + writer.WriteLine(" {"); + writer.WriteLine(" {0},", NONE); + enumBuffer.Add(NONE); + foreach (BuildPlatform platform in BuildSettings.platformList.platforms) + { + if (platform.enabled) + { + foreach (BuildDistribution dist in platform.distributionList.distributions) + { + string addedString = SanitizeString(dist.distributionName); + + if (dist.enabled && !enumBuffer.Contains(addedString)) + { + enumBuffer.Add(addedString); + writer.WriteLine(" {0},", addedString); + } + } + } + } + writer.WriteLine(" }"); + writer.WriteLine(); + + // Validate Distribution string. + if (!enumBuffer.Contains(distributionString)) + distributionString = NONE; + + // Write current values. + writer.WriteLine(" public static readonly System.DateTime buildDate = new System.DateTime({0});", buildTime.Ticks); + writer.WriteLine(" public const string version = \"{0}\";", versionString); + writer.WriteLine(" public const ReleaseType releaseType = ReleaseType.{0};", releaseTypeString); + writer.WriteLine(" public const Platform platform = Platform.{0};", platformString); + writer.WriteLine(" public const Architecture architecture = Architecture.{0};", archString); + writer.WriteLine(" public const Distribution distribution = Distribution.{0};", distributionString); + + // End of class. + writer.WriteLine("}"); + writer.WriteLine(); + } + + // Refresh AssetDatabse so that changes take effect. + AssetDatabase.Refresh(); + } + + private static string SanitizeString(string str) + { + str = Regex.Replace(str, "[^a-zA-Z0-9_]", "_", RegexOptions.Compiled); + if (char.IsDigit(str[0])) + { + str = "_" + str; + } + return str; + } +} + +} \ No newline at end of file diff --git a/Editor/BuildConstantsGenerator.cs.meta b/Editor/BuildConstantsGenerator.cs.meta new file mode 100644 index 0000000..6b0b885 --- /dev/null +++ b/Editor/BuildConstantsGenerator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 18890f23aa85ae249887b3a38b7031c3 +timeCreated: 1483545467 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Generic.meta b/Editor/Generic.meta new file mode 100644 index 0000000..0231301 --- /dev/null +++ b/Editor/Generic.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f93cd2aec6b897349a9aa8f318ad1646 +folderAsset: yes +timeCreated: 1463230039 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Generic/FilePathAttribute.cs b/Editor/Generic/FilePathAttribute.cs new file mode 100644 index 0000000..b8f5a11 --- /dev/null +++ b/Editor/Generic/FilePathAttribute.cs @@ -0,0 +1,24 @@ +using System.IO; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +public class FilePathAttribute : PropertyAttribute +{ + public bool folder = false; + public bool allowManualEdit = true; + public string message = ""; + public string initialNameOrFilter = ""; + public string projectPath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")) + Path.DirectorySeparatorChar; + + public FilePathAttribute(bool folder = true, bool allowManualEdit = true, string message = "", string initialFolderName = "") + { + this.folder = folder; + this.allowManualEdit = allowManualEdit; + this.message = message; + this.initialNameOrFilter = initialFolderName; + } +} + +} diff --git a/Editor/Generic/FilePathAttribute.cs.meta b/Editor/Generic/FilePathAttribute.cs.meta new file mode 100644 index 0000000..31326e0 --- /dev/null +++ b/Editor/Generic/FilePathAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 523280825bb87b747bd72001281190ae +timeCreated: 1483998265 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Generic/FilePathDrawer.cs b/Editor/Generic/FilePathDrawer.cs new file mode 100644 index 0000000..6f0636d --- /dev/null +++ b/Editor/Generic/FilePathDrawer.cs @@ -0,0 +1,68 @@ +using UnityEngine; +using UnityEditor; +using System.IO; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(FilePathAttribute))] +public class FilePathDrawer : PropertyDrawer +{ + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType != SerializedPropertyType.String) + base.OnGUI(position, property, label); + + EditorGUI.BeginProperty(position, label, property); + + FilePathAttribute filePathAttr = attribute as FilePathAttribute; + + EditorGUILayout.BeginHorizontal(); + + if (filePathAttr.allowManualEdit) + property.stringValue = EditorGUILayout.TextField(label, property.stringValue); + else + EditorGUILayout.TextField(label, property.stringValue); + + if (GUILayout.Button("...", UnityBuildGUIUtility.helpButtonStyle)) + { + SetPath(property, filePathAttr); + } + + EditorGUILayout.EndHorizontal(); + + EditorGUI.EndProperty(); + } + + private void SetPath(SerializedProperty property, FilePathAttribute filePathAttr) + { + string directory; + if (filePathAttr.folder) + directory = EditorUtility.OpenFolderPanel(filePathAttr.message, filePathAttr.projectPath, filePathAttr.initialNameOrFilter); + else + directory = EditorUtility.OpenFilePanel(filePathAttr.message, filePathAttr.projectPath, filePathAttr.initialNameOrFilter); + + // Canceled. + if (string.IsNullOrEmpty(directory)) + { + return; + } + + // Normalize path separators. + directory = Path.GetFullPath(directory); + + // If relative to project path, reduce the filepath to just what we need. + if (directory.Contains(filePathAttr.projectPath)) + directory = directory.Replace(filePathAttr.projectPath, ""); + + // Save setting. + property.stringValue = directory; + } +} + +} diff --git a/Editor/Generic/FilePathDrawer.cs.meta b/Editor/Generic/FilePathDrawer.cs.meta new file mode 100644 index 0000000..5fe694d --- /dev/null +++ b/Editor/Generic/FilePathDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a5105e008ea90f04e8deb62b30537b88 +timeCreated: 1483998265 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Generic/SerializableDictionary.cs b/Editor/Generic/SerializableDictionary.cs new file mode 100644 index 0000000..b778e55 --- /dev/null +++ b/Editor/Generic/SerializableDictionary.cs @@ -0,0 +1,589 @@ +// http://forum.unity3d.com/threads/finally-a-serializable-dictionary-for-unity-extracted-from-system-collections-generic.335797/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[Serializable, DebuggerDisplay("Count = {Count}")] +public class SerializableDictionary : IDictionary +{ + [SerializeField, HideInInspector] + int[] _Buckets; + [SerializeField, HideInInspector] + int[] _HashCodes; + [SerializeField, HideInInspector] + int[] _Next; + [SerializeField, HideInInspector] + int _Count; + [SerializeField, HideInInspector] + int _Version; + [SerializeField, HideInInspector] + int _FreeList; + [SerializeField, HideInInspector] + int _FreeCount; + [SerializeField, HideInInspector] + TKey[] _Keys; + [SerializeField, HideInInspector] + TValue[] _Values; + + readonly IEqualityComparer _Comparer; + + // Mainly for debugging purposes - to get the key-value pairs display + public Dictionary AsDictionary + { + get { return new Dictionary(this); } + } + + public int Count + { + get { return _Count - _FreeCount; } + } + + public TValue this[TKey key, TValue defaultValue] + { + get + { + int index = FindIndex(key); + if (index >= 0) + return _Values[index]; + return defaultValue; + } + } + + public TValue this[TKey key] + { + get + { + int index = FindIndex(key); + if (index >= 0) + return _Values[index]; + throw new KeyNotFoundException(key.ToString()); + } + + set { Insert(key, value, false); } + } + + public SerializableDictionary() + : this(0, null) + { + } + + public SerializableDictionary(int capacity) + : this(capacity, null) + { + } + + public SerializableDictionary(IEqualityComparer comparer) + : this(0, comparer) + { + } + + public SerializableDictionary(int capacity, IEqualityComparer comparer) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity"); + + Initialize(capacity); + + _Comparer = (comparer ?? EqualityComparer.Default); + } + + public SerializableDictionary(IDictionary dictionary) + : this(dictionary, null) + { + } + + public SerializableDictionary(IDictionary dictionary, IEqualityComparer comparer) + : this((dictionary != null) ? dictionary.Count : 0, comparer) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + foreach (KeyValuePair current in dictionary) + Add(current.Key, current.Value); + } + + public bool ContainsValue(TValue value) + { + if (value == null) + { + for (int i = 0; i < _Count; i++) + { + if (_HashCodes[i] >= 0 && _Values[i] == null) + return true; + } + } + else + { + var defaultComparer = EqualityComparer.Default; + for (int i = 0; i < _Count; i++) + { + if (_HashCodes[i] >= 0 && defaultComparer.Equals(_Values[i], value)) + return true; + } + } + return false; + } + + public bool ContainsKey(TKey key) + { + return FindIndex(key) >= 0; + } + + public void Clear() + { + if (_Count <= 0) + return; + + for (int i = 0; i < _Buckets.Length; i++) + _Buckets[i] = -1; + + Array.Clear(_Keys, 0, _Count); + Array.Clear(_Values, 0, _Count); + Array.Clear(_HashCodes, 0, _Count); + Array.Clear(_Next, 0, _Count); + + _FreeList = -1; + _Count = 0; + _FreeCount = 0; + _Version++; + } + + public void Add(TKey key, TValue value) + { + Insert(key, value, true); + } + + private void Resize(int newSize, bool forceNewHashCodes) + { + int[] bucketsCopy = new int[newSize]; + for (int i = 0; i < bucketsCopy.Length; i++) + bucketsCopy[i] = -1; + + var keysCopy = new TKey[newSize]; + var valuesCopy = new TValue[newSize]; + var hashCodesCopy = new int[newSize]; + var nextCopy = new int[newSize]; + + Array.Copy(_Values, 0, valuesCopy, 0, _Count); + Array.Copy(_Keys, 0, keysCopy, 0, _Count); + Array.Copy(_HashCodes, 0, hashCodesCopy, 0, _Count); + Array.Copy(_Next, 0, nextCopy, 0, _Count); + + if (forceNewHashCodes) + { + for (int i = 0; i < _Count; i++) + { + if (hashCodesCopy[i] != -1) + hashCodesCopy[i] = (_Comparer.GetHashCode(keysCopy[i]) & 2147483647); + } + } + + for (int i = 0; i < _Count; i++) + { + int index = hashCodesCopy[i] % newSize; + nextCopy[i] = bucketsCopy[index]; + bucketsCopy[index] = i; + } + + _Buckets = bucketsCopy; + _Keys = keysCopy; + _Values = valuesCopy; + _HashCodes = hashCodesCopy; + _Next = nextCopy; + } + + private void Resize() + { + Resize(PrimeHelper.ExpandPrime(_Count), false); + } + + public bool Remove(TKey key) + { + if (key == null) + throw new ArgumentNullException("key"); + + int hash = _Comparer.GetHashCode(key) & 2147483647; + int index = hash % _Buckets.Length; + int num = -1; + for (int i = _Buckets[index]; i >= 0; i = _Next[i]) + { + if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key)) + { + if (num < 0) + _Buckets[index] = _Next[i]; + else + _Next[num] = _Next[i]; + + _HashCodes[i] = -1; + _Next[i] = _FreeList; + _Keys[i] = default(TKey); + _Values[i] = default(TValue); + _FreeList = i; + _FreeCount++; + _Version++; + return true; + } + num = i; + } + return false; + } + + private void Insert(TKey key, TValue value, bool add) + { + if (key == null) + throw new ArgumentNullException("key"); + + if (_Buckets == null) + Initialize(0); + + int hash = _Comparer.GetHashCode(key) & 2147483647; + int index = hash % _Buckets.Length; + int num1 = 0; + for (int i = _Buckets[index]; i >= 0; i = _Next[i]) + { + if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key)) + { + if (add) + throw new ArgumentException("Key already exists: " + key); + + _Values[i] = value; + _Version++; + return; + } + num1++; + } + int num2; + if (_FreeCount > 0) + { + num2 = _FreeList; + _FreeList = _Next[num2]; + _FreeCount--; + } + else + { + if (_Count == _Keys.Length) + { + Resize(); + index = hash % _Buckets.Length; + } + num2 = _Count; + _Count++; + } + _HashCodes[num2] = hash; + _Next[num2] = _Buckets[index]; + _Keys[num2] = key; + _Values[num2] = value; + _Buckets[index] = num2; + _Version++; + + //if (num3 > 100 && HashHelpers.IsWellKnownEqualityComparer(comparer)) + //{ + // comparer = (IEqualityComparer)HashHelpers.GetRandomizedEqualityComparer(comparer); + // Resize(entries.Length, true); + //} + } + + private void Initialize(int capacity) + { + int prime = PrimeHelper.GetPrime(capacity); + + _Buckets = new int[prime]; + for (int i = 0; i < _Buckets.Length; i++) + _Buckets[i] = -1; + + _Keys = new TKey[prime]; + _Values = new TValue[prime]; + _HashCodes = new int[prime]; + _Next = new int[prime]; + + _FreeList = -1; + } + + private int FindIndex(TKey key) + { + if (key == null) + throw new ArgumentNullException("key"); + + if (_Buckets != null) + { + int hash = _Comparer.GetHashCode(key) & 2147483647; + for (int i = _Buckets[hash % _Buckets.Length]; i >= 0; i = _Next[i]) + { + if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key)) + return i; + } + } + return -1; + } + + public bool TryGetValue(TKey key, out TValue value) + { + int index = FindIndex(key); + if (index >= 0) + { + value = _Values[index]; + return true; + } + value = default(TValue); + return false; + } + + private static class PrimeHelper + { + public static readonly int[] Primes = new int[] + { + 3, + 7, + 11, + 17, + 23, + 29, + 37, + 47, + 59, + 71, + 89, + 107, + 131, + 163, + 197, + 239, + 293, + 353, + 431, + 521, + 631, + 761, + 919, + 1103, + 1327, + 1597, + 1931, + 2333, + 2801, + 3371, + 4049, + 4861, + 5839, + 7013, + 8419, + 10103, + 12143, + 14591, + 17519, + 21023, + 25229, + 30293, + 36353, + 43627, + 52361, + 62851, + 75431, + 90523, + 108631, + 130363, + 156437, + 187751, + 225307, + 270371, + 324449, + 389357, + 467237, + 560689, + 672827, + 807403, + 968897, + 1162687, + 1395263, + 1674319, + 2009191, + 2411033, + 2893249, + 3471899, + 4166287, + 4999559, + 5999471, + 7199369 + }; + + public static bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) + { + int num = (int)Math.Sqrt((double)candidate); + for (int i = 3; i <= num; i += 2) + { + if (candidate % i == 0) + { + return false; + } + } + return true; + } + return candidate == 2; + } + + public static int GetPrime(int min) + { + if (min < 0) + throw new ArgumentException("min < 0"); + + for (int i = 0; i < PrimeHelper.Primes.Length; i++) + { + int prime = PrimeHelper.Primes[i]; + if (prime >= min) + return prime; + } + for (int i = min | 1; i < 2147483647; i += 2) + { + if (PrimeHelper.IsPrime(i) && (i - 1) % 101 != 0) + return i; + } + return min; + } + + public static int ExpandPrime(int oldSize) + { + int num = 2 * oldSize; + if (num > 2146435069 && 2146435069 > oldSize) + { + return 2146435069; + } + return PrimeHelper.GetPrime(num); + } + } + + public ICollection Keys + { + get { return _Keys.Take(Count).ToArray(); } + } + + public ICollection Values + { + get { return _Values.Take(Count).ToArray(); } + } + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public bool Contains(KeyValuePair item) + { + int index = FindIndex(item.Key); + return index >= 0 && + EqualityComparer.Default.Equals(_Values[index], item.Value); + } + + public void CopyTo(KeyValuePair[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + + if (index < 0 || index > array.Length) + throw new ArgumentOutOfRangeException(string.Format("index = {0} array.Length = {1}", index, array.Length)); + + if (array.Length - index < Count) + throw new ArgumentException(string.Format("The number of elements in the dictionary ({0}) is greater than the available space from index to the end of the destination array {1}.", Count, array.Length)); + + for (int i = 0; i < _Count; i++) + { + if (_HashCodes[i] >= 0) + array[index++] = new KeyValuePair(_Keys[i], _Values[i]); + } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + public Enumerator GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator> + { + private readonly SerializableDictionary _Dictionary; + private int _Version; + private int _Index; + private KeyValuePair _Current; + + public KeyValuePair Current + { + get { return _Current; } + } + + internal Enumerator(SerializableDictionary dictionary) + { + _Dictionary = dictionary; + _Version = dictionary._Version; + _Current = default(KeyValuePair); + _Index = 0; + } + + public bool MoveNext() + { + if (_Version != _Dictionary._Version) + throw new InvalidOperationException(string.Format("Enumerator version {0} != Dictionary version {1}", _Version, _Dictionary._Version)); + + while (_Index < _Dictionary._Count) + { + if (_Dictionary._HashCodes[_Index] >= 0) + { + _Current = new KeyValuePair(_Dictionary._Keys[_Index], _Dictionary._Values[_Index]); + _Index++; + return true; + } + _Index++; + } + + _Index = _Dictionary._Count + 1; + _Current = default(KeyValuePair); + return false; + } + + void IEnumerator.Reset() + { + if (_Version != _Dictionary._Version) + throw new InvalidOperationException(string.Format("Enumerator version {0} != Dictionary version {1}", _Version, _Dictionary._Version)); + + _Index = 0; + _Current = default(KeyValuePair); + } + + object IEnumerator.Current + { + get { return Current; } + } + + public void Dispose() + { + } + } +} + +} \ No newline at end of file diff --git a/Editor/Generic/SerializableDictionary.cs.meta b/Editor/Generic/SerializableDictionary.cs.meta new file mode 100644 index 0000000..adde708 --- /dev/null +++ b/Editor/Generic/SerializableDictionary.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b4bbb6cd17816144bb10941e53b3bb28 +timeCreated: 1463230041 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Notifications.meta b/Editor/Notifications.meta new file mode 100644 index 0000000..8295353 --- /dev/null +++ b/Editor/Notifications.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 342553220c58f184cb1a9b72e03b481f +folderAsset: yes +timeCreated: 1483498280 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Notifications/BuildNotification.cs b/Editor/Notifications/BuildNotification.cs new file mode 100644 index 0000000..6097234 --- /dev/null +++ b/Editor/Notifications/BuildNotification.cs @@ -0,0 +1,33 @@ + +namespace SuperSystems.UnityBuild +{ + +[System.Serializable] +public class BuildNotification +{ + public enum Category + { + Notification, + Warning, + Error + } + + public delegate bool ValidityCheck(); + + public Category cat; + public string title; + public string details; + public bool clearable; + public ValidityCheck valid; + + public BuildNotification(Category cat = Category.Notification, string title = null, string details = null, bool clearable = true, ValidityCheck valid = null) + { + this.cat = cat; + this.title = title; + this.details = details; + this.clearable = clearable; + this.valid = valid; + } +} + +} \ No newline at end of file diff --git a/Editor/Notifications/BuildNotification.cs.meta b/Editor/Notifications/BuildNotification.cs.meta new file mode 100644 index 0000000..7e7b82d --- /dev/null +++ b/Editor/Notifications/BuildNotification.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bd48c64bc0b5bd340a40018aeca6c8a2 +timeCreated: 1483498280 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Notifications/BuildNotificationList.cs b/Editor/Notifications/BuildNotificationList.cs new file mode 100644 index 0000000..5f0b1c4 --- /dev/null +++ b/Editor/Notifications/BuildNotificationList.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; + +namespace SuperSystems.UnityBuild +{ + +[Serializable] +public class BuildNotificationList +{ + #region Singleton + + private static BuildNotificationList _instance; + + public static BuildNotificationList instance + { + get + { + if (_instance == null) + _instance = new BuildNotificationList(); + + return _instance; + } + } + + #endregion + + public List notifications = new List(); + public List warnings = new List(); + public List errors = new List(); + + public BuildNotificationList() + { + } + + public void AddNotification(BuildNotification notification) + { + BuildNotification entry = null; + switch (notification.cat) + { + case BuildNotification.Category.Error: + entry = FindDuplicate(notification, errors); + if (entry == null) + { + errors.Add(notification); + } + else if (entry.valid == null && notification.valid != null) + { + entry.valid = notification.valid; + } + break; + case BuildNotification.Category.Warning: + entry = FindDuplicate(notification, warnings); + if (entry == null) + { + warnings.Add(notification); + } + else if (entry.valid == null && notification.valid != null) + { + entry.valid = notification.valid; + } + break; + case BuildNotification.Category.Notification: + entry = FindDuplicate(notification, notifications); + if (entry == null) + { + notifications.Add(notification); + } + else if (entry.valid == null && notification.valid != null) + { + entry.valid = notification.valid; + } + break; + } + } + + public void RefreshAll() + { + RefreshList(notifications); + RefreshList(warnings); + RefreshList(errors); + } + + public void RefreshErrors() + { + RefreshList(errors); + } + + public void RefreshWarnings() + { + RefreshList(warnings); + } + + public void RefreshNotifications() + { + RefreshList(notifications); + } + + public void Remove(BuildNotification notification) + { + BuildNotification entry = null; + switch (notification.cat) + { + case BuildNotification.Category.Error: + entry = FindDuplicate(notification, errors); + if (entry != null) + errors.Remove(entry); + break; + case BuildNotification.Category.Warning: + entry = FindDuplicate(notification, warnings); + if (entry != null) + warnings.Remove(entry); + break; + case BuildNotification.Category.Notification: + entry = FindDuplicate(notification, notifications); + if (entry != null) + notifications.Remove(entry); + break; + } + } + + public void InitializeErrors() + { + AddNotification(new BuildNotification( + BuildNotification.Category.Error, + "No ReleaseType Found", + "At least one ReleaseType is required to perform a build.", + false, + () => BuildSettings.releaseTypeList.releaseTypes.Length == 0)); + + AddNotification(new BuildNotification( + BuildNotification.Category.Error, + "No Build Platform Found", + "At least one Build Platform with one enabled Architecture is required to perform a build.", + false, + () => + { + bool validError = true; + + int platformCount = BuildSettings.platformList.platforms.Length; + if (platformCount > 0) + { + for (int i = 0; i < platformCount; i++) + { + BuildPlatform platform = BuildSettings.platformList.platforms[i]; + if (platform.enabled && platform.atLeastOneArch) + { + validError = false; + break; + } + } + } + + return validError; + })); + + AddNotification(new BuildNotification( + BuildNotification.Category.Error, + "Invalid ReleaseType Name", + "One or more ReleaseType names is invalid. They may not be empty or '" + BuildConstantsGenerator.NONE + "'.", + false, + () => + { + bool validError = false; + + int count = BuildSettings.releaseTypeList.releaseTypes.Length; + for (int i = 0; i < count; i++) + { + string typeName = BuildSettings.releaseTypeList.releaseTypes[i].typeName.Trim(); + if (string.IsNullOrEmpty(typeName) || + typeName.Equals(BuildConstantsGenerator.NONE, StringComparison.OrdinalIgnoreCase)) + { + validError = true; + break; + } + } + + return validError; + })); + + AddNotification(new BuildNotification( + BuildNotification.Category.Error, + "Invalid Distribution Name", + "One or more Distribution names is invalid. They may not be empty or '" + BuildConstantsGenerator.NONE + "'.", + false, + () => + { + bool validError = false; + + int platformCount = BuildSettings.platformList.platforms.Length; + for (int i = 0; i < platformCount; i++) + { + BuildPlatform platform = BuildSettings.platformList.platforms[i]; + int distroCount = platform.distributionList.distributions.Length; + for (int j = 0; j < distroCount; j++) + { + string distributionName = platform.distributionList.distributions[j].distributionName.Trim(); + if (string.IsNullOrEmpty(distributionName) || + distributionName.Equals(BuildConstantsGenerator.NONE, StringComparison.OrdinalIgnoreCase)) + { + validError = true; + break; + } + } + } + + return validError; + })); + } + + private BuildNotification FindDuplicate(BuildNotification notification, List list) + { + BuildNotification duplicate = null; + for (int i = 0; i < list.Count; i++) + { + if (list[i].title.Equals(notification.title) && list[i].details.Equals(notification.details)) + { + duplicate = list[i]; + break; + } + } + + return duplicate; + } + + private void RefreshList(List buildNotifications) + { + for (int i = 0; i < buildNotifications.Count; i++) + { + BuildNotification note = buildNotifications[i]; + if (note.clearable) + { + buildNotifications.RemoveAt(i); + --i; + } + } + } +} + +} \ No newline at end of file diff --git a/Editor/Notifications/BuildNotificationList.cs.meta b/Editor/Notifications/BuildNotificationList.cs.meta new file mode 100644 index 0000000..731cc4d --- /dev/null +++ b/Editor/Notifications/BuildNotificationList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d0f390701f40de04dbdedf10645226e5 +timeCreated: 1483498280 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Notifications/UI.meta b/Editor/Notifications/UI.meta new file mode 100644 index 0000000..51d31d8 --- /dev/null +++ b/Editor/Notifications/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d4c2139e937dd7743bba9e34d056a9ce +folderAsset: yes +timeCreated: 1483499316 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Notifications/UI/BuildNotificationListDrawer.cs b/Editor/Notifications/UI/BuildNotificationListDrawer.cs new file mode 100644 index 0000000..1c1c731 --- /dev/null +++ b/Editor/Notifications/UI/BuildNotificationListDrawer.cs @@ -0,0 +1,189 @@ +using UnityEditor; +using UnityEngine; + +namespace SuperSystems.UnityBuild +{ + +[CustomPropertyDrawer(typeof(BuildNotificationList))] +public class BuildNotificationListDrawer : PropertyDrawer +{ + private bool show = true; + + private SerializedProperty errorList; + private SerializedProperty warningList; + private SerializedProperty notificationsList; + + private GUIContent clearButtonContent = new GUIContent("X", "Clear"); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + DrawErrors(); + DrawWarnings(); + DrawNotifications(); + + EditorGUI.EndProperty(); + } + + private void DrawErrors() + { + int errorCount = 0; + int clearableCount = 0; + for (int i = 0; i < BuildNotificationList.instance.errors.Count; i++) + { + BuildNotification notification = BuildNotificationList.instance.errors[i]; + + if (notification.valid == null || notification.valid()) + ++errorCount; + if (notification.clearable) + ++clearableCount; + } + + if (errorCount == 0) + return; + + Color defaultBackgroundColor = GUI.backgroundColor; + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = Color.red; + UnityBuildGUIUtility.DropdownHeader( + "Errors (" + errorCount + ")", + ref show, true, + GUILayout.ExpandWidth(true)); + + if (clearableCount > 0) + { + if (GUILayout.Button(clearButtonContent, UnityBuildGUIUtility.helpButtonStyle)) + { + BuildNotificationList.instance.RefreshErrors(); + } + } + + GUI.backgroundColor = defaultBackgroundColor; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = 0; i < BuildNotificationList.instance.errors.Count; i++) + { + BuildNotification notification = BuildNotificationList.instance.errors[i]; + + if (notification.valid == null || notification.valid()) + EditorGUILayout.HelpBox(notification.title + "\n" + notification.details, MessageType.Error); + } + + EditorGUILayout.EndVertical(); + } + } + + private void DrawWarnings() + { + int warningCount = 0; + int clearableCount = 0; + for (int i = 0; i < BuildNotificationList.instance.warnings.Count; i++) + { + BuildNotification notification = BuildNotificationList.instance.warnings[i]; + + if (notification.valid == null || notification.valid()) + ++warningCount; + if (notification.clearable) + ++clearableCount; + } + + if (warningCount == 0) + return; + + Color defaultBackgroundColor = GUI.backgroundColor; + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = Color.yellow; + UnityBuildGUIUtility.DropdownHeader( + "Warnings (" + warningCount + ")", + ref show, true, + GUILayout.ExpandWidth(true)); + + if (clearableCount > 0) + { + if (GUILayout.Button(clearButtonContent, UnityBuildGUIUtility.helpButtonStyle)) + { + BuildNotificationList.instance.RefreshWarnings(); + } + } + + GUI.backgroundColor = defaultBackgroundColor; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = 0; i < BuildNotificationList.instance.warnings.Count; i++) + { + BuildNotification notification = BuildNotificationList.instance.warnings[i]; + + if (notification.valid == null || notification.valid()) + EditorGUILayout.HelpBox(notification.title + "\n" + notification.details, MessageType.Warning); + } + + EditorGUILayout.EndVertical(); + } + } + + private void DrawNotifications() + { + int warningCount = 0; + int clearableCount = 0; + for (int i = 0; i < BuildNotificationList.instance.notifications.Count; i++) + { + BuildNotification notification = BuildNotificationList.instance.notifications[i]; + + if (notification.valid == null || notification.valid()) + ++warningCount; + if (notification.clearable) + ++clearableCount; + } + + if (warningCount == 0) + return; + + Color defaultBackgroundColor = GUI.backgroundColor; + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = Color.cyan; + UnityBuildGUIUtility.DropdownHeader( + "Log (" + warningCount + ")", + ref show, true, + GUILayout.ExpandWidth(true)); + + if (clearableCount > 0) + { + if (GUILayout.Button(clearButtonContent, UnityBuildGUIUtility.helpButtonStyle)) + { + BuildNotificationList.instance.RefreshNotifications(); + } + } + + GUI.backgroundColor = defaultBackgroundColor; + EditorGUILayout.EndHorizontal(); + + if (show) + { + EditorGUILayout.BeginVertical(UnityBuildGUIUtility.dropdownContentStyle); + + for (int i = BuildNotificationList.instance.notifications.Count - 1; i >= 0 ; i--) + { + BuildNotification notification = BuildNotificationList.instance.notifications[i]; + + if (notification.valid == null || notification.valid()) + EditorGUILayout.HelpBox(notification.title + "\n" + notification.details, MessageType.None); + } + + EditorGUILayout.EndVertical(); + } + } +} + +} \ No newline at end of file diff --git a/Editor/Notifications/UI/BuildNotificationListDrawer.cs.meta b/Editor/Notifications/UI/BuildNotificationListDrawer.cs.meta new file mode 100644 index 0000000..60524b4 --- /dev/null +++ b/Editor/Notifications/UI/BuildNotificationListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8e2d4912aae4c884899bbfd62c7a628f +timeCreated: 1483499316 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Upload/UploadItch.cs b/Editor/Upload/UploadItch.cs deleted file mode 100644 index 6d9940c..0000000 --- a/Editor/Upload/UploadItch.cs +++ /dev/null @@ -1,135 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.IO; - -namespace UnityBuild -{ - -public class UploadItch : PostBuildAction -{ - private const string WINDOWS = "windows"; - private const string OSX = "osx"; - private const string LINUX = "linux"; - - #region MenuItems - - [MenuItem("Build/Upload/itch.io/Execute", false, 50)] - private static void UploadAll() - { - for (int i = 0; i < BuildProject.platforms.Count; i++) - { - BuildPlatform platform = BuildProject.platforms[i]; - PerformUpload(platform); - } - } - - [MenuItem("Build/Upload/itch.io/Auto Upload")] - private static void ToggleAutoUpload() - { - EditorPrefs.SetBool("buildUploadItchAuto", !EditorPrefs.GetBool("buildUploadItchAuto", false)); - } - - [MenuItem("Build/Upload/itch.io/Auto Upload", true)] - private static bool ToggleAutoUploadValidate() - { - Menu.SetChecked("Build/Upload/itch.io/Auto Upload", EditorPrefs.GetBool("buildUploadItchAuto", false)); - return true; - } - - #endregion - - #region Public Methods - - public override void Execute(BuildPlatform platform) - { - if (EditorPrefs.GetBool("buildUploadItchAuto", false)) - PerformUpload(platform); - } - - #endregion - - #region Private Methods - - private static void PerformUpload(BuildPlatform platform) - { - if (!platform.buildEnabled) - return; - - string absolutePath = Path.GetFullPath(platform.buildPath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - - if (File.Exists(absolutePath)) - { - Debug.Log("UploadItch: Upload Failed - Build does not exist for platform " + platform.name + " - " + absolutePath); - return; - } - - string channel = GetChannelName(platform.target); - if (string.IsNullOrEmpty(channel)) - { - Debug.Log("UploadItch: Upload Failed - Unknown platform " + platform.name); - return; - } - - string arguments = "push \"" + absolutePath + "\" " + UploadItchSettings.itchUserName + "/" + UploadItchSettings.itchGameName + ":" + channel; - - if (!string.IsNullOrEmpty(UploadItchSettings.versionNumber)) - { - arguments += "--userversion " + UploadItchSettings.versionNumber; - } - - System.Diagnostics.Process uploadProc = new System.Diagnostics.Process(); - uploadProc.StartInfo.FileName = UploadItchSettings.butlerPath; - uploadProc.StartInfo.Arguments = - arguments; - uploadProc.StartInfo.CreateNoWindow = false; - uploadProc.StartInfo.UseShellExecute = false; - uploadProc.Start(); - } - - private static string GetChannelName(BuildTarget target) - { - switch (target) - { - // Windows - case BuildTarget.StandaloneWindows: - return WINDOWS + "-x86"; - case BuildTarget.StandaloneWindows64: - return WINDOWS + "-x64"; - - // Linux - case BuildTarget.StandaloneLinux: - return LINUX + "-x86"; - case BuildTarget.StandaloneLinux64: - return LINUX + "-x64"; - case BuildTarget.StandaloneLinuxUniversal: - return LINUX + "-universal"; - - // OSX - case BuildTarget.StandaloneOSXIntel: - return OSX + "-intel"; - case BuildTarget.StandaloneOSXIntel64: - return OSX + "-intel64"; - case BuildTarget.StandaloneOSXUniversal: - return OSX + "-universal"; - - default: - return null; - } - } - - #endregion - - #region Public Properties - - public override int priority - { - get - { - return 1000; - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Upload/UploadItch.cs.meta b/Editor/Upload/UploadItch.cs.meta deleted file mode 100644 index 4d49550..0000000 --- a/Editor/Upload/UploadItch.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 97d88f7d353534a4fbdeb11196057db7 -timeCreated: 1461244919 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Upload/UploadItchSettings.cs b/Editor/Upload/UploadItchSettings.cs deleted file mode 100644 index 8057867..0000000 --- a/Editor/Upload/UploadItchSettings.cs +++ /dev/null @@ -1,111 +0,0 @@ -using UnityEngine; -using UnityEditor; - -namespace UnityBuild -{ - -public class UploadItchSettings : BaseSettings -{ - #region Singleton - - private static UploadItchSettings instance = null; - - public static UploadItchSettings Instance - { - get - { - if (instance == null) - { - instance = CreateAsset("UploadItchSettings"); - } - - return instance; - } - } - - public UploadItchSettings() - { -#if UNITY_EDITOR_WIN - _butlerPath = @"C:\game-dev\butler.exe"; -#elif UNITY_EDITOR_OSX - _butlerPath = @"/Users/username/game-dev/butler"; -#endif - } - - #endregion - - #region MenuItems - - [MenuItem("Build/Upload/itch.io/Edit Settings", priority = 0)] - public static void EditSettings() - { - Selection.activeObject = Instance; - EditorApplication.ExecuteMenuItem("Window/Inspector"); - } - - #endregion - - #region Variables - - [Header("Itch.io Upload Settings (Field Info in Tooltips)")] - - [SerializeField] - [Tooltip("Path to butler executable.")] - private string _butlerPath = ""; - - [SerializeField] - [Tooltip("itch.io username.")] - private string _itchUserName = "username"; - - [SerializeField] - [Tooltip("itch.io project name.")] - private string _itchGameName = "project"; - - [SerializeField] - [Tooltip("Upload version number (optional).")] - private string _versionNumber = ""; - - #endregion - - #region Public Properties - - public static string versionNumber - { - get - { - return Instance._versionNumber; - } - set - { - Instance._versionNumber = value; - } - } - - public static string butlerPath - { - get - { - return Instance._butlerPath; - } - } - - public static string itchUserName - { - get - { - return Instance._itchUserName; - } - } - - public static string itchGameName - { - get - { - return Instance._itchGameName; - } - } - - #endregion -} - -} \ No newline at end of file diff --git a/Editor/Upload/UploadItchSettings.cs.meta b/Editor/Upload/UploadItchSettings.cs.meta deleted file mode 100644 index 425ba5d..0000000 --- a/Editor/Upload/UploadItchSettings.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 438393e651c4f1542a0219910e455f7b -timeCreated: 1462337906 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/adjectives.txt b/Editor/adjectives.txt new file mode 100644 index 0000000..1e87152 --- /dev/null +++ b/Editor/adjectives.txt @@ -0,0 +1,1501 @@ +abandoned +able +absolute +academic +acceptable +acclaimed +accomplished +accurate +aching +acidic +acrobatic +adorable +adventurous +babyish +back +bad +baggy +bare +barren +basic +beautiful +belated +beloved +calculating +calm +candid +canine +capital +carefree +careful +careless +caring +cautious +cavernous +celebrated +charming +damaged +damp +dangerous +dapper +daring +dark +darling +dazzling +dead +deadly +deafening +dear +dearest +each +eager +early +earnest +easy +easygoing +ecstatic +edible +educated +fabulous +failing +faint +fair +faithful +fake +familiar +famous +fancy +fantastic +far +faraway +farflung +faroff +gargantuan +gaseous +general +generous +gentle +genuine +giant +giddy +gigantic +hairy +half +handmade +handsome +handy +happy +happygolucky +hard +icky +icy +ideal +idealistic +identical +idiotic +idle +idolized +ignorant +ill +illegal +jaded +jagged +jampacked +kaleidoscopic +keen +lame +lanky +large +last +lasting +late +lavish +lawful +mad +madeup +magnificent +majestic +major +male +mammoth +married +marvelous +naive +narrow +nasty +natural +naughty +obedient +obese +oblong +oblong +obvious +occasional +oily +palatable +pale +paltry +parallel +parched +partial +passionate +past +pastel +peaceful +peppery +perfect +perfumed +quaint +qualified +radiant +ragged +rapid +rare +rash +raw +recent +reckless +rectangular +sad +safe +salty +same +sandy +sane +sarcastic +sardonic +satisfied +scaly +scarce +scared +scary +scented +scholarly +scientific +scornful +scratchy +scrawny +second +secondary +secondhand +secret +selfassured +selfish +selfreliant +sentimental +talkative +tall +tame +tan +tangible +tart +tasty +tattered +taut +tedious +teeming +ugly +ultimate +unacceptable +unaware +uncomfortable +uncommon +unconscious +understated +unequaled +vacant +vague +vain +valid +wan +warlike +warm +warmhearted +warped +wary +wasteful +watchful +waterlogged +watery +wavy +yawning +yearly +zany +false +active +actual +adept +admirable +admired +adolescent +adorable +adored +advanced +affectionate +afraid +aged +aggravating +beneficial +best +better +bewitched +big +bighearted +biodegradable +bitesized +bitter +black +cheap +cheerful +cheery +chief +chilly +chubby +circular +classic +clean +clear +clearcut +clever +close +closed +decent +decimal +decisive +deep +defenseless +defensive +defiant +deficient +definite +definitive +delayed +delectable +delicious +elaborate +elastic +elated +elderly +electric +elegant +elementary +elliptical +embarrassed +fast +fat +fatal +fatherly +favorable +favorite +fearful +fearless +feisty +feline +female +feminine +few +fickle +gifted +giving +glamorous +glaring +glass +gleaming +gleeful +glistening +glittering +hardtofind +harmful +harmless +harmonious +harsh +hasty +hateful +haunting +illfated +illinformed +illiterate +illustrious +imaginary +imaginative +immaculate +immaterial +immediate +immense +impassioned +jaunty +jealous +jittery +key +kind +lazy +leading +leafy +lean +left +legal +legitimate +light +masculine +massive +mature +meager +mealy +mean +measly +meaty +medical +mediocre +nautical +near +neat +necessary +needy +odd +oddball +offbeat +offensive +official +old +periodic +perky +personal +pertinent +pesky +pessimistic +petty +phony +physical +piercing +pink +pitiful +plain +quarrelsome +quarterly +ready +real +realistic +reasonable +red +reflecting +regal +regular +separate +serene +serious +serpentine +several +severe +shabby +shadowy +shady +shallow +shameful +shameless +sharp +shimmering +shiny +shocked +shocking +shoddy +short +shortterm +showy +shrill +shy +sick +silent +silky +tempting +tender +tense +tepid +terrible +terrific +testy +thankful +that +these +uneven +unfinished +unfit +unfolded +unfortunate +unhappy +unhealthy +uniform +unimportant +unique +valuable +vapid +variable +vast +velvety +weak +wealthy +weary +webbed +wee +weekly +weepy +weighty +weird +welcome +welldocumented +yellow +zealous +aggressive +agile +agitated +agonizing +agreeable +ajar +alarmed +alarming +alert +alienated +alive +all +altruistic +blackandwhite +bland +blank +blaring +bleak +blind +blissful +blond +blue +blushing +cloudy +clueless +clumsy +cluttered +coarse +cold +colorful +colorless +colossal +comfortable +common +compassionate +competent +complete +delightful +delirious +demanding +dense +dental +dependable +dependent +descriptive +deserted +detailed +determined +devoted +different +embellished +eminent +emotional +empty +enchanted +enchanting +energetic +enlightened +enormous +filthy +fine +finished +firm +first +firsthand +fitting +fixed +flaky +flamboyant +flashy +flat +flawed +flawless +flickering +gloomy +glorious +glossy +glum +golden +good +goodnatured +gorgeous +graceful +healthy +heartfelt +hearty +heavenly +heavy +hefty +helpful +helpless +impartial +impeccable +imperfect +imperturbable +impish +impolite +important +impossible +impractical +impressionable +impressive +improbable +joint +jolly +jovial +kindhearted +kindly +lighthearted +likable +likely +limited +limp +limping +linear +lined +liquid +medium +meek +mellow +melodic +memorable +menacing +merry +messy +metallic +mild +negative +neglected +negligible +neighboring +nervous +new +oldfashioned +only +open +optimal +optimistic +opulent +plaintive +plastic +playful +pleasant +pleased +pleasing +plump +plush +pointed +pointless +poised +polished +polite +political +queasy +querulous +reliable +relieved +remarkable +remorseful +remote +repentant +required +respectful +responsible +silly +silver +similar +simple +simplistic +sinful +single +sizzling +skeletal +skinny +sleepy +slight +slim +slimy +slippery +slow +slushy +small +smart +smoggy +smooth +smug +snappy +snarling +sneaky +sniveling +snoopy +thick +thin +third +thirsty +this +thorny +thorough +those +thoughtful +threadbare +united +unkempt +unknown +unlawful +unlined +unlucky +unnatural +unpleasant +unrealistic +venerated +vengeful +verifiable +vibrant +vicious +wellgroomed +wellinformed +welllit +wellmade +welloff +welltodo +wellworn +wet +which +whimsical +whirlwind +whispered +yellowish +zesty +amazing +ambitious +ample +amused +amusing +anchored +ancient +angelic +angry +anguished +animated +annual +another +antique +bogus +boiling +bold +bony +boring +bossy +both +bouncy +bountiful +bowed +complex +complicated +composed +concerned +concrete +confused +conscious +considerate +constant +content +conventional +cooked +cool +cooperative +difficult +digital +diligent +dim +dimpled +dimwitted +direct +disastrous +discrete +disfigured +disgusting +disloyal +dismal +enraged +entire +envious +equal +equatorial +essential +esteemed +ethical +euphoric +flimsy +flippant +flowery +fluffy +fluid +flustered +focused +fond +foolhardy +foolish +forceful +forked +formal +forsaken +gracious +grand +grandiose +granular +grateful +grave +gray +great +greedy +green +hidden +hideous +high +highlevel +hilarious +hoarse +hollow +homely +impure +inborn +incomparable +incompatible +incomplete +inconsequential +incredible +indelible +indolent +inexperienced +infamous +infantile +joyful +joyous +jubilant +klutzy +knobby +little +live +lively +livid +loathsome +lone +lonely +long +milky +mindless +miniature +minor +minty +miserable +miserly +misguided +misty +mixed +next +nice +nifty +nimble +nippy +orange +orderly +ordinary +organic +ornate +ornery +poor +popular +portly +posh +positive +possible +potable +powerful +powerless +practical +precious +present +prestigious +questionable +quick +repulsive +revolving +rewarding +rich +right +rigid +ringed +ripe +sociable +soft +soggy +solid +somber +some +sophisticated +sore +sorrowful +soulful +soupy +sour +spanish +sparkling +sparse +specific +spectacular +speedy +spherical +spicy +spiffy +spirited +spiteful +splendid +spotless +spotted +spry +thrifty +thunderous +tidy +tight +timely +tinted +tiny +tired +torn +total +unripe +unruly +unselfish +unsightly +unsteady +unsung +untidy +untimely +untried +victorious +vigilant +vigorous +villainous +violet +white +whole +whopping +wicked +wide +wideeyed +wiggly +wild +willing +wilted +winding +windy +young +zigzag +anxious +any +apprehensive +appropriate +apt +arctic +arid +aromatic +artistic +ashamed +assured +astonishing +athletic +brave +breakable +brief +bright +brilliant +brisk +broken +bronze +brown +bruised +coordinated +corny +corrupt +costly +courageous +courteous +crafty +crazy +creamy +creative +creepy +criminal +crisp +dirty +disguised +dishonest +dismal +distant +distant +distinct +distorted +dizzy +dopey +downright +dreary +even +evergreen +everlasting +every +evil +exalted +excellent +excitable +exemplary +exhausted +forthright +fortunate +fragrant +frail +frank +frayed +free +french +frequent +fresh +friendly +frightened +frightening +frigid +gregarious +grim +grimy +gripping +grizzled +gross +grotesque +grouchy +grounded +honest +honorable +honored +hopeful +horrible +hospitable +hot +huge +infatuated +inferior +infinite +informal +innocent +insecure +insidious +insignificant +insistent +instructive +insubstantial +judicious +juicy +jumbo +knotty +knowing +knowledgeable +longterm +loose +lopsided +lost +loud +lovable +lovely +loving +modern +modest +moist +monstrous +monthly +monumental +moral +mortified +motherly +motionless +nocturnal +noisy +nonstop +normal +notable +noted +original +other +our +outgoing +outlandish +outlying +precious +pretty +previous +pricey +prickly +primary +prime +pristine +private +prize +probable +productive +profitable +quickwitted +quiet +quintessential +roasted +robust +rosy +rotating +rotten +rough +round +rowdy +square +squeaky +squiggly +stable +staid +stained +stale +standard +starchy +stark +starry +steel +steep +sticky +stiff +stimulating +stingy +stormy +straight +strange +strict +strident +striking +striped +strong +studious +stunning +tough +tragic +trained +traumatic +treasured +tremendous +tremendous +triangular +tricky +trifling +trim +untrue +unused +unusual +unwelcome +unwieldy +unwilling +unwitting +unwritten +upbeat +violent +virtual +virtuous +visible +winged +wiry +wise +witty +wobbly +woeful +wonderful +wooden +woozy +wordy +worldly +worn +youthful +attached +attentive +attractive +austere +authentic +authorized +automatic +avaricious +average +aware +awesome +awful +awkward +bubbly +bulky +bumpy +buoyant +burdensome +burly +bustling +busy +buttery +buzzing +critical +crooked +crowded +cruel +crushing +cuddly +cultivated +cultured +cumbersome +curly +curvy +cute +cylindrical +doting +double +downright +drab +drafty +dramatic +dreary +droopy +dry +dual +dull +dutiful +excited +exciting +exotic +expensive +experienced +expert +extralarge +extraneous +extrasmall +extroverted +frilly +frivolous +frizzy +front +frosty +frozen +frugal +fruitful +full +fumbling +functional +funny +fussy +fuzzy +growing +growling +grown +grubby +gruesome +grumpy +guilty +gullible +gummy +humble +humiliating +humming +humongous +hungry +hurtful +husky +intelligent +intent +intentional +interesting +internal +international +intrepid +ironclad +irresponsible +irritating +itchy +jumpy +junior +juvenile +known +kooky +kosher +low +loyal +lucky +lumbering +luminous +lumpy +lustrous +luxurious +mountainous +muddy +muffled +multicolored +mundane +murky +mushy +musty +muted +mysterious +noteworthy +novel +noxious +numb +nutritious +nutty +onerlooked +outrageous +outstanding +oval +overcooked +overdue +overjoyed +profuse +proper +proud +prudent +punctual +pungent +puny +pure +purple +pushy +putrid +puzzled +puzzling +quirky +quixotic +quizzical +royal +rubbery +ruddy +rude +rundown +runny +rural +rusty +stupendous +stupid +sturdy +stylish +subdued +submissive +substantial +subtle +suburban +sudden +sugary +sunny +super +superb +superficial +superior +supportive +surefooted +surprised +suspicious +svelte +sweaty +sweet +sweltering +swift +sympathetic +trivial +troubled +trusting +trustworthy +trusty +truthful +tubby +turbulent +twin +upright +upset +urban +usable +used +useful +useless +utilized +utter +vital +vivacious +vivid +voluminous +worried +worrisome +worse +worst +worthless +worthwhile +worthy +wrathful +wretched +writhing +wrong +wry +yummy +true +aliceblue +antiquewhite +aqua +aquamarine +azure +beige +bisque +black +blanchedalmond +blue +blueviolet +brown +burlywood +cadetblue +chartreuse +chocolate +coral +cornflowerblue +cornsilk +crimson +cyan +darkblue +darkcyan +darkgoldenrod +darkgray +darkgreen +darkgrey +darkkhaki +darkmagenta +darkolivegreen +darkorange +darkorchid +darkred +darksalmon +darkseagreen +darkslateblue +darkslategray +darkslategrey +darkturquoise +darkviolet +deeppink +deepskyblue +dimgray +dimgrey +dodgerblue +firebrick +floralwhite +forestgreen +fractal +fuchsia +gainsboro +ghostwhite +gold +goldenrod +gray +green +greenyellow +honeydew +hotpink +indianred +indigo +ivory +khaki +lavender +lavenderblush +lawngreen +lemonchiffon +lightblue +lightcoral +lightcyan +lightgoldenrod +lightgoldenrodyellow +lightgray +lightgreen +lightgrey +lightpink +lightsalmon +lightseagreen +lightskyblue +lightslateblue +lightslategray +lightsteelblue +lightyellow +lime +limegreen +linen +magenta +maroon +mediumaquamarine +mediumblue +mediumforestgreen +mediumgoldenrod +mediumorchid +mediumpurple +mediumseagreen +mediumslateblue +mediumspringgreen +mediumturquoise +mediumvioletred +midnightblue +mintcream +mistyrose +moccasin +navajowhite +navy +navyblue +oldlace +olive +olivedrab +opaque +orange +orangered +orchid +palegoldenrod +palegreen +paleturquoise +palevioletred +papayawhip +peachpuff +peru +pink +plum +powderblue +purple +red +rosybrown +royalblue +saddlebrown +salmon +sandybrown +seagreen +seashell +sienna +silver +skyblue +slateblue +slategray +slategrey +snow +springgreen +steelblue +tan +teal +thistle +tomato +transparent +turquoise +violet +violetred +wheat +white +whitesmoke +yellow +yellowgreen \ No newline at end of file diff --git a/Editor/Build/Platform/BuildPlatformTemplate.txt.meta b/Editor/adjectives.txt.meta similarity index 64% rename from Editor/Build/Platform/BuildPlatformTemplate.txt.meta rename to Editor/adjectives.txt.meta index 7e7f2d0..12d88ae 100644 --- a/Editor/Build/Platform/BuildPlatformTemplate.txt.meta +++ b/Editor/adjectives.txt.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 997027e31d480e942a7d92a6b66c49df -timeCreated: 1460734697 +guid: 677f070411e8c014196f129ff45fbaa9 +timeCreated: 1483559909 licenseType: Pro TextScriptImporter: userData: diff --git a/Editor/nouns.txt b/Editor/nouns.txt new file mode 100644 index 0000000..debdc8d --- /dev/null +++ b/Editor/nouns.txt @@ -0,0 +1,2302 @@ +aardvark +abyssinian +accelerator +accordion +account +accountant +acknowledgment +acoustic +acrylic +act +action +active +activity +actor +actress +adapter +addition +address +adjustment +adult +advantage +advertisement +advice +aftermath +afternoon +aftershave +afterthought +age +agenda +agreement +air +airbus +airmail +airplane +airport +airship +alarm +albatross +alcohol +algebra +alibi +alley +alligator +alloy +almanac +alphabet +alto +aluminium +aluminum +ambulance +amount +amusement +anatomy +anethesiologist +anger +angle +animal +anime +ankle +answer +ant +antarctica +anteater +antelope +anthony +anthropology +apartment +apology +apparatus +apparel +appeal +appendix +apple +appliance +approval +april +aquarius +arch +archaeology +archeology +archer +architecture +area +argentina +argument +aries +arithmetic +arm +armadillo +armchair +armenian +army +arrow +art +ash +ashtray +asia +asparagus +asphalt +asterisk +astronomy +athlete +atm +atom +attack +attempt +attention +attic +attraction +august +aunt +australia +australian +author +authorisation +authority +authorization +avenue +babies +baboon +baby +back +backbone +bacon +badge +badger +bag +bagel +bagpipe +bail +bait +baker +bakery +balance +balinese +ball +balloon +bamboo +banana +band +bandana +bangladesh +bangle +banjo +bank +bankbook +banker +bar +barbara +barber +barge +baritone +barometer +base +baseball +basement +basin +basket +basketball +bass +bassoon +bat +bath +bathroom +bathtub +battery +battle +bay +beach +bead +beam +bean +bear +beard +beast +beat +beautician +beauty +beaver +bed +bedroom +bee +beech +beef +beer +beet +beetle +beggar +beginner +begonia +behavior +belief +believe +bell +belt +bench +bengal +beret +berry +bestseller +betty +bibliography +bicycle +bike +bill +billboard +biology +biplane +birch +bird +birth +birthday +bit +bite +black +bladder +blade +blanket +blinker +blizzard +block +blood +blouse +blow +blowgun +blue +board +boat +bobcat +body +bolt +bomb +bomber +bone +bongo +bonsai +book +bookcase +booklet +boot +border +botany +bottle +bottom +boundary +bow +bowl +bowling +box +boy +bra +brace +bracket +brain +brake +branch +brand +brandy +brass +brazil +bread +break +breakfast +breath +brian +brick +bridge +british +broccoli +brochure +broker +bronze +brother +brother-in-law +brow +brown +brush +bubble +bucket +budget +buffer +buffet +bugle +building +bulb +bull +bulldozer +bumper +bun +burglar +burma +burn +burst +bus +bush +business +butane +butcher +butter +button +buzzard +cabbage +cabinet +cable +cactus +cafe +cake +calculator +calculus +calendar +calf +call +camel +camera +camp +can +canada +cancer +candle +cannon +canoe +canvas +cap +capital +cappelletti +capricorn +captain +caption +car +caravan +carbon +card +cardboard +cardigan +care +carnation +carol +carp +carpenter +carriage +carrot +cart +cartoon +case +cast +castanet +cat +catamaran +caterpillar +cathedral +catsup +cattle +cauliflower +cause +caution +cave +c-clamp +cd +ceiling +celery +celeste +cell +cellar +cello +celsius +cement +cemetery +cent +centimeter +century +ceramic +cereal +certification +chain +chair +chalk +chance +change +channel +character +chard +charles +chauffeur +check +cheek +cheese +cheetah +chef +chemistry +cheque +cherries +cherry +chess +chest +chick +chicken +chicory +chief +child +children +chill +chime +chimpanzee +chin +china +chinese +chive +chocolate +chord +christmas +christopher +chronometer +church +cicada +cinema +circle +circulation +cirrus +citizenship +city +clam +clarinet +class +claus +clave +clef +clerk +click +client +climb +clipper +cloakroom +clock +close +closet +cloth +cloud +cloudy +clover +club +clutch +coach +coal +coast +coat +cobweb +cockroach +cocktail +cocoa +cod +coffee +coil +coin +coke +cold +collar +college +collision +colombia +colon +colony +color +colt +column +columnist +comb +comfort +comic +comma +command +commission +committee +community +company +comparison +competition +competitor +composer +composition +computer +condition +condor +cone +confirmation +conga +congo +conifer +connection +consonant +continent +control +cook +cooking +copper +copy +copyright +cord +cork +cormorant +corn +cornet +correspondent +cost +cotton +couch +cougar +cough +country +course +court +cousin +cover +cow +cowbell +crab +crack +cracker +craftsman +crate +crawdad +crayfish +crayon +cream +creator +creature +credit +creditor +creek +crib +cricket +crime +criminal +crocodile +crocus +croissant +crook +crop +cross +crow +crowd +crown +crush +cry +cub +cuban +cucumber +cultivator +cup +cupboard +cupcake +curler +currency +current +curtain +curve +cushion +custard +customer +cut +cuticle +cycle +cyclone +cylinder +cymbal +dad +daffodil +dahlia +daisy +damage +dance +dancer +danger +daniel +dash +dashboard +database +date +daughter +david +day +dead +deadline +deal +death +deborah +debt +debtor +decade +december +decimal +decision +decrease +dedication +deer +defense +deficit +degree +delete +delivery +den +denim +dentist +deodorant +department +deposit +description +desert +design +desire +desk +dessert +destruction +detail +detective +development +dew +diamond +diaphragm +dibble +dictionary +dietician +difference +digestion +digger +digital +dill +dime +dimple +dinghy +dinner +dinosaur +diploma +dipstick +direction +dirt +disadvantage +discovery +discussion +disease +disgust +dish +distance +distribution +distributor +diving +division +dock +doctor +dog +dogsled +doll +dollar +dolphin +domain +donald +donkey +donna +door +dorothy +double +doubt +downtown +dragon +dragonfly +drain +drake +drama +draw +drawbridge +drawer +dream +dredger +dress +dresser +dressing +drill +drink +drive +driver +driving +drizzle +drop +drug +drum +dry +dryer +duck +duckling +dugout +dungeon +dust +eagle +ear +earth +earthquake +ease +east +edge +edger +editor +editorial +education +edward +eel +effect +egg +eggnog +eggplant +egypt +eight +elbow +element +elephant +elizabeth +ellipse +emery +employee +employer +encyclopedia +end +enemy +energy +engine +engineer +engineering +english +enquiry +entrance +environment +epoch +epoxy +equinox +equipment +era +error +estimate +ethernet +euphonium +evening +event +examination +example +exchange +exclamation +exhaust +ex-husband +existence +expansion +experience +expert +explanation +ex-wife +eye +eyebrow +eyelash +eyeliner +face +facilities +fact +factory +fahrenheit +fairies +fall +family +fan +fang +farm +farmer +fat +father +father-in-law +faucet +fear +feast +feather +feature +february +fedelini +feedback +feeling +feet +felony +female +fender +ferry +ferryboat +fertilizer +fiber +fiberglass +fibre +fiction +field +fifth +fight +fighter +file +find +fine +finger +fir +fire +fireman +fireplace +firewall +fish +fisherman +flag +flame +flare +flat +flavor +flax +flesh +flight +flock +flood +floor +flower +flugelhorn +flute +fly +foam +fog +fold +font +food +foot +football +footnote +force +forecast +forehead +forest +forgery +fork +form +format +fortnight +foundation +fountain +fowl +fox +foxglove +fragrance +frame +france +freckle +freeze +freezer +freighter +french +freon +friction +friday +fridge +friend +frog +front +frost +frown +fruit +fuel +fur +furniture +galley +gallon +game +gander +garage +garden +garlic +gas +gasoline +gate +gateway +gauge +gazelle +gear +gearshift +geese +gemini +gender +geography +geology +geometry +george +geranium +german +germany +ghana +ghost +giant +giraffe +girdle +girl +gladiolus +glass +glider +gliding +glockenspiel +glove +glue +goal +goat +gold +goldfish +golf +gondola +gong +good-bye +goose +gorilla +gosling +government +governor +grade +grain +gram +granddaughter +grandfather +grandmother +grandson +grape +graphic +grass +grasshopper +gray +grease +great-grandfather +great-grandmother +greece +greek +green +grenade +grey +grill +grip +ground +group +grouse +growth +guarantee +guatemalan +guide +guilty +guitar +gum +gun +gym +gymnast +hacksaw +hail +hair +haircut +half-brother +half-sister +halibut +hall +hallway +hamburger +hammer +hamster +hand +handball +handicap +handle +handsaw +harbor +hardboard +hardcover +hardhat +hardware +harmonica +harmony +harp +hat +hate +hawk +head +headlight +headline +health +hearing +heart +heat +heaven +hedge +height +helen +helicopter +helium +hell +helmet +help +hemp +hen +heron +herring +hexagon +hill +himalayan +hip +hippopotamus +history +hobbies +hockey +hoe +hole +holiday +home +honey +hood +hook +hope +horn +horse +hose +hospital +hot +hour +hourglass +house +hovercraft +hub +hubcap +humidity +humor +hurricane +hyacinth +hydrant +hydrofoil +hydrogen +hyena +hygienic +ice +icebreaker +icicle +icon +idea +ikebana +illegal +imprisonment +improvement +impulse +inch +income +increase +index +industry +ink +innocent +input +insect +instruction +instrument +insulation +insurance +interactive +interest +internet +interviewer +intestine +invention +inventory +invoice +iris +iron +island +italian +italy +jacket +jaguar +jail +jam +james +january +japanese +jar +jasmine +jason +jaw +jeans +jeep +jeff +jelly +jellyfish +jennifer +jet +jewel +jogging +john +join +joke +joseph +journey +judge +judo +juice +july +jumbo +jump +jumper +june +jury +justice +jute +kale +kamikaze +kangaroo +karate +karen +kayak +kendo +kenneth +kenya +ketchup +kettle +kettledrum +kevin +key +keyboard +keyboarding +kick +kidney +kilogram +kilometer +kimberly +kiss +kitchen +kite +kitten +kitty +knee +knickers +knife +knight +knot +knowledge +kohlrabi +korean +laborer +lace +ladybug +lake +lamb +lamp +lan +land +landmine +language +larch +lasagna +latency +latex +lathe +laugh +laundry +laura +law +lawyer +layer +lead +leaf +learning +leather +leek +leg +legal +lemonade +lentil +leo +leopard +letter +lettuce +level +libra +library +license +lier +lift +light +lightning +lilac +lily +limit +linda +line +linen +link +lion +lip +lipstick +liquid +liquor +lisa +list +literature +litter +liver +lizard +llama +loaf +loan +lobster +lock +locket +locust +look +loss +lotion +love +low +lumber +lunch +lunchroom +lung +lunge +lute +luttuce +lycra +lynx +lyocell +lyre +lyric +macaroni +machine +macrame +magazine +magic +magician +maid +mail +mailbox +mailman +makeup +malaysia +male +mall +mallet +man +manager +mandolin +manicure +manx +map +maple +maraca +marble +march +margaret +margin +maria +marimba +mark +market +mary +mascara +mask +mass +match +math +mattock +may +mayonnaise +meal +measure +meat +mechanic +medicine +meeting +melody +memory +men +menu +mercury +message +metal +meteorology +meter +methane +mexico +mice +michael +michelle +microwave +middle +mile +milk +milkshake +millennium +millimeter +millisecond +mimosa +mind +mine +minibus +mini-skirt +minister +mint +minute +mirror +missile +mist +mistake +mitten +moat +modem +mole +mom +monday +money +monkey +month +moon +morning +morocco +mosque +mosquito +mother +mother-in-law +motion +motorboat +motorcycle +mountain +mouse +moustache +mouth +move +multi-hop +multimedia +muscle +museum +music +musician +mustard +myanmar +nail +name +nancy +napkin +narcissus +nation +neck +need +needle +neon +nepal +nephew +nerve +nest +net +network +news +newsprint +newsstand +nic +nickel +niece +nigeria +night +nitrogen +node +noise +noodle +north +north america +north korea +norwegian +nose +note +notebook +notify +novel +november +number +numeric +nurse +nut +nylon +oak +oatmeal +objective +oboe +observation +occupation +ocean +ocelot +octagon +octave +october +octopus +odometer +offence +offer +office +oil +okra +olive +onion +open +opera +operation +ophthalmologist +opinion +option +orange +orchestra +orchid +order +organ +organisation +organization +ornament +ostrich +otter +ounce +output +outrigger +oval +oven +overcoat +owl +owner +ox +oxygen +oyster +package +packet +page +pail +pain +paint +pair +pajama +pakistan +palm +pamphlet +pan +pancake +pancreas +panda +pansy +panther +panties +pantry +pants +panty +pantyhose +paper +paperback +parade +parallelogram +parcel +parent +parentheses +park +parrot +parsnip +part +particle +partner +partridge +party +passbook +passenger +passive +pasta +paste +pastor +pastry +patch +path +patient +patio +patricia +paul +payment +pea +peace +peak +peanut +pear +pedestrian +pediatrician +peen +peer-to-peer +pelican +pen +penalty +pencil +pendulum +pentagon +peony +pepper +perch +perfume +period +periodical +peripheral +permission +persian +person +peru +pest +pet +pharmacist +pheasant +philippines +philosophy +phone +physician +piano +piccolo +pickle +picture +pie +pig +pigeon +pike +pillow +pilot +pimple +pin +pine +ping +pink +pint +pipe +pisces +pizza +place +plain +plane +planet +plant +plantation +plaster +plasterboard +plastic +plate +platinum +play +playground +playroom +pleasure +plier +plot +plough +plow +plywood +pocket +poet +point +poison +poland +police +policeman +polish +politician +pollution +polo +polyester +pond +popcorn +poppy +population +porch +porcupine +port +porter +position +possibility +postage +postbox +pot +potato +poultry +pound +powder +power +precipitation +preface +pressure +price +priest +print +printer +prison +probation +process +processing +produce +product +production +professor +profit +promotion +propane +property +prose +prosecution +protest +protocol +pruner +psychiatrist +psychology +ptarmigan +puffin +pull +puma +pump +pumpkin +punch +punishment +puppy +purchase +purple +purpose +push +pvc +pyjama +pyramid +quail +quality +quart +quarter +quartz +queen +question +quicksand +quiet +quill +quilt +quince +quit +quiver +quotation +rabbi +rabbit +racing +radar +radiator +radio +radish +raft +rail +railway +rain +rainbow +raincoat +rainstorm +rake +ramie +random +range +rat +rate +raven +ravioli +ray +rayon +reaction +reading +reason +receipt +recess +record +recorder +rectangle +red +reduction +refrigerator +refund +regret +reindeer +relation +relative +religion +relish +reminder +repair +replace +report +representative +request +resolution +respect +responsibility +rest +restaurant +result +retailer +revolve +revolver +reward +rhinoceros +rhythm +rice +richard +riddle +rifle +ring +rise +risk +river +riverbed +road +roadway +roast +robert +robin +rock +rocket +rod +roll +romania +romanian +ronald +roof +room +rooster +root +rose +rotate +route +router +rowboat +rub +rubber +rugby +rule +run +russia +russian +rutabaga +ruth +sack +sagittarius +sail +sailboat +sailor +salad +salary +sale +salesman +salmon +salt +sampan +samurai +sand +sandra +sandwich +santa +sarah +sardine +satin +saturday +sauce +saudi arabia +sausage +save +saw +saxophone +scale +scallion +scanner +scarecrow +scarf +scene +scent +schedule +school +science +scissors +scooter +scorpio +scorpion +scraper +screen +screw +screwdriver +sea +seagull +seal +seaplane +search +seashore +season +seat +second +secretary +secure +security +seed +seeder +segment +select +selection +self +semicircle +semicolon +sense +sentence +september +servant +server +session +sex +shade +shadow +shake +shallot +shame +shampoo +shape +share +shark +sharon +shears +sheep +sheet +shelf +shell +shield +shingle +ship +shirt +shock +shoe +shoemaker +shop +shorts +shoulder +shovel +show +shrimp +shrine +siamese +siberian +side +sideboard +sidecar +sidewalk +sign +signature +silica +silk +silver +sing +singer +single +sink +sister +sister-in-law +size +skate +skiing +skill +skin +skirt +sky +slash +slave +sled +sleep +sleet +slice +slime +slip +slipper +slope +smash +smell +smile +smoke +snail +snake +sneeze +snow +snowboarding +snowflake +snowman +snowplow +snowstorm +soap +soccer +society +sociology +sock +soda +sofa +softball +softdrink +software +soil +soldier +son +song +soprano +sort +sound +soup +sousaphone +south africa +south america +south korea +soy +soybean +space +spade +spaghetti +spain +spandex +spark +sparrow +spear +specialist +speedboat +sphere +sphynx +spider +spike +spinach +spleen +sponge +spoon +spot +spring +sprout +spruce +spy +square +squash +squid +squirrel +stage +staircase +stamp +star +start +starter +state +statement +station +statistic +steam +steel +stem +step +step-brother +stepdaughter +step-daughter +step-father +stepmother +step-mother +step-sister +stepson +step-son +steven +stew +stick +stinger +stitch +stock +stocking +stomach +stone +stool +stop +stopsign +stopwatch +store +storm +story +stove +stranger +straw +stream +street +streetcar +stretch +string +structure +study +sturgeon +submarine +substance +subway +success +sudan +suede +sugar +suggestion +suit +summer +sun +sunday +sundial +sunflower +sunshine +supermarket +supply +support +surfboard +surgeon +surname +surprise +susan +sushi +swallow +swamp +swan +sweater +sweatshirt +sweatshop +swedish +sweets +swim +swimming +swing +swiss +switch +sword +swordfish +sycamore +syria +syrup +system +table +tablecloth +tabletop +tachometer +tadpole +tail +tailor +taiwan +talk +tank +tanker +tanzania +target +taste +taurus +tax +taxi +taxicab +tea +teacher +teaching +team +technician +teeth +television +teller +temper +temperature +temple +tempo +tendency +tennis +tenor +tent +territory +test +text +textbook +texture +thailand +theater +theory +thermometer +thing +thistle +thomas +thought +thread +thrill +throat +throne +thumb +thunder +thunderstorm +thursday +ticket +tie +tiger +tights +tile +timbale +time +timer +timpani +tin +tip +tire +titanium +title +toad +toast +toe +toenail +toilet +tomato +tom-tom +ton +tongue +tooth +toothbrush +toothpaste +top +tornado +tortellini +tortoise +touch +tower +town +toy +tractor +trade +traffic +trail +train +tramp +transaction +transmission +transport +trapezoid +tray +treatment +tree +trial +triangle +trick +trigonometry +trip +trombone +trouble +trousers +trout +trowel +truck +trumpet +trunk +t-shirt +tsunami +tub +tuba +tuesday +tugboat +tulip +tuna +tune +turkey +turkish +turn +turnip +turnover +turret +turtle +tv +twig +twilight +twine +twist +typhoon +tyvek +umbrella +uncle +underclothes +underpants +undershirt +underwear +unit +use +utensil +uzbekistan +vacation +vacuum +valley +value +van +vase +vault +vegetable +vegetarian +veil +vein +velvet +venezuela +venezuelan +verdict +vermicelli +verse +vessel +vest +veterinarian +vibraphone +vietnam +view +vinyl +viola +violet +violin +virgo +viscose +vise +vision +visitor +voice +volcano +volleyball +voyage +vulture +waiter +waitress +walk +wall +wallaby +wallet +walrus +war +warm +wash +washer +wasp +waste +watch +watchmaker +water +waterfall +wave +wax +way +wealth +weapon +weasel +weather +wedge +wednesday +weed +weeder +week +weight +whale +wheel +whip +whiskey +whistle +white +wholesaler +whorl +wilderness +william +willow +wind +windchime +window +windscreen +windshield +wine +wing +winter +wire +wish +witch +withdrawal +witness +wolf +woman +women +wood +wool +woolen +word +work +workshop +worm +wound +wrecker +wren +wrench +wrinkle +wrist +writer +xylophone +yacht +yak +yam +yard +yarn +year +yellow +yew +yogurt +yoke +zebra +zephyr +zinc +zipper +zone +zoo +zoology \ No newline at end of file diff --git a/Editor/nouns.txt.meta b/Editor/nouns.txt.meta new file mode 100644 index 0000000..d5af0e0 --- /dev/null +++ b/Editor/nouns.txt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 69bafc6dca80dca498a5d51a18c85dda +timeCreated: 1483559909 +licenseType: Pro +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.md b/LICENSE.md index 45c7204..ce6ad8c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Super Systems Softworks LLC +Copyright (c) 2017 Super Systems Softworks LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b75ff2c..a48cbc5 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,80 @@ -# UnityBuild -> An expandable and customizable framework for multiplatform builds with Unity. +# SuperUnityBuild +> A powerful automation tool for quickly and easily generating builds of a game with Unity. + +![](https://github.com/Chaser324/unity-build/blob/gh-pages/Unity_2017-01-11_00-38-20.png) + +SuperUnityBuild is a Unity utility that automates the process of generating builds of your game. It's easy and quick enough to use on small games, but it's also powerful and extensible enough to be extremely useful on larger projects. The key to this flexibility lies in SuperUnityBuilds configurable degrees of granularity and its "BuildActions" framework which allows additional operations to be added into the build process. + +Features: +* **Manage and Build Multiple Versions** - If you're targetting more than one platform or distribution storefront, the build process can quickly become very cumbersome with Unity's built in tools. SuperUnityBuild makes it easy to manage a wide array of build configurations targetting any number of versions, platforms, architectures, or distribution methods. +* **One-Click Batch Builds** - Easily kick-off batch builds for all or a specific subset of your build configurations. +* **Expanded Build Capability** - SuperUnityBuild overs many features not available in Unity's built in build workflow such as version number generation, and the BuildAction framework provides options for even more expanded build capabilities like automated file copying/moving, creating zip files, and building AssetBundles. +* **Quick Initial Setup** - If all you need is the bare essentials, you can be up and running in minutes. SuperUnityBuild scales to fit your project's specific needs whether it be large or small. +* **Highly Extensible and Customizable** - SuperUnityBuild's BuildAction framework provides simple hooks for adding in your own additional functionality. +* **Free and Open-Source** - Some similar tools available only on the AssetStore are as much as $50+. + + -The primary goal of this project is to take build scripts that I've already used on some projects and make them slightly more generic, expandable, and customizable. This includes supporting the generation of AssetBundles as well as preparing/uploading builds for services like itch.io and Steam. ## Basic Usage -#### Install -Do one of the following: -* [Download](https://github.com/Chaser324/unity-build/archive/master.zip) this project and copy the `Editor` dirctory into your project's assets directory. -* Make this repository a git submodule within your project's assets directory. +Requires Unity 5.0 or higher. Currently supports Windows, OSX, and Linux builds - more platforms soon once they've been tested more thoroughly. + +### Install + +Either [download the latest released Unity Package][release] and import it into your project OR [download the zip][download] of this repository and extract its contents into your Unity project's Assets directory. + +You may also want to download some of the available BuildAction modules in the [Unity-Build-Actions][unitybuild-actions] repository to expand SuperUnityBuild's capabilities. + +### Basic Setup + +See [Standard Usage](https://github.com/Chaser324/unity-build/wiki/Standard-Usage) in the wiki. -#### Generate Settings -* Click `Build > Edit Settings`. -* If you're using AssetBundles, click `Build > AssetBundles > Edit Settings` to edit the applicable settings. -* If you're using itch.io uploading, click `Build > Upload > itch.io > Edit Settings` to edit the applicable settings. -#### Build -* Click `Build > Run Build` to build the project. You can select which platforms to build in the `Build > Platforms` menu. -## Project Contents -This project is designed to be highly modular, so you can delete any parts you don't need for your project. I may break these out into separate GitHub repositories at some point but for now just delete what you don't need. -* `AssetBundles` - AssetBundle building. Delete this directory if you aren't using AssetBundles or have your own AssetBundle workflow. -* `Build` - The core build functionality. Don't delete this directory. If you don't need a particular platform, you can delete that individual class. -* `Upload` - *TODO* ## Customizing and Expanding -#### Creating a new BuildPlatform. -* Generate a BuildPlatform file by clicking `Build > Generate > BuildPlatform` and selecting an Editor directory within your project. -* Set the constant values. +### Creating BuildPlatforms + +*TODO* + +### Creating BuildActions + +See [Build Actions](https://github.com/Chaser324/unity-build/wiki/Build-Actions) in the wiki for details. + + -#### Creating Pre/Post BuildActions. -Create an editor class that inherits from `PreBuildAction` or `PostBuildAction` and overrides the `Execute` method. You can override the "priority" property to control the order actions execute (lower values runs earlier). ## Command Line Interface -*TODO* +The command line interface is still in development. Feel free to let me know if there's specific functionality you want from this feature. + + + ## Contributing + Bug reports, feature requests, and pull requests are welcome and appreciated. + + + ## Credits + * **Chase Pettit** - [github](https://github.com/Chaser324), [twitter](http://twitter.com/chasepettit) + + + ## License -All code in this repository ([unity-build](https://github.com/Chaser324/unity-build)) is made freely available under the MIT license. +All code in this repository ([unity-build](https://github.com/Chaser324/unity-build)) is made freely available under the MIT license. This essentially means you're free to use it however you like as long as you provide attribution. + + + + +[download]: https://github.com/Chaser324/unity-build/archive/master.zip +[release]: https://github.com/Chaser324/unity-build/releases +[unitybuild]: https://github.com/Chaser324/unity-build +[unitybuild-actions]: https://github.com/Chaser324/unity-build-actions +[unitybuild-wiki]: https://github.com/Chaser324/unity-build/wiki/Build-Actions \ No newline at end of file