您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
309 行
11 KiB
309 行
11 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace MetaCity.BundleKit.Editor
|
|
{
|
|
public enum MetacityBundleType
|
|
{
|
|
Prefab,
|
|
Scene,
|
|
Avatar,
|
|
SpawnPoints
|
|
}
|
|
|
|
public class MetacityBundle
|
|
{
|
|
public MetacityBundleType BundleType;
|
|
public AssetBundleBuild BundleBuild;
|
|
public bool NeedUpload;
|
|
}
|
|
public enum PlayMode
|
|
{
|
|
SinglePlayer,
|
|
MultiPlayer
|
|
}
|
|
|
|
public enum WebUrl
|
|
{
|
|
LocalTesting,
|
|
MetacityInt,
|
|
U3D
|
|
}
|
|
[Serializable]
|
|
public class BuildBundleConfig
|
|
{
|
|
public PlayMode playMode;
|
|
public MetacityBundleType curType;
|
|
public string bundleName;
|
|
public bool needBuild;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class BuildMainConfig
|
|
{
|
|
public PlayMode mPlayMode;
|
|
public WebUrl mWebUrl;
|
|
public bool mCustomize = false;
|
|
|
|
public List<BuildBundleConfig> bundleConfigs = new List<BuildBundleConfig>();
|
|
|
|
private BuildBundleConfig TryGetConfig(string bundleName, MetacityBundleType bundleType, bool createIfNotExists = false)
|
|
{
|
|
if (bundleConfigs != null)
|
|
{
|
|
foreach (var bundle in bundleConfigs)
|
|
{
|
|
if (bundle.bundleName == bundleName && bundle.curType == bundleType)
|
|
{
|
|
return bundle;
|
|
}
|
|
}
|
|
}
|
|
|
|
BuildBundleConfig ret = null;
|
|
if (createIfNotExists)
|
|
{
|
|
if (bundleConfigs == null)
|
|
{
|
|
bundleConfigs = new List<BuildBundleConfig>();
|
|
}
|
|
|
|
ret = new BuildBundleConfig
|
|
{
|
|
bundleName = bundleName,
|
|
curType = bundleType,
|
|
needBuild = true
|
|
};
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private void ReCollectBundleByType(List<BuildBundleConfig> newConfigs, List<string> bundleSources, MetacityBundleType curType)
|
|
{
|
|
foreach (var sceneName in bundleSources)
|
|
{
|
|
var newConfig = TryGetConfig(sceneName, curType);
|
|
if (newConfig == null)
|
|
{
|
|
newConfig = new BuildBundleConfig
|
|
{
|
|
bundleName = sceneName,
|
|
curType = curType,
|
|
needBuild = true,
|
|
};
|
|
}
|
|
|
|
newConfigs.Add(newConfig);
|
|
}
|
|
}
|
|
|
|
public void RefreshBundles(List<string> allScenes, List<string> allPrefabs)
|
|
{
|
|
var newConfigs = new List<BuildBundleConfig>();
|
|
ReCollectBundleByType(newConfigs, allScenes, MetacityBundleType.Scene);
|
|
ReCollectBundleByType(newConfigs, allPrefabs, MetacityBundleType.Prefab);
|
|
|
|
bundleConfigs = newConfigs;
|
|
}
|
|
|
|
public bool NeedBuildBundle(string bundleName, MetacityBundleType bundleType)
|
|
{
|
|
return TryGetConfig(bundleName, bundleType)?.needBuild ?? true;
|
|
}
|
|
|
|
public void ToggleNeedBuildArtifact(string bundleName)
|
|
{
|
|
if (bundleConfigs == null)
|
|
{
|
|
bundleConfigs = new List<BuildBundleConfig>();
|
|
}
|
|
|
|
var curConfig = TryGetConfig(bundleName, MetacityBundleType.Prefab, true);
|
|
curConfig.needBuild = !curConfig.needBuild;
|
|
}
|
|
public void ToggleSceneBundleConfig(string bundleName)
|
|
{
|
|
if (bundleConfigs == null)
|
|
{
|
|
bundleConfigs = new List<BuildBundleConfig>();
|
|
}
|
|
|
|
var curConfig = TryGetConfig(bundleName, MetacityBundleType.Scene, true);
|
|
curConfig.needBuild = !curConfig.needBuild;
|
|
curConfig.playMode=mPlayMode;
|
|
}
|
|
public void SetPlayMode(PlayMode playMode)
|
|
{
|
|
mPlayMode=playMode;
|
|
foreach (var bundle in bundleConfigs)
|
|
{
|
|
if (bundle.curType == MetacityBundleType.Scene)
|
|
{
|
|
bundle.playMode=playMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetWebUrl(WebUrl weburl)
|
|
{
|
|
mWebUrl= weburl;
|
|
}
|
|
|
|
public void PrepareSave(List<string> allScenes, List<string> allAssets)
|
|
{
|
|
RefreshBundles(allScenes, allAssets);
|
|
}
|
|
|
|
private List<string> GetSkippedBundles(MetacityBundleType curType)
|
|
{
|
|
var bundleNames = new List<string>();
|
|
if (bundleConfigs != null)
|
|
{
|
|
foreach (var bundleConfig in bundleConfigs)
|
|
{
|
|
if (bundleConfig.curType == curType &&
|
|
!bundleConfig.needBuild)
|
|
{
|
|
bundleNames.Add(bundleConfig.bundleName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bundleNames;
|
|
}
|
|
|
|
private List<BuildBundleConfig> GetAllBundles(MetacityBundleType curType)
|
|
{
|
|
var bundles = new List<BuildBundleConfig>();
|
|
if (bundleConfigs != null)
|
|
{
|
|
foreach (var bundleConfig in bundleConfigs)
|
|
{
|
|
if (bundleConfig.curType == curType)
|
|
{
|
|
bundles.Add(bundleConfig);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bundles;
|
|
}
|
|
|
|
public List<string> skipAssets => GetSkippedBundles(MetacityBundleType.Prefab);
|
|
|
|
public List<BuildBundleConfig> allSceneBundles => GetAllBundles(MetacityBundleType.Scene);
|
|
|
|
public List<BuildBundleConfig> allAssetBundles => GetAllBundles(MetacityBundleType.Prefab);
|
|
}
|
|
|
|
public static class BuildEntry
|
|
{
|
|
private static readonly List<MetacityBundle> AllBundleBuilds = new List<MetacityBundle>();
|
|
|
|
private static void PrepareBuild()
|
|
{
|
|
AllBundleBuilds.Clear();
|
|
|
|
var buildPath = Constants.BundleFolderPath;
|
|
if (Directory.Exists(buildPath))
|
|
{
|
|
DirectoryInfo di = new DirectoryInfo(buildPath);
|
|
foreach (FileInfo file in di.GetFiles())
|
|
{
|
|
file.Delete();
|
|
}
|
|
foreach (DirectoryInfo dir in di.GetDirectories())
|
|
{
|
|
dir.Delete(true);
|
|
}
|
|
|
|
Directory.Delete(buildPath);
|
|
}
|
|
|
|
Directory.CreateDirectory(buildPath);
|
|
}
|
|
|
|
/**
|
|
* Build all user generated contents into Bundles according to the following rules:
|
|
* (1) Each scene inside the Assets/Game folder will be packed into one scene bundle named as its scene name in lower cases
|
|
*
|
|
* (2) User should put all the sharable assets (e.g., a prefab that can be bought and used by other users) into the Assets/Exports folder.
|
|
* Specifically, a specific prefab and all its dependent assets should be put into one child folder in Assets/Exports. Then they will be
|
|
* packed into one asset bundle named as the folder name in lower cases
|
|
*
|
|
* (3) All the referenced assets (e.g., a prefab from a bundle that shared from other users) are automatically downloaded into the Assets/Imports folder and
|
|
* user should not modify this folder manually at all if they want to remain the reference link. These assets won't be uploaded to the
|
|
* cloud as dependent bundles of the user scene. On the contrary, the user scene will dependent on the shared bundle directly instead.
|
|
*
|
|
* (4) Bundle dependencies will be correctly processed in the pack progress and stored on the cloud. So user doesn't need to handle it by themselves
|
|
*
|
|
* (5) Bundle hashes will be considered automatically when uploading the bundle and updating its content on the cloud. If it doesn't change after
|
|
* a new build, nothing will be changed on the cloud.
|
|
*
|
|
* (6) By default, user can use the builtin pack process which will generate bundles following the above rules. However, they can also customize
|
|
* it by turning on "Customize Build" and toggling off check boxes before bundles to build in the BundleMainWindow. Bundles with unchecked boxes will
|
|
* skip the next build and won't be uploaded to the cloud at all
|
|
*
|
|
*/
|
|
public static List<BuildCatalog> DoBuild(PlayMode playMode,List<BuildBundleConfig> sceneConfigs, List<string> skipPrefabs)
|
|
{
|
|
PrepareBuild();
|
|
SpawnPositionCollector.CollectSpawnPositionBundle(AllBundleBuilds);
|
|
PrefabCollector.CollectPrefabBundles(AllBundleBuilds, skipPrefabs);
|
|
SceneCollector.CollectSceneBundles(AllBundleBuilds, sceneConfigs);
|
|
|
|
var platform = EditorUserBuildSettings.activeBuildTarget;
|
|
AssetBundleManifest manifest = null;
|
|
try
|
|
{
|
|
var allBundleBuilds = AllBundleBuilds.Select(item => item.BundleBuild);
|
|
manifest = BuildPipeline.BuildAssetBundles(Constants.BundleFolderPath, allBundleBuilds.ToArray(), BuildAssetBundleOptions.None, platform);
|
|
Debug.Log($"Build succeeded. Manifest {manifest.name}");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"Build bundle error for {platform.ToString()}: {e.Message}");
|
|
}
|
|
|
|
if (manifest != null)
|
|
{
|
|
var catalogs = CatalogUtilities.CreateCatalog(playMode,platform, manifest, AllBundleBuilds);
|
|
|
|
var catalogCollection = new BuildCatalogCollection
|
|
{
|
|
catalogs = catalogs.ToArray()
|
|
};
|
|
|
|
var writer = new StreamWriter(Constants.BundleLocalCatalogPath, false);
|
|
writer.WriteLine(JsonUtility.ToJson(catalogCollection));
|
|
writer.Close();
|
|
|
|
return catalogs;
|
|
}
|
|
|
|
Debug.LogError($"nothing is built");
|
|
return null;
|
|
}
|
|
|
|
public static List<BuildCatalog> LoadLastBuiltCatalog()
|
|
{
|
|
var catalogReader = new StreamReader(Constants.BundleLocalCatalogPath);
|
|
try
|
|
{
|
|
var catalogCollection = JsonUtility.FromJson<BuildCatalogCollection>(catalogReader.ReadToEnd());
|
|
return catalogCollection.catalogs.ToList();
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
Debug.Log($"Cannot load last build catalog from {Constants.BundleLocalCatalogPath}!");
|
|
}
|
|
|
|
return new List<BuildCatalog>();
|
|
}
|
|
}
|
|
}
|