zxl
/
CTT
forked from Cal/CTT
1
0
Fork 0
CTT/Unity/Assets/Editor/XAsset/BuildScript.cs

349 lines
13 KiB
C#

//
// BuildScript.cs
//
// Author:
// fjy <jiyuan.feng@live.com>
//
// Copyright (c) 2020 fjy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace libx
{
public static class BuildScript
{
public static string outputPath = "../Release/" + GetPlatformName();
public static void ClearAssetBundles()
{
string[] allAssetBundleNames = AssetDatabase.GetAllAssetBundleNames();
for (int i = 0; i < allAssetBundleNames.Length; i++)
{
string text = allAssetBundleNames[i];
if (EditorUtility.DisplayCancelableProgressBar(
string.Format("Clear AssetBundles {0}/{1}", i, allAssetBundleNames.Length), text,
i * 1f / allAssetBundleNames.Length))
break;
AssetDatabase.RemoveAssetBundleName(text, true);
}
EditorUtility.ClearProgressBar();
}
internal static void ApplyBuildRules()
{
BuildRules rule = GetBuildRules();
rule.Apply();
}
internal static BuildRules GetBuildRules()
{
return GetAsset<BuildRules>("Assets/Res/Common/Rules.asset");
}
public static void CopyAssetBundlesTo(string path, bool vfs = false)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
var versions = new List<VFile>();
if (!vfs)
{
versions.AddRange(Versions.LoadVersions(outputPath + "/" + Versions.Filename));
versions.Add(new VFile() {name = Versions.Filename});
versions.RemoveAt(versions.FindIndex(file => file.name.Equals(Versions.Dataname)));
}
else
{
versions.Add(new VFile() {name = Versions.Filename});
versions.Add(new VFile() {name = Versions.Dataname});
}
foreach (VFile item in versions)
{
string src = outputPath + "/" + item.name;
string dest = path + "/" + item.name;
if (File.Exists(src))
{
File.Copy(src, dest, true);
}
}
AssetDatabase.Refresh();
}
public static string GetPlatformName()
{
return GetPlatformForAssetBundles(EditorUserBuildSettings.activeBuildTarget);
}
private static string GetPlatformForAssetBundles(BuildTarget target)
{
switch (target)
{
case BuildTarget.Android:
return "Android";
case BuildTarget.iOS:
return "iOS";
case BuildTarget.WebGL:
return "WebGL";
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return "Windows";
#if UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneOSX:
return "OSX";
#else
case BuildTarget.StandaloneOSXIntel:
case BuildTarget.StandaloneOSXIntel64:
case BuildTarget.StandaloneOSXUniversal:
return "OSX";
#endif
default:
return null;
}
}
private static string[] GetLevelsFromBuildSettings()
{
List<string> scenes = new List<string>();
foreach (SceneAsset item in GetBuildRules().scenesInBuild)
{
string path = AssetDatabase.GetAssetPath(item);
if (!string.IsNullOrEmpty(path))
{
scenes.Add(path);
}
}
return scenes.ToArray();
}
private static string GetAssetBundleManifestFilePath()
{
string relativeAssetBundlesOutputPathForPlatform = Path.Combine("Asset", GetPlatformName());
return Path.Combine(relativeAssetBundlesOutputPathForPlatform, GetPlatformName()) + ".manifest";
}
public static void BuildStandalonePlayer()
{
string outputPath =
Path.Combine(Environment.CurrentDirectory,
"Build/" + GetPlatformName()
.ToLower()); //EditorUtility.SaveFolderPanel("Choose Location of the Built Game", "", "");
if (outputPath.Length == 0)
return;
string[] levels = GetLevelsFromBuildSettings();
if (levels.Length == 0)
{
Debug.Log("Nothing to build.");
return;
}
string targetName = GetBuildTargetName(EditorUserBuildSettings.activeBuildTarget);
if (targetName == null)
return;
#if UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0
BuildOptions option = EditorUserBuildSettings.development ? BuildOptions.Development : BuildOptions.None;
BuildPipeline.BuildPlayer(levels, path + targetName, EditorUserBuildSettings.activeBuildTarget, option);
#else
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions
{
scenes = levels,
locationPathName = outputPath + targetName,
assetBundleManifestPath = GetAssetBundleManifestFilePath(),
target = EditorUserBuildSettings.activeBuildTarget,
options = EditorUserBuildSettings.development ? BuildOptions.Development : BuildOptions.None
};
BuildPipeline.BuildPlayer(buildPlayerOptions);
#endif
}
public static string CreateAssetBundleDirectory()
{
// Choose the output path according to the build target.
if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
return outputPath;
}
public static void BuildAssetBundles()
{
// Choose the output path according to the build target.
string outputPath = CreateAssetBundleDirectory();
const BuildAssetBundleOptions options = BuildAssetBundleOptions.ChunkBasedCompression;
BuildTarget targetPlatform = EditorUserBuildSettings.activeBuildTarget;
BuildRules rules = GetBuildRules();
var builds = rules.GetBuilds();
AssetBundleManifest assetBundleManifest =
BuildPipeline.BuildAssetBundles(outputPath, builds, options, targetPlatform);
if (assetBundleManifest == null)
{
return;
}
Manifest manifest = GetManifest();
var dirs = new List<string>();
var assets = new List<AssetRef>();
string[] bundles = assetBundleManifest.GetAllAssetBundles();
var bundle2Ids = new Dictionary<string, int>();
for (int index = 0; index < bundles.Length; index++)
{
string bundle = bundles[index];
bundle2Ids[bundle] = index;
}
var bundleRefs = new List<BundleRef>();
for (int index = 0; index < bundles.Length; index++)
{
string bundle = bundles[index];
string[] deps = assetBundleManifest.GetAllDependencies(bundle);
string path = string.Format("{0}/{1}", outputPath, bundle);
if (File.Exists(path))
{
using (FileStream stream = File.OpenRead(path))
{
bundleRefs.Add(new BundleRef
{
name = bundle,
id = index,
deps = Array.ConvertAll(deps, input => bundle2Ids[input]),
len = stream.Length,
hash = assetBundleManifest.GetAssetBundleHash(bundle).ToString(),
});
}
}
else
{
Debug.LogError(path + " file not exsit.");
}
}
for (int i = 0; i < rules.ruleAssets.Length; i++)
{
RuleAsset item = rules.ruleAssets[i];
string path = item.path;
string dir = Path.GetDirectoryName(path).Replace("\\", "/");
int index = dirs.FindIndex(o => o.Equals(dir));
if (index == -1)
{
index = dirs.Count;
dirs.Add(dir);
}
if (!bundle2Ids.TryGetValue(item.bundle, out int bundle))
{
throw new Exception($"{item.bundle}\n{item.path}");
}
AssetRef asset = new AssetRef
{bundle = bundle, dir = index, name = Path.GetFileName(path)};
assets.Add(asset);
}
manifest.dirs = dirs.ToArray();
manifest.assets = assets.ToArray();
manifest.bundles = bundleRefs.ToArray();
EditorUtility.SetDirty(manifest);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
string manifestBundleName = "manifest.unity3d";
builds = new[]
{
new AssetBundleBuild
{
assetNames = new[] {AssetDatabase.GetAssetPath(manifest),},
assetBundleName = manifestBundleName
}
};
BuildPipeline.BuildAssetBundles(outputPath, builds, options, targetPlatform);
ArrayUtility.Add(ref bundles, manifestBundleName);
Versions.BuildVersions(outputPath, bundles, GetBuildRules().AddVersion());
}
private static string GetBuildTargetName(BuildTarget target)
{
string time = DateTime.Now.ToString("yyyyMMdd-HHmmss");
string name = PlayerSettings.productName + "-v" + PlayerSettings.bundleVersion + ".";
switch (target)
{
case BuildTarget.Android:
return string.Format("/{0}{1}-{2}.apk", name, GetBuildRules().version, time);
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return string.Format("/{0}{1}-{2}.exe", name, GetBuildRules().version, time);
#if UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneOSX:
return "/" + name + ".app";
#else
case BuildTarget.StandaloneOSXIntel:
case BuildTarget.StandaloneOSXIntel64:
case BuildTarget.StandaloneOSXUniversal:
return "/" + path + ".app";
#endif
case BuildTarget.WebGL:
case BuildTarget.iOS:
return "";
// Add more build targets for your own.
default:
Debug.Log("Target not implemented.");
return null;
}
}
private static T GetAsset<T>(string path) where T : ScriptableObject
{
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
if (asset == null)
{
asset = ScriptableObject.CreateInstance<T>();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
}
return asset;
}
public static Manifest GetManifest()
{
return GetAsset<Manifest>(Assets.ManifestAsset);
}
}
}