public LateReferenceProcessor(IList <string> assetPaths) { var objSet = new HashSet <UnityEngine.Object>(); AssetId.CurrentGenerator = obj => { string id = AssetId.DefaultGenerator(obj); if (!string.IsNullOrEmpty(id)) { objSet.Add(obj); } return(id); }; foreach (string assetPath in ScanningUtils.ItemsProcessor(assetPaths, "Scanning assets for late references", p => Path.GetFileName(p))) { var asset = AssetDatabase.LoadMainAssetAtPath(assetPath); ProcessObject(asset); } AssetId.CurrentGenerator = AssetId.DefaultGenerator; _referencedObjects = objSet.ToList(); }
private bool IsLateAttributeField(object obj, FieldInfo field, out FieldInfo targetField, bool performChecks) { targetField = null; LateAttribute lazyAttribute = Attribute.GetCustomAttribute(field, typeof(LateAttribute)) as LateAttribute; if (lazyAttribute == null) { return(false); } string targetIdField = lazyAttribute.TargetIdField ?? (field.Name + (field.FieldType.IsArray ? "Ids" : "Id")); targetField = obj.GetType().GetField(targetIdField, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (targetField == null) { throw new UnityException(FormatTargetFieldErrorMessage("does not exist", obj, field, lazyAttribute.TargetIdField)); } if (performChecks) { if (ScanningUtils.IsSerializableArray(field.FieldType)) { if (!typeof(UnityEngine.Object).IsAssignableFrom(ScanningUtils.GetSerializableArrayType(field.FieldType))) { throw new UnityException(FormatLateFieldErrorMessage("is not an UnityEngine.Object assignable array", obj, field.Name)); } if (ScanningUtils.GetSerializableArrayType(targetField.FieldType) != typeof(string)) { throw new UnityException(FormatTargetFieldErrorMessage("is not a string array", obj, field, targetIdField)); } } else { if (!typeof(UnityEngine.Object).IsAssignableFrom(field.FieldType)) { throw new UnityException(FormatLateFieldErrorMessage("is not an UnityEngine.Object assignable", obj, field.Name)); } if (targetField.FieldType != typeof(string)) { throw new UnityException(FormatTargetFieldErrorMessage("is not a string", obj, field, targetIdField)); } } if (!targetField.IsPublic && Attribute.GetCustomAttribute(targetField, typeof(SerializeField)) == null) { throw new UnityException(FormatTargetFieldErrorMessage("is not public or have [SerializeField] attribute", obj, field, lazyAttribute.TargetIdField)); } if (targetField.IsPublic && Attribute.GetCustomAttribute(targetField, typeof(HideInInspector)) == null) { Debug.LogWarning(FormatTargetFieldErrorMessage("is public but don't have the [HideInInspector] attribute, " + "this field is not meant to be editable by users", obj, field, lazyAttribute.TargetIdField)); } } return(true); }
private bool DetargetLateAttributeField(object obj, FieldInfo field) { FieldInfo targetField; if (IsLateAttributeField(obj, field, out targetField, true)) { if (ScanningUtils.IsSerializableArray(field.FieldType)) { IList referencesArray = (IList)field.GetValue(obj); var idsArray = new string[referencesArray.Count]; for (int i = 0; i < referencesArray.Count; i++) { UnityEngine.Object val = (UnityEngine.Object)referencesArray[i]; idsArray[i] = AssetId.FromObject(val); referencesArray[i] = null; } targetField.SetValue(obj, (object)idsArray); } else { UnityEngine.Object val = (UnityEngine.Object)field.GetValue(obj); targetField.SetValue(obj, (object)AssetId.FromObject(val)); field.SetValue(obj, null); } return(true); } return(false); }
private bool DetargetObject(UnityEngine.Object obj) { bool modified = false; foreach (var info in ScanningUtils.ScanObjectFields(obj)) { //if (DetargetLateAttributeField(info.Obj, info.Field)) // modified = true; if (DetargetLateAttributeField(info.Obj, info.Field)) { modified = true; #if KEEP_BROKEN_LINKS if (modified) { EditorUtility.SetDirty(obj); } #endif //Console.WriteLine("---" + AssetDatabase.GetAssetPath(obj) + " true"); } else { //Console.WriteLine("---" + AssetDatabase.GetAssetPath(obj) + " false"); } } return(modified); }
public static string[] CollectBuildAssets() { string oldScene = EditorApplication.currentScene; try { var buildAssets = new HashSet <string>(); var scenes = CollectBuildScenes(); foreach (var scene in ScanningUtils.ItemsProcessor(scenes, "Collecting build assets", p => Path.GetFileName(p))) { EditorApplication.OpenScene(scene); buildAssets.Add(scene); UnityEngine.Debug.Log("current scene: " + scene); buildAssets.UnionWith(ScanningUtils.ScanCurrentSceneAssets().Select(o => AssetDatabase.GetAssetPath(o))); } buildAssets.Remove(""); return(buildAssets.OrderBy(p => p).ToArray()); } finally { EditorApplication.OpenScene(oldScene); } }
// Note: Hashes are calculated for source files since unity seems to // serialize material maps in a way that yields a random order private void ComputeBuildAssetsHashes() { _buildAssetsHashes = new byte[_buildAssets.Length][]; int i = 0; foreach (var assetPath in ScanningUtils.ItemsProcessor(_buildAssets, "Computing assets hashes", p => Path.GetFileName(p))) { _buildAssetsHashes[i] = BuilderCache.Instance.GetHashForAsset(assetPath); i++; } }
private void MapBundles() { var bundlesMap = new Dictionary <string, AssetBundleBuildInfo>(); foreach (string assetPath in ScanningUtils.ItemsProcessor(_buildAssets, "Mapping asset to bundles", p => Path.GetFileName(p))) { string matchAssetPath = assetPath.ToLower().Substring("assets/".Length); var rule = _bundlesConfig.MatchRules(matchAssetPath); if (rule != null && rule.Type == AssetBundlesConfig.RuleType.Include && !string.IsNullOrEmpty(rule.BundleName)) { bool isSceneAsset = Path.GetExtension(assetPath) == ".unity"; string bundleName = rule.GetReplacedBundleName(matchAssetPath); AssetBundleBuildInfo bundleInfo; if (!bundlesMap.TryGetValue(bundleName, out bundleInfo)) { bundleInfo = new AssetBundleBuildInfo(bundleName, rule, isSceneAsset); bundlesMap.Add(bundleName, bundleInfo); } if (isSceneAsset) { if (!bundleInfo.IsScene) { throw new UnityException("Scenes can only be added to scene bundles"); } } else { var importer = AssetImporter.GetAtPath(assetPath); if (importer != null) { AudioImporter audioImporter = importer as AudioImporter; if (audioImporter != null) { //if (audioImporter.loadType == AudioImporterLoadType.StreamFromDisc) // throw new UnityException("Can't add streamed audio clips to asset bundles: " + assetPath); } } } bundleInfo.AssetsPaths.Add(assetPath); } } _bundles = bundlesMap.Values.OrderBy(b => b.Order).ThenBy(b => b.Name).ToList(); }
private void CreateLateResources(IList <UnityEngine.Object> objects) { const string lateResourcesDirectory = "Assets/Resources/Late"; BuildUtils.PrepareCleanDirectory(lateResourcesDirectory); foreach (var obj in ScanningUtils.ItemsProcessor(objects, "Creating late resources", p => AssetDatabase.GetAssetPath(p))) { var lateResource = ScriptableObject.CreateInstance <LateResource>(); lateResource.Target = obj; AssetDatabase.CreateAsset(lateResource, lateResourcesDirectory + "/" + AssetId.FromObject(obj) + ".asset"); } }
private bool ProcessObject(UnityEngine.Object sourceObj) { if (!(sourceObj is GameObject) && !(sourceObj is ScriptableObject)) { return(false); } bool ret = false; foreach (var obj in ScanningUtils.ScanObject(sourceObj)) { if (DetargetObject(obj)) { _processedObjects.Add(obj); ret = true; } } return(ret); }
private bool RetargetObject(UnityEngine.Object obj) { bool modified = false; foreach (var info in ScanningUtils.ScanObjectFields(obj)) { if (RetargetLateAttributeField(info.Obj, info.Field)) { modified = true; } } #if DEBUG_KEEP_IDS if (modified) { EditorUtility.SetDirty(obj); } #endif return(modified); }
private bool RetargetLateAttributeField(object obj, FieldInfo field) { FieldInfo targetField; if (IsLateAttributeField(obj, field, out targetField, false)) { if (ScanningUtils.IsSerializableArray(field.FieldType)) { IList idsArray = (IList)targetField.GetValue(obj); UnityEngine.Object[] referencesArray = (UnityEngine.Object[])Activator.CreateInstance(field.FieldType, new object[] { idsArray.Count }); for (int i = 0; i < idsArray.Count; i++) { referencesArray[i] = AssetId.FromId((string)idsArray[i], ScanningUtils.GetSerializableArrayType(field.FieldType)); } field.SetValue(obj, (object)referencesArray); #if !DEBUG_KEEP_IDS targetField.SetValue(obj, null); #endif } else { #if !KEEP_BROKEN_LINKS string val = (string)targetField.GetValue(obj); field.SetValue(obj, (object)AssetId.FromId(val, field.FieldType)); #endif #if !DEBUG_KEEP_IDS targetField.SetValue(obj, null); #endif } return(true); } return(false); }
private void PackBundles() { var referencedObjects = new HashSet <UnityEngine.Object>(_lateProcessor.ReferencedObjects); var packedObjects = new HashSet <UnityEngine.Object>(); var tempPath = Path.Combine(Path.GetTempPath(), "bundles_" + DateTime.UtcNow.Ticks.ToString()); BuildUtils.PrepareCleanDirectory(tempPath); PushAssetDependencies(); { foreach (var bundleInfo in ScanningUtils.ItemsProcessor(_bundles, "Packing asset bundles", p => Path.GetFileName(p.Name), true)) { Console.WriteLine("Building bundle " + bundleInfo.Name + "..."); string bundlePath = Path.Combine(tempPath, bundleInfo.Name); //BuildUtils.GetPathHashString(bundleInfo.Name)); if (bundleInfo.IsScene) { var scenePaths = bundleInfo.AssetsPaths.ToArray(); PushAssetDependencies(); { string buildResult = BuildPipeline.BuildStreamedSceneAssetBundle(scenePaths, bundlePath, _params.Target); if (!String.IsNullOrEmpty(buildResult)) { throw new UnityException(buildResult); } } PopAssetDependencies(); // Find which assets were packed var packedDependencies = new HashSet <UnityEngine.Object>(); foreach (var scenePath in scenePaths) { Debug.Log(scenePath); EditorApplication.OpenScene(scenePath); packedDependencies.UnionWith(ScanningUtils.ScanCurrentSceneAssets()); packedDependencies.ExceptWith(packedObjects); } bundleInfo.Dependencies = packedDependencies.ToList(); var hash = GetHashForBuildAssets(scenePaths.Concat(BuildUtils.GetAssetPathsForObjects(packedDependencies))); int bundleLevel = _bundleLevelDataBase.GetBundleLevel(bundleInfo.Name); bundleInfo.Data = _bundlesDatabaseBuilder.AddSceneBundle(bundleInfo.Name, hash, bundleLevel, scenePaths.Select(p => Path.GetFileNameWithoutExtension(p)).ToArray(), bundlePath); } else { // Add only the main asset + any late referenced asset var mainObjects = bundleInfo.AssetsPaths.Select(p => AssetDatabase.LoadMainAssetAtPath(p)); var representations = bundleInfo.AssetsPaths.SelectMany(p => AssetDatabase.LoadAllAssetRepresentationsAtPath(p)); var objects = mainObjects.Concat(representations.Where(o => referencedObjects.Contains(o))).ToArray(); var assetIds = objects.Select(o => AssetId.FromObject(o)).ToArray(); foreach (var obj in objects) { string assetPath = AssetDatabase.GetAssetPath(obj); string guid = AssetDatabase.AssetPathToGUID(assetPath); Console.WriteLine("path: " + assetPath + " guid:" + guid); } if (bundleInfo.Isolate) { PushAssetDependencies(); } { if (!BuildPipeline.BuildAssetBundleExplicitAssetNames(objects, assetIds, bundlePath, BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.DeterministicAssetBundle, _params.Target)) { throw new UnityException("Error building bundle " + bundleInfo.Name); } } if (bundleInfo.Isolate) { PopAssetDependencies(); } // Find which assets were packed var packedDependencies = new HashSet <UnityEngine.Object>(EditorUtility.CollectDependencies(objects.ToArray())); packedDependencies.ExceptWith(packedObjects); bundleInfo.Dependencies = packedDependencies.ToList(); if (!bundleInfo.Isolate) { packedObjects.UnionWith(packedDependencies); } var hash = GetHashForBuildAssets(BuildUtils.GetAssetPathsForObjects(packedDependencies)); int bundleLevel = _bundleLevelDataBase.GetBundleLevel(bundleInfo.Name); bundleInfo.Data = _bundlesDatabaseBuilder.AddBundle(bundleInfo.Name, hash, bundleLevel, bundlePath, assetIds.ToList()); foreach (var obj in objects) { referencedObjects.Remove(obj); } } } } PopAssetDependencies(); // Move to right destination Directory.CreateDirectory(_params.BundlesLocation); _bundlesPath = Path.Combine(_params.BundlesLocation, _bundlesDatabaseBuilder.Database.Id); FileUtil.DeleteFileOrDirectory(_bundlesPath); FileUtil.MoveFileOrDirectory(tempPath, _bundlesPath); // To create late reference for any late object not added to bundles _objectsToLateReference = referencedObjects.ToList(); }