From fd94af21022724d94476a44a81bad77777561980 Mon Sep 17 00:00:00 2001 From: Nihav Jain Date: Thu, 4 Mar 2021 22:01:03 -0500 Subject: [PATCH] Add an MPKBuilder script to unity package. (#6) Any Unity project can use this to build mpks for Lumin. Scenes listed and enabled in the editor build settings are added to the mpk, either one scene per mpk or all scenes in one mpk, depending on the cmd line args passed in to Unity. To invoke this script, pass the fully qualified class & func name - '-executeMethod UnityEditor.XR.MagicLeap.MPKBuilder.BuildMPK'. --- .gitignore | 1 + Editor/LuminUnity-Editor.asmdef | 19 +++ Editor/LuminUnity-Editor.asmdef.meta | 7 + Editor/MPKBuilder.cs | 188 +++++++++++++++++++++++++++ Editor/MPKBuilder.cs.meta | 11 ++ 5 files changed, 226 insertions(+) create mode 100644 Editor/LuminUnity-Editor.asmdef create mode 100644 Editor/LuminUnity-Editor.asmdef.meta create mode 100644 Editor/MPKBuilder.cs create mode 100644 Editor/MPKBuilder.cs.meta diff --git a/.gitignore b/.gitignore index 59d5c6e..bc4e226 100644 --- a/.gitignore +++ b/.gitignore @@ -372,3 +372,4 @@ FodyWeavers.xsd # Don't ignore Unity .meta files !Runtime/**/*.meta +!Editor/**/*.meta diff --git a/Editor/LuminUnity-Editor.asmdef b/Editor/LuminUnity-Editor.asmdef new file mode 100644 index 0000000..f6cd05a --- /dev/null +++ b/Editor/LuminUnity-Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "LuminUnity-Editor", + "rootNamespace": "", + "references": [ + "GUID:ec0144320e2ab8c42b9ce084651ff2a1", + "GUID:28d8685fae23c21419ef42894cb9b075" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/LuminUnity-Editor.asmdef.meta b/Editor/LuminUnity-Editor.asmdef.meta new file mode 100644 index 0000000..16a9b0f --- /dev/null +++ b/Editor/LuminUnity-Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11d5768f6c980e14f8d3c5ea315a650c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/MPKBuilder.cs b/Editor/MPKBuilder.cs new file mode 100644 index 0000000..c2ca0f7 --- /dev/null +++ b/Editor/MPKBuilder.cs @@ -0,0 +1,188 @@ +using UnityEngine; +using UnityEditor; +using System.IO; +using System.Collections.Generic; + +namespace UnityEditor.XR.MagicLeap +{ + public class MPKBuilder + { + private static readonly string Arg_Development = "--development"; + private static readonly string Arg_Shipping = "--shipping"; + private static readonly string Arg_OutDir = "--outdir"; + private static readonly string Arg_OneMpkPerScene = "--one-mpk-per-scene"; + private static readonly string Arg_CheckProLicense = "--check-pro-license"; + + private class BuildSettingsCache + { + private string appIdentifier; + private string productName; + private UnityEditor.BuildTargetGroup seletedBuildTargetGroup; + private bool signPackage; + private bool isPackageDebuggable; + + public BuildSettingsCache() + { + appIdentifier = PlayerSettings.applicationIdentifier; + productName = PlayerSettings.productName; + seletedBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; + signPackage = PlayerSettings.Lumin.signPackage; + isPackageDebuggable = UnityEditor.Lumin.UserBuildSettings.isPackageDebuggable; + } + + public void RestoreSettings() + { + PlayerSettings.applicationIdentifier = appIdentifier; + PlayerSettings.productName = productName; + EditorUserBuildSettings.selectedBuildTargetGroup = seletedBuildTargetGroup; + PlayerSettings.Lumin.signPackage = signPackage; + UnityEditor.Lumin.UserBuildSettings.isPackageDebuggable = isPackageDebuggable; + } + + ~BuildSettingsCache() + { + RestoreSettings(); + } + } + + public static void BuildMPK() + { + MPKBuilder mpkBuilder = new MPKBuilder(); + mpkBuilder.Build(); + } + + private void Build() + { + BuildSettingsCache buildSettingsCache = new BuildSettingsCache(); + + try + { + if (IsArgSet(Arg_CheckProLicense) && !UnityEngine.Application.HasProLicense()) + { + throw new System.Exception($"{Arg_CheckProLicense} was passed but Unity Pro License not found!"); + } + + EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Lumin; + PlayerSettings.Lumin.signPackage = true; + UnityEditor.Lumin.UserBuildSettings.isPackageDebuggable = !IsArgSet(Arg_Shipping); + + if (IsArgSet(Arg_OneMpkPerScene)) + { + BuildSceneByScene(); + } + else + { + BuildAllScenes(); + } + } + catch (System.Exception) + { + throw; + } + finally + { + buildSettingsCache.RestoreSettings(); + } + } + + private void BuildAllScenes() + { + List activeScenes = new List(); + EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes; + foreach (EditorBuildSettingsScene scene in scenes) + { + if (!scene.enabled) + { + continue; + } + + activeScenes.Add(scene.path); + } + + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); + buildPlayerOptions.target = BuildTarget.Lumin; + buildPlayerOptions.targetGroup = BuildTargetGroup.Lumin; + buildPlayerOptions.options = GetBuildOptions(); + buildPlayerOptions.scenes = activeScenes.ToArray(); + buildPlayerOptions.locationPathName = System.IO.Path.Combine(GetBuildFolder().FullName, $"{PlayerSettings.applicationIdentifier}.mpk"); + + UnityEditor.Build.Reporting.BuildReport report = UnityEditor.BuildPipeline.BuildPlayer(buildPlayerOptions); + if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Failed) + { + throw new System.Exception($"Building {PlayerSettings.applicationIdentifier} failed."); + } + } + + private void BuildSceneByScene() + { + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); + buildPlayerOptions.target = BuildTarget.Lumin; + buildPlayerOptions.targetGroup = BuildTargetGroup.Lumin; + buildPlayerOptions.options = GetBuildOptions(); + + System.IO.FileInfo buildFolder = GetBuildFolder(); + + string cachedAppIdentifier = PlayerSettings.applicationIdentifier; + + EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes; + foreach (EditorBuildSettingsScene scene in scenes) + { + if (!scene.enabled) + { + continue; + } + + string sceneName = System.IO.Path.GetFileNameWithoutExtension(scene.path); + PlayerSettings.applicationIdentifier = $"{cachedAppIdentifier}.{sceneName.ToLower()}"; + PlayerSettings.productName = sceneName; + buildPlayerOptions.locationPathName = System.IO.Path.Combine(buildFolder.FullName, $"{PlayerSettings.applicationIdentifier}.mpk"); + buildPlayerOptions.scenes = new string[] { scene.path }; + + UnityEditor.Build.Reporting.BuildReport report = UnityEditor.BuildPipeline.BuildPlayer(buildPlayerOptions); + if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Failed) + { + throw new System.Exception($"Building {sceneName} failed."); + } + } + } + + private UnityEditor.BuildOptions GetBuildOptions() + { + UnityEditor.BuildOptions buildOptions = BuildOptions.None; + if (IsArgSet(Arg_Development)) + { + buildOptions |= BuildOptions.Development; + } + + return buildOptions; + } + + private System.IO.FileInfo GetBuildFolder() + { + string outDir = "Build"; + TryGetArgValue(Arg_OutDir, ref outDir); + + System.IO.FileInfo buildFolder = new System.IO.FileInfo(System.IO.Path.Combine(outDir, BuildTarget.Lumin.ToString())); + buildFolder.Directory.Create(); + + return buildFolder; + } + + private bool IsArgSet(string arg) + { + return (System.Array.IndexOf(System.Environment.GetCommandLineArgs(), arg) != -1); + } + + private bool TryGetArgValue(string arg, ref string value) + { + int argIndex = System.Array.IndexOf(System.Environment.GetCommandLineArgs(), arg); + if (argIndex != -1 && argIndex < System.Environment.GetCommandLineArgs().Length - 1) + { + value = System.Environment.GetCommandLineArgs()[argIndex + 1]; + return true; + } + + return false; + } + } +} diff --git a/Editor/MPKBuilder.cs.meta b/Editor/MPKBuilder.cs.meta new file mode 100644 index 0000000..09fb8a5 --- /dev/null +++ b/Editor/MPKBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 202d437036da52c4a9822b52d1925ec1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: