您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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>();
}
}
}