| New file |
| | |
| | | using System; |
| | | using System.IO; |
| | | using UnityEditor; |
| | | using UnityEngine; |
| | | using YooAsset.Editor; |
| | | |
| | | public static class CollectResBeforeUpdate |
| | | { |
| | | private const string BuiltinPackageName = "Builtin"; |
| | | private const string PrefabPackageName = "Prefab"; |
| | | private const string GroupName = "ResBeforeUpdate"; |
| | | private const string AfterUpdateGroupName = "BuiltinAfterUpdate"; |
| | | private const string CollectBuiltinAfterUpdateRuleName = "CollectBuiltinAfterUpdate"; |
| | | private const string BuiltInRoot = "Assets/ResourcesOut/BuiltIn"; |
| | | private const string ConfigRoot = "Assets/ResourcesOut/Config"; |
| | | private const string InitialFunctionPath = ConfigRoot + "/InitialFunction.txt"; |
| | | private const string ResourcesInitialFunctionPath = "Assets/Resources/Config/InitialFunction.txt"; |
| | | |
| | | private static readonly string[] BeforeUpdateBuiltinAssetPaths = |
| | | { |
| | | BuiltInRoot + "/Prefabs/LaunchExWin.prefab", |
| | | BuiltInRoot + "/Sprites/TY_TB_JH1.png", |
| | | BuiltInRoot + "/Sprites/TY_TB_JH2.png", |
| | | BuiltInRoot + "/Sprites/LoadingBottom.png", |
| | | BuiltInRoot + "/Sprites/LoadingSlider.png", |
| | | }; |
| | | |
| | | private static readonly string[] BuiltinConfigPaths = |
| | | { |
| | | ConfigRoot + "/Contact.txt", |
| | | ConfigRoot + "/HelpInfo.txt", |
| | | ConfigRoot + "/PriorBundle.txt", |
| | | ConfigRoot + "/PriorLanguage.txt", |
| | | ConfigRoot + "/ApkUpdateUrl.txt", |
| | | InitialFunctionPath, |
| | | }; |
| | | |
| | | [MenuItem("YooAsset工具/收集热更前资源到Builtin", false, 202)] |
| | | public static void Execute() |
| | | { |
| | | var changed = SyncCollectors(); |
| | | EditorUtility.DisplayDialog( |
| | | "CollectResBeforeUpdate", |
| | | changed ? "热更前资源已同步到 Builtin Package。" : "热更前资源收集配置已经是最新。", |
| | | "确定"); |
| | | } |
| | | |
| | | public static bool SyncCollectors() |
| | | { |
| | | var setting = AssetBundleCollectorSettingData.Setting; |
| | | var changed = false; |
| | | |
| | | var builtinPackage = setting.Packages.Find(package => package.PackageName == BuiltinPackageName); |
| | | if (builtinPackage == null) |
| | | { |
| | | builtinPackage = AssetBundleCollectorSettingData.CreatePackage(BuiltinPackageName); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Package: {BuiltinPackageName}"); |
| | | } |
| | | |
| | | var group = builtinPackage.Groups.Find(item => item.GroupName == GroupName); |
| | | if (group == null) |
| | | { |
| | | group = AssetBundleCollectorSettingData.CreateGroup(builtinPackage, GroupName); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Group: {GroupName}"); |
| | | } |
| | | |
| | | changed |= RemoveObsoleteBuiltinRootCollectors(builtinPackage); |
| | | changed |= RemoveDuplicateBeforeUpdateCollectors(setting, builtinPackage, group); |
| | | foreach (var assetPath in BeforeUpdateBuiltinAssetPaths) |
| | | { |
| | | changed |= EnsureCollector(group, assetPath, nameof(PackSeparately), nameof(CollectAll)); |
| | | } |
| | | |
| | | foreach (var configPath in BuiltinConfigPaths) |
| | | { |
| | | changed |= EnsureCollector(group, configPath, nameof(PackSeparately), nameof(CollectAll)); |
| | | } |
| | | |
| | | changed |= EnsureAfterUpdateBuiltinCollector(setting); |
| | | changed |= SyncResourcesInitialFunction(); |
| | | |
| | | if (changed) |
| | | { |
| | | AssetBundleCollectorSettingData.SaveFile(); |
| | | AssetDatabase.Refresh(); |
| | | Debug.Log("[CollectResBeforeUpdate] 热更前资源收集配置已同步。Builtin 只保留 Launch 白名单,其余 BuiltIn 资源由 Prefab 包收集。"); |
| | | } |
| | | else |
| | | { |
| | | Debug.Log("[CollectResBeforeUpdate] 热更前资源收集配置无需更新。"); |
| | | } |
| | | |
| | | return changed; |
| | | } |
| | | |
| | | public static bool IsBeforeUpdateBuiltinAsset(string assetPath) |
| | | { |
| | | foreach (var beforeUpdatePath in BeforeUpdateBuiltinAssetPaths) |
| | | { |
| | | if (IsSameAssetPath(assetPath, beforeUpdatePath)) |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | private static bool EnsureAfterUpdateBuiltinCollector(AssetBundleCollectorSetting setting) |
| | | { |
| | | var prefabPackage = setting.Packages.Find(package => package.PackageName == PrefabPackageName); |
| | | if (prefabPackage == null) |
| | | { |
| | | prefabPackage = AssetBundleCollectorSettingData.CreatePackage(PrefabPackageName); |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Package: {PrefabPackageName}"); |
| | | } |
| | | |
| | | var group = prefabPackage.Groups.Find(item => item.GroupName == AfterUpdateGroupName); |
| | | if (group == null) |
| | | { |
| | | group = AssetBundleCollectorSettingData.CreateGroup(prefabPackage, AfterUpdateGroupName); |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Group: {AfterUpdateGroupName}"); |
| | | } |
| | | |
| | | return EnsureCollector(group, BuiltInRoot, nameof(PackDirectory), CollectBuiltinAfterUpdateRuleName); |
| | | } |
| | | |
| | | private static bool RemoveObsoleteBuiltinRootCollectors(AssetBundleCollectorPackage builtinPackage) |
| | | { |
| | | var changed = false; |
| | | foreach (var group in builtinPackage.Groups) |
| | | { |
| | | for (var index = group.Collectors.Count - 1; index >= 0; index--) |
| | | { |
| | | var collector = group.Collectors[index]; |
| | | if (!IsSameAssetPath(collector.CollectPath, BuiltInRoot)) |
| | | continue; |
| | | |
| | | AssetBundleCollectorSettingData.RemoveCollector(group, collector); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 从 Builtin Package 移除整目录 Collector: {collector.CollectPath}"); |
| | | } |
| | | } |
| | | |
| | | return changed; |
| | | } |
| | | |
| | | private static bool RemoveDuplicateBeforeUpdateCollectors( |
| | | AssetBundleCollectorSetting setting, |
| | | AssetBundleCollectorPackage builtinPackage, |
| | | AssetBundleCollectorGroup targetGroup) |
| | | { |
| | | var changed = false; |
| | | foreach (var package in setting.Packages) |
| | | { |
| | | foreach (var group in package.Groups) |
| | | { |
| | | for (var index = group.Collectors.Count - 1; index >= 0; index--) |
| | | { |
| | | var collector = group.Collectors[index]; |
| | | if (!IsExactBeforeUpdateCollectPath(collector.CollectPath)) |
| | | continue; |
| | | |
| | | if (package == builtinPackage && group == targetGroup) |
| | | continue; |
| | | |
| | | AssetBundleCollectorSettingData.RemoveCollector(group, collector); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 从 Package '{package.PackageName}' 移除重复 Collector: {collector.CollectPath}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return changed; |
| | | } |
| | | |
| | | private static bool EnsureCollector(AssetBundleCollectorGroup group, string collectPath, string packRuleName, string filterRuleName) |
| | | { |
| | | var collectorGuid = AssetDatabase.AssetPathToGUID(collectPath); |
| | | if (string.IsNullOrEmpty(collectorGuid)) |
| | | { |
| | | Debug.LogWarning($"[CollectResBeforeUpdate] 跳过不存在的资源: {collectPath}"); |
| | | return false; |
| | | } |
| | | |
| | | var changed = false; |
| | | AssetBundleCollector target = null; |
| | | |
| | | for (var index = group.Collectors.Count - 1; index >= 0; index--) |
| | | { |
| | | var collector = group.Collectors[index]; |
| | | if (!IsSameAssetPath(collector.CollectPath, collectPath)) |
| | | continue; |
| | | |
| | | if (target == null) |
| | | { |
| | | target = collector; |
| | | } |
| | | else |
| | | { |
| | | AssetBundleCollectorSettingData.RemoveCollector(group, collector); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 移除重复 Collector: {collector.CollectPath}"); |
| | | } |
| | | } |
| | | |
| | | if (target == null) |
| | | { |
| | | target = new AssetBundleCollector { CollectPath = collectPath }; |
| | | AssetBundleCollectorSettingData.CreateCollector(group, target); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Collector: {collectPath}"); |
| | | } |
| | | |
| | | changed |= SetString(ref target.CollectPath, collectPath); |
| | | changed |= SetString(ref target.CollectorGUID, collectorGuid); |
| | | if (target.CollectorType != ECollectorType.MainAssetCollector) |
| | | { |
| | | target.CollectorType = ECollectorType.MainAssetCollector; |
| | | changed = true; |
| | | } |
| | | |
| | | changed |= SetString(ref target.AddressRuleName, nameof(AddressByRelativePath)); |
| | | changed |= SetString(ref target.PackRuleName, packRuleName); |
| | | changed |= SetString(ref target.FilterRuleName, filterRuleName); |
| | | changed |= SetString(ref target.AssetTags, string.Empty); |
| | | changed |= SetString(ref target.UserData, string.Empty); |
| | | |
| | | if (changed) |
| | | AssetBundleCollectorSettingData.ModifyCollector(group, target); |
| | | return changed; |
| | | } |
| | | |
| | | private static bool SyncResourcesInitialFunction() |
| | | { |
| | | var sourceFullPath = ToProjectFullPath(InitialFunctionPath); |
| | | if (!File.Exists(sourceFullPath)) |
| | | { |
| | | Debug.LogError($"[CollectResBeforeUpdate] 找不到 ResourcesOut InitialFunction: {InitialFunctionPath}"); |
| | | return false; |
| | | } |
| | | |
| | | var targetFullPath = ToProjectFullPath(ResourcesInitialFunctionPath); |
| | | var targetDirectory = Path.GetDirectoryName(targetFullPath); |
| | | if (!Directory.Exists(targetDirectory)) |
| | | Directory.CreateDirectory(targetDirectory); |
| | | |
| | | var sourceText = File.ReadAllText(sourceFullPath); |
| | | if (File.Exists(targetFullPath) && File.ReadAllText(targetFullPath) == sourceText) |
| | | return false; |
| | | |
| | | File.WriteAllText(targetFullPath, sourceText); |
| | | AssetDatabase.ImportAsset(ResourcesInitialFunctionPath); |
| | | Debug.Log($"[CollectResBeforeUpdate] 已同步 Resources InitialFunction: {ResourcesInitialFunctionPath}"); |
| | | return true; |
| | | } |
| | | |
| | | private static bool IsExactBeforeUpdateCollectPath(string collectPath) |
| | | { |
| | | if (IsSameAssetPath(collectPath, BuiltInRoot)) |
| | | return false; |
| | | |
| | | foreach (var beforeUpdatePath in BeforeUpdateBuiltinAssetPaths) |
| | | { |
| | | if (IsSameAssetPath(collectPath, beforeUpdatePath)) |
| | | return true; |
| | | } |
| | | |
| | | foreach (var configPath in BuiltinConfigPaths) |
| | | { |
| | | if (IsSameAssetPath(collectPath, configPath)) |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | private static bool IsSameAssetPath(string lhs, string rhs) |
| | | { |
| | | return NormalizeAssetPath(lhs).Equals(NormalizeAssetPath(rhs), StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static string ToProjectFullPath(string assetPath) |
| | | { |
| | | var projectRoot = Directory.GetParent(Application.dataPath).FullName; |
| | | return Path.Combine(projectRoot, NormalizeAssetPath(assetPath)); |
| | | } |
| | | |
| | | private static string NormalizeAssetPath(string assetPath) |
| | | { |
| | | return string.IsNullOrEmpty(assetPath) ? string.Empty : assetPath.Replace('\\', '/').TrimEnd('/'); |
| | | } |
| | | |
| | | private static bool SetString(ref string target, string value) |
| | | { |
| | | if (target == value) |
| | | return false; |
| | | |
| | | target = value; |
| | | return true; |
| | | } |
| | | } |