| | |
| | | ShowEditorAlias: 0 |
| | | UniqueBundleName: 1 |
| | | Packages: |
| | | - PackageName: UI |
| | | PackageDesc: all uiprefabs |
| | | - PackageName: Builtin |
| | | PackageDesc: builtin resources |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/UI |
| | | CollectorGUID: 0a5282bb472d1144ab08a2d07b5a3801 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/UIComp |
| | | CollectorGUID: cafb96babf67f0e47aa47d7bd7e851f9 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Sprite |
| | | CollectorGUID: d525c1ea56911ef46968923700fee47f |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Texture |
| | | CollectorGUID: cc4265f3ee528e64e8afa76bd8f7d3f7 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: Font |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Font |
| | | CollectorGUID: 6c72fee81b7c8804dbc80d80a5770197 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Prefab |
| | | PackageDesc: all prefab |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Shader |
| | | CollectorGUID: 01ad80e2bb073fb46ad906e3572fbe50 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: shader |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Materials |
| | | CollectorGUID: 676c8b4532d6ca646804bf73ed43dd96 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/ScriptableObject |
| | | CollectorGUID: 1482db32e9d88d444bc22e54075bf994 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Scenes |
| | | CollectorGUID: b3332ee13576c994186d5570af59b0b6 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Config |
| | | CollectorGUID: 6a0e1d814ea59174985b17c9f4ecaba3 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectConfigExcludeOPConfig |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: BuiltinAfterUpdate |
| | | - GroupName: BuiltIn |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | |
| | | FilterRuleName: CollectBuiltinAfterUpdate |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Dll |
| | | PackageDesc: HybridCLR Generated |
| | | EnableAddressable: 0 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 0 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Default Group |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: [] |
| | | - GroupName: HybridCLR Generated |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/HybridCLRDlls |
| | | CollectorGUID: |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByFileName |
| | | PackRuleName: PackRawFile |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: UIEffect |
| | | PackageDesc: |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/UIEffect |
| | | CollectorGUID: 62eb3abc624381e4b8950f355812a8e9 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Battle |
| | | PackageDesc: battle resources |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Hero |
| | | CollectorGUID: 4ef1d5e33efbd83438f79bd2fd7c44ac |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Battle |
| | | CollectorGUID: f4b5330ed101c7b4c8cbfba3f0daff9f |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Audio |
| | | PackageDesc: audio resources |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Audio |
| | | CollectorGUID: 3d2c92bf721b286489d290a1a2c9763a |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Video |
| | | PackageDesc: video resources |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Video |
| | | CollectorGUID: |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Builtin |
| | | PackageDesc: builtin resources |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Prefab |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: [] |
| | | - GroupName: ResBeforeUpdate |
| | | GroupDesc: |
| | | AssetTags: |
| | |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2 |
| | | CollectorGUID: f8d4cf3f39e708b4796c455fbf07a55b |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - CollectPath: Assets/ResourcesOut/Config/InitialFunction.txt |
| | | CollectorGUID: ab2ea28be4c891a4e81ddf6317e8f7c0 |
| | | CollectorType: 0 |
| | |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Dll |
| | | PackageDesc: HybridCLR Generated |
| | | EnableAddressable: 0 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 0 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: HybridCLR Generated |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/HybridCLRDlls |
| | | CollectorGUID: abc904664683ec645829ea85e356b657 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByFileName |
| | | PackRuleName: PackRawFile |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Audio |
| | | PackageDesc: ResourcesOut/Audio |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Audio |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Audio |
| | | CollectorGUID: 3d2c92bf721b286489d290a1a2c9763a |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Battle |
| | | PackageDesc: ResourcesOut/Battle |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Battle |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Battle |
| | | CollectorGUID: f4b5330ed101c7b4c8cbfba3f0daff9f |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Config |
| | | PackageDesc: ResourcesOut/Config |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Config |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Config |
| | | CollectorGUID: 6a0e1d814ea59174985b17c9f4ecaba3 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectConfigExcludeOPConfig |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Hero |
| | | PackageDesc: ResourcesOut/Hero |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Hero |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Hero |
| | | CollectorGUID: 4ef1d5e33efbd83438f79bd2fd7c44ac |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Materials |
| | | PackageDesc: ResourcesOut/Materials |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Materials |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Materials |
| | | CollectorGUID: 676c8b4532d6ca646804bf73ed43dd96 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Scenes |
| | | PackageDesc: ResourcesOut/Scenes |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Scenes |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Scenes |
| | | CollectorGUID: b3332ee13576c994186d5570af59b0b6 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectScene |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: ScriptableObject |
| | | PackageDesc: ResourcesOut/ScriptableObject |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: ScriptableObject |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/ScriptableObject |
| | | CollectorGUID: 1482db32e9d88d444bc22e54075bf994 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Shader |
| | | PackageDesc: ResourcesOut/Shader |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Shader |
| | | GroupDesc: |
| | | AssetTags: shader |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Shader |
| | | CollectorGUID: 01ad80e2bb073fb46ad906e3572fbe50 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackShader |
| | | FilterRuleName: CollectShader |
| | | AssetTags: shader |
| | | UserData: |
| | | - PackageName: UI |
| | | PackageDesc: ResourcesOut/UI + UIComp + Sprite + Texture + Font |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: UI |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/UI |
| | | CollectorGUID: 0a5282bb472d1144ab08a2d07b5a3801 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: UIComp |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/UIComp |
| | | CollectorGUID: cafb96babf67f0e47aa47d7bd7e851f9 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: Sprite |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Sprite |
| | | CollectorGUID: d525c1ea56911ef46968923700fee47f |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectSpriteAtlas |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: Texture |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Texture |
| | | CollectorGUID: cc4265f3ee528e64e8afa76bd8f7d3f7 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackSeparately |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - GroupName: Font |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Font |
| | | CollectorGUID: 6c72fee81b7c8804dbc80d80a5770197 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackFontAssetGroup |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: UIEffect |
| | | PackageDesc: ResourcesOut/UIEffect |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: UIEffect |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/UIEffect |
| | | CollectorGUID: 62eb3abc624381e4b8950f355812a8e9 |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackDirectory |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | | - PackageName: Video |
| | | PackageDesc: ResourcesOut/Video |
| | | EnableAddressable: 1 |
| | | SupportExtensionless: 1 |
| | | LocationToLower: 0 |
| | | IncludeAssetGUID: 1 |
| | | AutoCollectShaders: 1 |
| | | IgnoreRuleName: NormalIgnoreRule |
| | | Groups: |
| | | - GroupName: Video |
| | | GroupDesc: |
| | | AssetTags: |
| | | ActiveRuleName: EnableGroup |
| | | Collectors: |
| | | - CollectPath: Assets/ResourcesOut/Video |
| | | CollectorGUID: 81c62c4ce41908342a87b93cd29dd7ba |
| | | CollectorType: 0 |
| | | AddressRuleName: AddressByRelativePath |
| | | PackRuleName: PackVideoFile |
| | | FilterRuleName: CollectAll |
| | | AssetTags: |
| | | UserData: |
| | |
| | | using HybridCLR.Editor;
|
| | | using System.Text;
|
| | | using Cysharp.Threading.Tasks;
|
| | | using YooAsset.Editor;
|
| | |
|
| | | namespace UnityEngine.AssetBundles
|
| | | {
|
| | |
| | | EditorApplication.delayCall += ExecuteBuildAll;
|
| | | }
|
| | |
|
| | | EditorGUILayout.BeginHorizontal();
|
| | |
|
| | | if (GUILayout.Button("Prefab"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildConfig;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("UI+UIEffect"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildUI;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("Builtin"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildBuiltIn;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("Audio"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildAudio;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("Video"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildVideo;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("Battle"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildMobEffectShader;
|
| | | }
|
| | |
|
| | | if (GUILayout.Button("Dll(HybridCLR)"))
|
| | | {
|
| | | EditorApplication.delayCall += ExcuteBuildHybridclrUpdate;
|
| | | }
|
| | | EditorGUILayout.EndHorizontal();
|
| | | DrawYooAssetPackageButtons();
|
| | |
|
| | | EditorGUILayout.Space();
|
| | | if (GUILayout.Button("导出到 LocalCDN (D:\\LocalCDN)"))
|
| | |
| | | EditorGUILayout.Space();
|
| | | GUILayout.BeginHorizontal();
|
| | |
|
| | | ClientPackage.includeConfig = EditorGUILayout.Toggle("Include Config ", ClientPackage.includeConfig, GUILayout.Width(250));
|
| | | ClientPackage.includeUI = EditorGUILayout.Toggle("Include UI ", ClientPackage.includeUI, GUILayout.Width(250));
|
| | | ClientPackage.includeConfig = EditorGUILayout.Toggle("Include Config Package", ClientPackage.includeConfig, GUILayout.Width(250));
|
| | | ClientPackage.includeUI = EditorGUILayout.Toggle("Include UI Base Packages", ClientPackage.includeUI, GUILayout.Width(250));
|
| | |
|
| | | GUILayout.EndHorizontal();
|
| | | EditorGUILayout.Space();
|
| | |
| | | YooAssetBuildTool.CopyBuildOutputToLocalCDNFlat();
|
| | | }
|
| | |
|
| | | private static readonly string[] YooAssetPackageButtonOrder =
|
| | | {
|
| | | "Builtin",
|
| | | "Dll",
|
| | | "Config",
|
| | | "Shader",
|
| | | "Materials",
|
| | | "ScriptableObject",
|
| | | "Scenes",
|
| | | "Audio",
|
| | | "Battle",
|
| | | "Hero",
|
| | | "UI",
|
| | | "UIEffect",
|
| | | "Video",
|
| | | };
|
| | |
|
| | | private void DrawYooAssetPackageButtons()
|
| | | {
|
| | | var packageNames = GetYooAssetPackageNames();
|
| | | if (packageNames.Count == 0)
|
| | | {
|
| | | EditorGUILayout.HelpBox("AssetBundleCollectorSetting 中没有配置 YooAsset Package。", MessageType.Warning);
|
| | | return;
|
| | | }
|
| | |
|
| | | EditorGUILayout.LabelField("Build Single Package", EditorStyles.boldLabel);
|
| | | int columns = Mathf.Max(1, Mathf.FloorToInt((EditorGUIUtility.currentViewWidth - 30f) / 155f));
|
| | | for (int i = 0; i < packageNames.Count; i++)
|
| | | {
|
| | | if (i % columns == 0)
|
| | | EditorGUILayout.BeginHorizontal();
|
| | |
|
| | | string packageName = packageNames[i];
|
| | | if (GUILayout.Button(GetYooAssetPackageButtonLabel(packageName)))
|
| | | {
|
| | | string capturedPackageName = packageName;
|
| | | EditorApplication.delayCall += () => ExecuteBuildYooAssetPackage(capturedPackageName);
|
| | | }
|
| | |
|
| | | if (i % columns == columns - 1 || i == packageNames.Count - 1)
|
| | | EditorGUILayout.EndHorizontal();
|
| | | }
|
| | | }
|
| | |
|
| | | private List<string> GetYooAssetPackageNames()
|
| | | {
|
| | | var result = new List<string>();
|
| | | var setting = AssetBundleCollectorSettingData.Setting;
|
| | | if (setting == null || setting.Packages == null)
|
| | | return result;
|
| | |
|
| | | foreach (var packageName in YooAssetPackageButtonOrder)
|
| | | {
|
| | | if (HasYooAssetPackage(setting, packageName))
|
| | | result.Add(packageName);
|
| | | }
|
| | |
|
| | | foreach (var package in setting.Packages)
|
| | | {
|
| | | if (package == null || string.IsNullOrEmpty(package.PackageName))
|
| | | continue;
|
| | |
|
| | | if (!ContainsPackageName(result, package.PackageName))
|
| | | result.Add(package.PackageName);
|
| | | }
|
| | |
|
| | | return result;
|
| | | }
|
| | |
|
| | | private static bool HasYooAssetPackage(AssetBundleCollectorSetting setting, string packageName)
|
| | | {
|
| | | foreach (var package in setting.Packages)
|
| | | {
|
| | | if (package != null && string.Equals(package.PackageName, packageName, StringComparison.OrdinalIgnoreCase))
|
| | | return true;
|
| | | }
|
| | |
|
| | | return false;
|
| | | }
|
| | |
|
| | | private static bool ContainsPackageName(List<string> packageNames, string packageName)
|
| | | {
|
| | | foreach (var item in packageNames)
|
| | | {
|
| | | if (string.Equals(item, packageName, StringComparison.OrdinalIgnoreCase))
|
| | | return true;
|
| | | }
|
| | |
|
| | | return false;
|
| | | }
|
| | |
|
| | | private static string GetYooAssetPackageButtonLabel(string packageName)
|
| | | {
|
| | | return string.Equals(packageName, "Dll", StringComparison.OrdinalIgnoreCase) ? "Dll(HybridCLR)" : packageName;
|
| | | }
|
| | |
|
| | | private void ExecuteBuildYooAssetPackage(string packageName)
|
| | | {
|
| | | if (string.Equals(packageName, "Builtin", StringComparison.OrdinalIgnoreCase))
|
| | | {
|
| | | ExcuteBuildBuiltIn();
|
| | | }
|
| | | else if (string.Equals(packageName, "Dll", StringComparison.OrdinalIgnoreCase))
|
| | | {
|
| | | ExcuteBuildHybridclrUpdate();
|
| | | }
|
| | | else
|
| | | {
|
| | | ExcuteBuildAsset(packageName);
|
| | | }
|
| | | }
|
| | |
|
| | | private void ExcuteBuildAsset(string yooPackageName)
|
| | | {
|
| | | string version = YooAssetBuildTool.GenerateVersion();
|
| | |
| | |
|
| | | if (ok)
|
| | | {
|
| | | YooAssetBuildTool.CopyStartupConfigsToStreamingAssets();
|
| | | Debug.Log($"[AssetBundleBuildTab] Package '{yooPackageName}' 打包成功!");
|
| | | bool copied = YooAssetBuildTool.CopySinglePackageBuildOutput(yooPackageName, m_UserData.m_OutputPath, version);
|
| | | if (copied)
|
| | | Debug.Log($"[AssetBundleBuildTab] Package '{yooPackageName}' 打包并拷贝成功!");
|
| | | else
|
| | | Debug.LogError($"[AssetBundleBuildTab] Package '{yooPackageName}' 打包成功,但拷贝到 StreamingAssets/外部资源目录失败!");
|
| | | }
|
| | | else
|
| | | {
|
| | |
| | |
|
| | | private void ExcuteBuildConfig()
|
| | | {
|
| | | ExcuteBuildAsset("Prefab");
|
| | | ExcuteBuildAsset("Config");
|
| | | }
|
| | |
|
| | | //发包时获取热更dll和裁剪AOT
|
| | |
| | | return;
|
| | | }
|
| | |
|
| | | if (!YooAssetBuildTool.CopySinglePackageBuildOutput("Dll", m_UserData.m_OutputPath, version))
|
| | | {
|
| | | Debug.LogError("[AssetBundleBuildTab] Dll Package 打包成功,但拷贝到 StreamingAssets/外部资源目录失败!");
|
| | | return;
|
| | | }
|
| | |
|
| | | AssetDatabase.Refresh();
|
| | | Debug.Log("[AssetBundleBuildTab] 热更新 DLL 增量打包完成。");
|
| | | Debug.Log("[AssetBundleBuildTab] 热更新 DLL 增量打包并拷贝完成。");
|
| | | }
|
| | |
|
| | |
|
| | |
| | |
|
| | | private void ExcuteBuildLevels()
|
| | | {
|
| | | // Scenes 在 YooAsset 的 Prefab Package 中
|
| | | ExcuteBuildAsset("Prefab");
|
| | | ExcuteBuildAsset("Scenes");
|
| | | }
|
| | |
|
| | | private void ExcuteBuildUI()
|
| | | {
|
| | | // UI 和 UIEffect 是两个独立 Package
|
| | | ExcuteBuildAsset("UI");
|
| | | ExcuteBuildAsset("UIEffect");
|
| | | }
|
| | |
| | | {
|
| | | continue;
|
| | | }
|
| | | if (fileInfo.Name.EndsWith("OPConfig.txt", StringComparison.OrdinalIgnoreCase))
|
| | | if (AssetVersionUtility.IsOPConfigFileName(fileInfo.Name))
|
| | | {
|
| | | continue;
|
| | | }
|
| | |
| | | {
|
| | | continue;
|
| | | }
|
| | | if (fileInfo.Name.EndsWith("OPConfig.txt", StringComparison.OrdinalIgnoreCase))
|
| | | if (AssetVersionUtility.IsOPConfigFileName(fileInfo.Name))
|
| | | {
|
| | | continue;
|
| | | }
|
| | |
| | | public static readonly string versionsFilePath = Application.dataPath + "/Editor/VersionConfigs/Versions.txt";
|
| | | public static readonly string[] baseLevels = new string[] { "Assets/Resources/Scenes/Launch.unity" };
|
| | | private static readonly string[] LaunchRequiredYooPackages = { "Builtin", "Dll" };
|
| | | private static readonly string[] YooAssetNoCompressExtensions = { ".unity3d", ".bundle", ".bytes", ".hash", ".version", ".json", ".txt" };
|
| | |
|
| | | public static string auditOutTime = string.Empty;
|
| | |
|
| | |
| | | // ---- HalfAsset(中包):剔除部分 Package ----
|
| | | if (halfPackages.Count > 0)
|
| | | {
|
| | | // 按旧逻辑映射:hero→Battle, audio→Audio, video→Video, uieffect→UIEffect
|
| | | var removePackages = new List<string> { "Battle", "Audio", "Video", "UIEffect" };
|
| | | if (!includeUI) removePackages.Add("UI");
|
| | | var removePackages = CreateHalfAssetRemovePackages();
|
| | |
|
| | | foreach (var pkgName in removePackages)
|
| | | {
|
| | |
| | | // File.Copy(copySdkFile, File_google_services);
|
| | | copySdkFile = StringUtility.Concat(_sdkPath, "/Channel/Android/", versionConfig.sdkFileName, "/gradleTemplate.properties");
|
| | | File.Copy(copySdkFile, File_gradleTemplate);
|
| | | EnsureYooAssetNoCompressExtensions(File_gradleTemplate);
|
| | | copySdkFile = StringUtility.Concat(_sdkPath, "/Channel/Android/", versionConfig.sdkFileName, "/LauncherManifest.xml");
|
| | | File.Copy(copySdkFile, File_LauncherManifest);
|
| | | copySdkFile = StringUtility.Concat(_sdkPath, "/Channel/Android/", versionConfig.sdkFileName, "/launcherTemplate.gradle");
|
| | |
| | | Debug.Log("[ClientPackage] NullAsset Export: 已清空 StreamingAssets/yoo");
|
| | | break;
|
| | | case InstalledAsset.HalfAsset:
|
| | | var removePackages = new List<string> { "Battle", "Audio", "Video", "UIEffect" };
|
| | | if (!includeUI) removePackages.Add("UI");
|
| | | var removePackages = CreateHalfAssetRemovePackages();
|
| | | foreach (var pkgName in removePackages)
|
| | | {
|
| | | string pkgDir = Path.Combine(yooRoot, pkgName);
|
| | |
| | |
|
| | | File.Copy(item.FullName, to, true);
|
| | | }
|
| | | }
|
| | |
|
| | | static bool IsOPConfigFile(FileInfo file)
|
| | | {
|
| | | return file.Name.EndsWith("OPConfig.txt", StringComparison.OrdinalIgnoreCase);
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | |
| | |
|
| | | foreach (var item in fromFiles)
|
| | | {
|
| | | if (IsOPConfigFile(item))
|
| | | if (AssetVersionUtility.IsOPConfigFileName(item.Name))
|
| | | continue;
|
| | |
|
| | | var extension = Path.GetExtension(item.FullName);
|
| | |
| | | FileExtersion.GetAllDirectoryFileInfos(_assetBundlePath, files);
|
| | | foreach (var file in files)
|
| | | {
|
| | | if (IsOPConfigFile(file))
|
| | | if (AssetVersionUtility.IsOPConfigFileName(file.Name))
|
| | | continue;
|
| | |
|
| | | var extension = Path.GetExtension(file.FullName);
|
| | |
| | | {
|
| | | Debug.Log("[ClientPackage] 恢复 YooAsset StreamingAssets 到完整状态...");
|
| | | YooAssetBuildTool.RestoreBuildOutputToStreamingAssets();
|
| | | }
|
| | |
|
| | | private static List<string> CreateHalfAssetRemovePackages()
|
| | | {
|
| | | var removePackages = new List<string> { "Battle", "Hero", "Audio", "Video", "UIEffect" };
|
| | | if (!includeUI)
|
| | | {
|
| | | removePackages.Add("UI");
|
| | | removePackages.Add("UIComp");
|
| | | removePackages.Add("Sprite");
|
| | | removePackages.Add("Texture");
|
| | | removePackages.Add("Font");
|
| | | }
|
| | |
|
| | | return removePackages;
|
| | | }
|
| | |
|
| | | //随包安装的资源不同平台不一定可以获取FileInfo,所以需要下载一个文件来获取资源的MD5信息
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | static void EnsureYooAssetNoCompressExtensions(string gradleTemplatePath)
|
| | | {
|
| | | if (!File.Exists(gradleTemplatePath))
|
| | | {
|
| | | Debug.LogWarning($"[ClientPackage] gradleTemplate.properties not found: {gradleTemplatePath}");
|
| | | return;
|
| | | }
|
| | |
|
| | | string text = File.ReadAllText(gradleTemplatePath);
|
| | | var lineRegex = new Regex(@"(?m)^unityStreamingAssets\s*=\s*(.*)$");
|
| | | var match = lineRegex.Match(text);
|
| | | var extensions = new List<string>();
|
| | | var extensionSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
| | |
|
| | | if (match.Success)
|
| | | {
|
| | | foreach (var value in match.Groups[1].Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
| | | {
|
| | | var extension = value.Trim();
|
| | | if (extension.Length > 0 && extensionSet.Add(extension))
|
| | | extensions.Add(extension);
|
| | | }
|
| | | }
|
| | |
|
| | | foreach (var extension in YooAssetNoCompressExtensions)
|
| | | {
|
| | | if (extensionSet.Add(extension))
|
| | | extensions.Add(extension);
|
| | | }
|
| | |
|
| | | string newLine = "unityStreamingAssets=" + string.Join(",", extensions);
|
| | | text = match.Success
|
| | | ? lineRegex.Replace(text, newLine, 1)
|
| | | : text.TrimEnd() + Environment.NewLine + newLine + Environment.NewLine;
|
| | |
|
| | | File.WriteAllText(gradleTemplatePath, text, new UTF8Encoding(false));
|
| | | Debug.Log($"[ClientPackage] Ensured Android noCompress extensions: {newLine}");
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// 导出 Gradle 工程前清理 Assets/Plugins/Android(保留 libs 目录)
|
| | | /// </summary>
|
| | |
| | | set { LocalSave.SetBool("obfuscatorEnabled", value); } |
| | | } |
| | | |
| | | static bool IsOPConfigFile(FileInfo file) |
| | | { |
| | | return file.Name.EndsWith("OPConfig.txt", StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | static bool IsBuiltinFile(FileInfo file) |
| | | { |
| | | if (file.FullName.IndexOf("builtin", StringComparison.OrdinalIgnoreCase) >= 0) |
| | |
| | | |
| | | foreach (var item in fromFiles) |
| | | { |
| | | if (IsOPConfigFile(item)) |
| | | if (AssetVersionUtility.IsOPConfigFileName(item.Name)) |
| | | { |
| | | continue; |
| | | } |
| | |
| | | FileExtersion.GetAllDirectoryFileInfos(assetPath, fromFiles); |
| | | foreach (var item in fromFiles) |
| | | { |
| | | if (IsOPConfigFile(item)) |
| | | if (AssetVersionUtility.IsOPConfigFileName(item.Name)) |
| | | { |
| | | continue; |
| | | } |
| | |
| | | using System; |
| | | using System.IO; |
| | | using YooAsset.Editor; |
| | | |
| | |
| | | { |
| | | public bool IsCollectAsset(FilterRuleData data) |
| | | { |
| | | return !Path.GetFileName(data.AssetPath).EndsWith("OPConfig.txt", StringComparison.OrdinalIgnoreCase); |
| | | return !AssetVersionUtility.IsOPConfigFileName(Path.GetFileName(data.AssetPath)); |
| | | } |
| | | } |
| | |
| | | public static class CollectResBeforeUpdate |
| | | { |
| | | private const string BuiltinPackageName = "Builtin"; |
| | | private const string PrefabPackageName = "Prefab"; |
| | | private const string BuiltInGroupName = "BuiltIn"; |
| | | 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"; |
| | |
| | | BuiltInRoot + "/Sprites/TY_TB_JH2.png", |
| | | BuiltInRoot + "/Sprites/LoadingBottom.png", |
| | | BuiltInRoot + "/Sprites/LoadingSlider.png", |
| | | BuiltInRoot + "/Sprites/sprites.spriteatlasv2", |
| | | }; |
| | | |
| | | private static readonly string[] BuiltinConfigPaths = |
| | |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Package: {BuiltinPackageName}"); |
| | | } |
| | | |
| | | var builtInGroup = builtinPackage.Groups.Find(item => item.GroupName == BuiltInGroupName); |
| | | if (builtInGroup == null) |
| | | { |
| | | builtInGroup = AssetBundleCollectorSettingData.CreateGroup(builtinPackage, BuiltInGroupName); |
| | | changed = true; |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Group: {BuiltInGroupName}"); |
| | | } |
| | | |
| | | changed |= EnsureCollector(builtInGroup, BuiltInRoot, nameof(PackDirectory), CollectBuiltinAfterUpdateRuleName); |
| | | |
| | | var group = builtinPackage.Groups.Find(item => item.GroupName == GroupName); |
| | | if (group == null) |
| | | { |
| | |
| | | Debug.Log($"[CollectResBeforeUpdate] 创建 Group: {GroupName}"); |
| | | } |
| | | |
| | | changed |= RemoveObsoleteBuiltinRootCollectors(builtinPackage); |
| | | changed |= RemoveDuplicateBeforeUpdateCollectors(setting, builtinPackage, group); |
| | | foreach (var assetPath in BeforeUpdateBuiltinAssetPaths) |
| | | { |
| | |
| | | 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 包收集。"); |
| | | Debug.Log("[CollectResBeforeUpdate] 热更前资源收集配置已同步。Builtin 包包含 BuiltIn 整目录,并保留 Launch 白名单资源。"); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | |
| | | 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( |
| New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.IO; |
| | | using System.Reflection; |
| | | using UnityEditor; |
| | | using YooAsset.Editor; |
| | | |
| | | [DisplayName("收集SpriteAtlas图集")] |
| | | public class CollectSpriteAtlas : IFilterRule |
| | | { |
| | | public bool IsCollectAsset(FilterRuleData data) |
| | | { |
| | | var extension = Path.GetExtension(data.AssetPath); |
| | | return string.Equals(extension, ".spriteatlasv2", System.StringComparison.OrdinalIgnoreCase) |
| | | || string.Equals(extension, ".spriteatlas", System.StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | } |
| | | |
| | | [InitializeOnLoad] |
| | | public static class YooAssetCustomFilterRuleRegistry |
| | | { |
| | | static YooAssetCustomFilterRuleRegistry() |
| | | { |
| | | EditorApplication.delayCall -= Register; |
| | | EditorApplication.delayCall += Register; |
| | | } |
| | | |
| | | private static void Register() |
| | | { |
| | | RegisterFilterRule<CollectSpriteAtlas>(); |
| | | } |
| | | |
| | | private static void RegisterFilterRule<T>() where T : IFilterRule |
| | | { |
| | | var fieldInfo = typeof(AssetBundleCollectorSettingData).GetField( |
| | | "_cacheFilterRuleTypes", |
| | | BindingFlags.Static | BindingFlags.NonPublic); |
| | | |
| | | var cache = fieldInfo?.GetValue(null) as Dictionary<string, Type>; |
| | | if (cache == null) |
| | | return; |
| | | |
| | | cache[typeof(T).Name] = typeof(T); |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 0172787988c69a84db1d38139c18f351 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| New file |
| | |
| | | using System; |
| | | using System.IO; |
| | | using YooAsset.Editor; |
| | | |
| | | [DisplayName("资源包名: 字体资源组")] |
| | | public class PackFontAssetGroup : IPackRule |
| | | { |
| | | PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) |
| | | { |
| | | var assetPath = NormalizePath(data.AssetPath); |
| | | var directory = NormalizePath(Path.GetDirectoryName(assetPath)); |
| | | var baseName = GetFontBaseName(assetPath); |
| | | var bundleName = string.IsNullOrEmpty(baseName) |
| | | ? EditorTools.RemoveExtension(assetPath) |
| | | : $"{directory}/{baseName}"; |
| | | |
| | | return new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); |
| | | } |
| | | |
| | | private static string GetFontBaseName(string assetPath) |
| | | { |
| | | var extension = Path.GetExtension(assetPath); |
| | | if (string.Equals(extension, ".ttf", StringComparison.OrdinalIgnoreCase)) |
| | | return Path.GetFileNameWithoutExtension(assetPath); |
| | | |
| | | var fileName = Path.GetFileNameWithoutExtension(assetPath); |
| | | return StripTrailingAtlasPage(fileName); |
| | | } |
| | | |
| | | private static string StripTrailingAtlasPage(string fileName) |
| | | { |
| | | var underscoreIndex = fileName.LastIndexOf('_'); |
| | | if (underscoreIndex < 0 || underscoreIndex == fileName.Length - 1) |
| | | return fileName; |
| | | |
| | | for (var index = underscoreIndex + 1; index < fileName.Length; index++) |
| | | { |
| | | if (!char.IsDigit(fileName[index])) |
| | | return fileName; |
| | | } |
| | | |
| | | return fileName.Substring(0, underscoreIndex); |
| | | } |
| | | |
| | | private static string NormalizePath(string path) |
| | | { |
| | | return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/'); |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6a82435e7e7ab7b49927a640f82f875a |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.IO; |
| | | using YooAsset.Editor; |
| | | |
| | | [DisplayName("资源包名: Spine资源组")] |
| | | public class PackSpineAssetGroup : IPackRule |
| | | { |
| | | private const string SkeletonDataSuffix = "_SkeletonData"; |
| | | private static readonly Dictionary<string, List<string>> SkeletonBaseCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); |
| | | |
| | | PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) |
| | | { |
| | | var assetPath = NormalizePath(data.AssetPath); |
| | | var directory = NormalizePath(Path.GetDirectoryName(assetPath)); |
| | | var spineBaseName = FindSpineBaseName(directory, assetPath); |
| | | var bundleName = string.IsNullOrEmpty(spineBaseName) |
| | | ? EditorTools.RemoveExtension(assetPath) |
| | | : $"{directory}/{spineBaseName}"; |
| | | |
| | | return new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); |
| | | } |
| | | |
| | | private static string FindSpineBaseName(string directory, string assetPath) |
| | | { |
| | | if (string.IsNullOrEmpty(directory)) |
| | | return string.Empty; |
| | | |
| | | var fileName = Path.GetFileNameWithoutExtension(assetPath); |
| | | var bestMatch = string.Empty; |
| | | foreach (var baseName in GetSkeletonBaseNames(directory)) |
| | | { |
| | | if (!IsSameSpineResource(fileName, baseName)) |
| | | continue; |
| | | |
| | | if (baseName.Length > bestMatch.Length) |
| | | bestMatch = baseName; |
| | | } |
| | | |
| | | return bestMatch; |
| | | } |
| | | |
| | | private static bool IsSameSpineResource(string fileName, string baseName) |
| | | { |
| | | return string.Equals(fileName, baseName, StringComparison.OrdinalIgnoreCase) |
| | | || fileName.StartsWith(baseName + "_", StringComparison.OrdinalIgnoreCase) |
| | | || fileName.StartsWith(baseName + ".", StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static List<string> GetSkeletonBaseNames(string directory) |
| | | { |
| | | if (SkeletonBaseCache.TryGetValue(directory, out var cached)) |
| | | return cached; |
| | | |
| | | var result = new List<string>(); |
| | | if (Directory.Exists(directory)) |
| | | { |
| | | foreach (var filePath in Directory.GetFiles(directory, "*" + SkeletonDataSuffix + ".asset", SearchOption.TopDirectoryOnly)) |
| | | { |
| | | var fileName = Path.GetFileNameWithoutExtension(filePath); |
| | | if (fileName.EndsWith(SkeletonDataSuffix, StringComparison.OrdinalIgnoreCase)) |
| | | result.Add(fileName.Substring(0, fileName.Length - SkeletonDataSuffix.Length)); |
| | | } |
| | | } |
| | | |
| | | SkeletonBaseCache[directory] = result; |
| | | return result; |
| | | } |
| | | |
| | | private static string NormalizePath(string path) |
| | | { |
| | | return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/'); |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 4145f25573e3ea84dbaeadb7ba012550 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| New file |
| | |
| | | using System; |
| | | using System.IO; |
| | | using YooAsset.Editor; |
| | | |
| | | [DisplayName("资源包名: 收集器下二级文件夹路径")] |
| | | public class PackTopDirectorySubDirectory : IPackRule |
| | | { |
| | | PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) |
| | | { |
| | | var assetPath = NormalizePath(data.AssetPath); |
| | | var collectPath = NormalizePath(data.CollectPath).TrimEnd('/'); |
| | | var relativePath = GetRelativeAssetPath(assetPath, collectPath); |
| | | var segments = relativePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); |
| | | |
| | | if (segments.Length == 0 || Path.HasExtension(segments[0])) |
| | | throw new Exception($"Not found top directory : {relativePath}"); |
| | | |
| | | var bundleName = GetBundleName(collectPath, segments); |
| | | return new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); |
| | | } |
| | | |
| | | private static string GetBundleName(string collectPath, string[] segments) |
| | | { |
| | | if (segments.Length >= 2 && !Path.HasExtension(segments[1])) |
| | | return $"{collectPath}/{segments[0]}/{segments[1]}"; |
| | | |
| | | return $"{collectPath}/{segments[0]}"; |
| | | } |
| | | |
| | | private static string GetRelativeAssetPath(string assetPath, string collectPath) |
| | | { |
| | | if (string.IsNullOrEmpty(collectPath)) |
| | | return assetPath.TrimStart('/'); |
| | | |
| | | if (assetPath.Equals(collectPath, StringComparison.OrdinalIgnoreCase)) |
| | | return string.Empty; |
| | | |
| | | if (assetPath.StartsWith(collectPath + "/", StringComparison.OrdinalIgnoreCase)) |
| | | return assetPath.Substring(collectPath.Length + 1); |
| | | |
| | | return assetPath; |
| | | } |
| | | |
| | | private static string NormalizePath(string path) |
| | | { |
| | | return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/'); |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: a6553361f76f01840a08ad8ea9d67356 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.IO; |
| | | using YooAsset.Editor; |
| | | |
| | | [DisplayName("资源包名: UI特效资源组")] |
| | | public class PackUIEffectAssetGroup : IPackRule |
| | | { |
| | | private const string SkeletonDataSuffix = "_SkeletonData"; |
| | | private const string UnityEffectRoot = "Assets/ResourcesOut/UIEffect/Unity"; |
| | | private static readonly Dictionary<string, List<string>> SkeletonBaseCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); |
| | | private static readonly Dictionary<string, string> SinglePrefabCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); |
| | | |
| | | PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) |
| | | { |
| | | var assetPath = NormalizePath(data.AssetPath); |
| | | var directory = NormalizePath(Path.GetDirectoryName(assetPath)); |
| | | var bundleName = IsUnityEffectAsset(assetPath) |
| | | ? GetUnityEffectBundleName(directory, assetPath) |
| | | : GetSpineBundleName(directory, assetPath); |
| | | |
| | | return new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); |
| | | } |
| | | |
| | | private static string GetSpineBundleName(string directory, string assetPath) |
| | | { |
| | | var spineBaseName = FindSpineBaseName(directory, assetPath); |
| | | return string.IsNullOrEmpty(spineBaseName) |
| | | ? EditorTools.RemoveExtension(assetPath) |
| | | : $"{directory}/{spineBaseName}"; |
| | | } |
| | | |
| | | private static string GetUnityEffectBundleName(string directory, string assetPath) |
| | | { |
| | | var singlePrefabPath = FindSinglePrefabPath(directory); |
| | | if (!string.IsNullOrEmpty(singlePrefabPath)) |
| | | return EditorTools.RemoveExtension(singlePrefabPath); |
| | | |
| | | return EditorTools.RemoveExtension(assetPath); |
| | | } |
| | | |
| | | private static string FindSpineBaseName(string directory, string assetPath) |
| | | { |
| | | if (string.IsNullOrEmpty(directory)) |
| | | return string.Empty; |
| | | |
| | | var fileName = Path.GetFileNameWithoutExtension(assetPath); |
| | | var bestMatch = string.Empty; |
| | | foreach (var baseName in GetSkeletonBaseNames(directory)) |
| | | { |
| | | if (!IsSameSpineResource(fileName, baseName)) |
| | | continue; |
| | | |
| | | if (baseName.Length > bestMatch.Length) |
| | | bestMatch = baseName; |
| | | } |
| | | |
| | | return bestMatch; |
| | | } |
| | | |
| | | private static bool IsSameSpineResource(string fileName, string baseName) |
| | | { |
| | | return string.Equals(fileName, baseName, StringComparison.OrdinalIgnoreCase) |
| | | || fileName.StartsWith(baseName + "_", StringComparison.OrdinalIgnoreCase) |
| | | || fileName.StartsWith(baseName + ".", StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static List<string> GetSkeletonBaseNames(string directory) |
| | | { |
| | | if (SkeletonBaseCache.TryGetValue(directory, out var cached)) |
| | | return cached; |
| | | |
| | | var result = new List<string>(); |
| | | if (Directory.Exists(directory)) |
| | | { |
| | | foreach (var filePath in Directory.GetFiles(directory, "*" + SkeletonDataSuffix + ".asset", SearchOption.TopDirectoryOnly)) |
| | | { |
| | | var fileName = Path.GetFileNameWithoutExtension(filePath); |
| | | if (fileName.EndsWith(SkeletonDataSuffix, StringComparison.OrdinalIgnoreCase)) |
| | | result.Add(fileName.Substring(0, fileName.Length - SkeletonDataSuffix.Length)); |
| | | } |
| | | } |
| | | |
| | | SkeletonBaseCache[directory] = result; |
| | | return result; |
| | | } |
| | | |
| | | private static string FindSinglePrefabPath(string directory) |
| | | { |
| | | if (SinglePrefabCache.TryGetValue(directory, out var cached)) |
| | | return cached; |
| | | |
| | | var result = string.Empty; |
| | | if (Directory.Exists(directory)) |
| | | { |
| | | foreach (var prefabPath in Directory.GetFiles(directory, "*.prefab", SearchOption.TopDirectoryOnly)) |
| | | { |
| | | if (!string.IsNullOrEmpty(result)) |
| | | { |
| | | result = string.Empty; |
| | | break; |
| | | } |
| | | |
| | | result = NormalizePath(prefabPath); |
| | | } |
| | | } |
| | | |
| | | SinglePrefabCache[directory] = result; |
| | | return result; |
| | | } |
| | | |
| | | private static bool IsUnityEffectAsset(string assetPath) |
| | | { |
| | | return IsSameAssetPath(assetPath, UnityEffectRoot) || assetPath.StartsWith(UnityEffectRoot + "/", StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static bool IsSameAssetPath(string lhs, string rhs) |
| | | { |
| | | return NormalizePath(lhs).TrimEnd('/').Equals(NormalizePath(rhs).TrimEnd('/'), StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static string NormalizePath(string path) |
| | | { |
| | | return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/'); |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 9f2c76b7cf0d4d44ba0c121e5a18f3d4 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| | |
| | | |
| | | public static class YooAssetBuildTool |
| | | { |
| | | /// <summary> |
| | | /// 所有需要打包的 Package 名称(与 AssetBundleCollectorSetting 一致) |
| | | /// </summary> |
| | | private static readonly string[] ALL_PACKAGES = { "Prefab", "UI", "UIEffect", "Battle", "Audio", "Video", "Builtin", "Dll" }; |
| | | private static string[] GetAllPackageNames() |
| | | { |
| | | var setting = AssetBundleCollectorSettingData.Setting; |
| | | if (setting == null || setting.Packages == null) |
| | | { |
| | | return Array.Empty<string>(); |
| | | } |
| | | |
| | | var packageNames = new System.Collections.Generic.List<string>(); |
| | | foreach (var package in setting.Packages) |
| | | { |
| | | if (package == null || string.IsNullOrEmpty(package.PackageName)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | packageNames.Add(package.PackageName); |
| | | } |
| | | |
| | | return packageNames.ToArray(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// HybridCLR .bytes 文件输出目录(相对 Assets) |
| | |
| | | |
| | | private static void BuildAllPackagesInternal(bool incremental) |
| | | { |
| | | string[] allPackages = GetAllPackageNames(); |
| | | if (allPackages.Length == 0) |
| | | { |
| | | EditorUtility.DisplayDialog("打包失败", "AssetBundleCollectorSetting 中没有配置任何 Package。", "确定"); |
| | | return; |
| | | } |
| | | |
| | | string modeDesc = incremental ? "增量打包(跳过HybridCLR,复用版本号)" : "全量打包"; |
| | | if (!EditorUtility.DisplayDialog("确认打包", |
| | | $"模式: {modeDesc}\n" + |
| | | $"将使用 BuiltinBuildPipeline 打包以下 {ALL_PACKAGES.Length} 个 Package:\n" + |
| | | $"{string.Join(", ", ALL_PACKAGES)}\n\n" + |
| | | $"将使用 BuiltinBuildPipeline 打包以下 {allPackages.Length} 个 Package:\n" + |
| | | $"{string.Join(", ", allPackages)}\n\n" + |
| | | $"平台: {EditorUserBuildSettings.activeBuildTarget}\n" + |
| | | $"输出: {AssetBundleBuilderHelper.GetDefaultBuildOutputRoot()}\n" + |
| | | $"并自动拷贝到 StreamingAssets\n\n是否继续?", |
| | |
| | | } |
| | | } |
| | | |
| | | string[] allPackages = GetAllPackageNames(); |
| | | if (allPackages.Length == 0) |
| | | { |
| | | Debug.LogError("[YooAssetBuildTool] AssetBundleCollectorSetting 中没有配置任何 Package,无法打包。 "); |
| | | return false; |
| | | } |
| | | |
| | | // 增量模式复用上次版本号,避免 YooAsset 认为全新版本 |
| | | string version; |
| | | if (incremental) |
| | | { |
| | | string lastVer = GetLastBuildVersion(ALL_PACKAGES[0]); |
| | | string lastVer = GetLastBuildVersion(allPackages[0]); |
| | | version = !string.IsNullOrEmpty(lastVer) ? lastVer : GenerateVersion(); |
| | | Debug.Log($"[YooAssetBuildTool] 增量模式,复用版本号: {version}"); |
| | | } |
| | |
| | | |
| | | ClearStreamingAssetsYooDirectory(); |
| | | |
| | | for (int i = 0; i < ALL_PACKAGES.Length; i++) |
| | | for (int i = 0; i < allPackages.Length; i++) |
| | | { |
| | | string pkgName = ALL_PACKAGES[i]; |
| | | string pkgName = allPackages[i]; |
| | | EditorUtility.DisplayProgressBar("YooAsset 打包中...", |
| | | $"正在打包 {pkgName} ({i + 1}/{ALL_PACKAGES.Length})", |
| | | (float)i / ALL_PACKAGES.Length); |
| | | $"正在打包 {pkgName} ({i + 1}/{allPackages.Length})", |
| | | (float)i / allPackages.Length); |
| | | |
| | | bool ok = BuildSinglePackage(pkgName, version); |
| | | if (ok) |
| | |
| | | System.IO.Directory.CreateDirectory(destFullPath); |
| | | |
| | | int copiedCount = 0; |
| | | foreach (var packageName in ALL_PACKAGES) |
| | | foreach (var packageName in GetAllPackageNames()) |
| | | { |
| | | string sourcePackageDir = System.IO.Path.Combine(sourceFullPath, packageName); |
| | | if (!System.IO.Directory.Exists(sourcePackageDir)) |
| | |
| | | return true; |
| | | } |
| | | |
| | | public static bool CopySinglePackageBuildOutput(string packageName, string outputPath = null, string version = null) |
| | | { |
| | | if (string.IsNullOrEmpty(packageName)) |
| | | { |
| | | Debug.LogError("[YooAssetBuildTool] Package 名为空,无法拷贝单包构建产物。"); |
| | | return false; |
| | | } |
| | | |
| | | bool success = true; |
| | | string streamingYooRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(); |
| | | if (!CopyPackageBuildOutputToYooDirectory(packageName, streamingYooRoot, version, "StreamingAssets")) |
| | | { |
| | | success = false; |
| | | } |
| | | |
| | | if (!CopyStartupConfigsToStreamingAssets()) |
| | | { |
| | | success = false; |
| | | } |
| | | |
| | | if (!string.IsNullOrWhiteSpace(outputPath)) |
| | | { |
| | | string destYooRoot = ResolveYooOutputDirectory(outputPath); |
| | | string streamingFullPath = NormalizeFullPath(streamingYooRoot); |
| | | string destFullPath = NormalizeFullPath(destYooRoot); |
| | | if (string.Equals(streamingFullPath, destFullPath, StringComparison.OrdinalIgnoreCase)) |
| | | { |
| | | Debug.LogWarning($"[YooAssetBuildTool] 单包外部输出目录与 StreamingAssets 相同,跳过重复拷贝: {destFullPath}"); |
| | | } |
| | | else |
| | | { |
| | | if (!CopyPackageBuildOutputToYooDirectory(packageName, destYooRoot, version, "外部资源目录")) |
| | | { |
| | | success = false; |
| | | } |
| | | |
| | | if (!CopyStartupConfigsToYooDirectory(destYooRoot)) |
| | | { |
| | | success = false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return success; |
| | | } |
| | | |
| | | private static bool CopyPackageBuildOutputToYooDirectory(string packageName, string targetYooRoot, string version, string targetName) |
| | | { |
| | | string sourceDir = GetPackageBuildOutputDirectory(packageName, version); |
| | | if (string.IsNullOrEmpty(sourceDir)) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | string sourceFullPath = NormalizeFullPath(sourceDir); |
| | | string targetFullPath = NormalizeFullPath(targetYooRoot); |
| | | if (targetFullPath.StartsWith(sourceFullPath + "/", StringComparison.OrdinalIgnoreCase)) |
| | | { |
| | | Debug.LogError($"[YooAssetBuildTool] {targetName} 目录不能位于构建产物目录内部: {targetFullPath}"); |
| | | return false; |
| | | } |
| | | |
| | | DeleteObsoletePackageDirectories(targetFullPath); |
| | | |
| | | string destPackageDir = System.IO.Path.Combine(targetFullPath, packageName); |
| | | if (System.IO.Directory.Exists(destPackageDir)) |
| | | { |
| | | System.IO.Directory.Delete(destPackageDir, true); |
| | | } |
| | | |
| | | int copiedCount = CopyDirectoryFiles(sourceFullPath, destPackageDir); |
| | | Debug.Log($"[YooAssetBuildTool] 已拷贝 Package '{packageName}' 到{targetName}: {copiedCount} 个文件,from={sourceFullPath}, to={destPackageDir}"); |
| | | return true; |
| | | } |
| | | |
| | | private static string GetPackageBuildOutputDirectory(string packageName, string version) |
| | | { |
| | | string buildRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot(); |
| | | string platform = EditorUserBuildSettings.activeBuildTarget.ToString(); |
| | | string packageRoot = System.IO.Path.Combine(buildRoot, platform, packageName); |
| | | if (!System.IO.Directory.Exists(packageRoot)) |
| | | { |
| | | Debug.LogError($"[YooAssetBuildTool] Package 构建输出目录不存在: {packageRoot}"); |
| | | return null; |
| | | } |
| | | |
| | | if (!string.IsNullOrEmpty(version)) |
| | | { |
| | | string versionDir = System.IO.Path.Combine(packageRoot, version); |
| | | if (System.IO.Directory.Exists(versionDir)) |
| | | { |
| | | return versionDir; |
| | | } |
| | | |
| | | Debug.LogWarning($"[YooAssetBuildTool] 指定版本目录不存在,将使用最新版本目录: {versionDir}"); |
| | | } |
| | | |
| | | var versionDirs = new System.Collections.Generic.List<string>(); |
| | | foreach (var dir in System.IO.Directory.GetDirectories(packageRoot)) |
| | | { |
| | | string dirName = System.IO.Path.GetFileName(dir); |
| | | if (dirName == "OutputCache" || dirName == "Simulate") |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | versionDirs.Add(dir); |
| | | } |
| | | |
| | | if (versionDirs.Count == 0) |
| | | { |
| | | Debug.LogError($"[YooAssetBuildTool] Package '{packageName}' 没有可用的版本目录: {packageRoot}"); |
| | | return null; |
| | | } |
| | | |
| | | versionDirs.Sort(StringComparer.OrdinalIgnoreCase); |
| | | return versionDirs[versionDirs.Count - 1]; |
| | | } |
| | | |
| | | public static void ClearStreamingAssetsYooDirectory() |
| | | { |
| | | string yooRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(); |
| | |
| | | System.IO.Directory.CreateDirectory(yooRoot); |
| | | } |
| | | |
| | | private static void DeleteObsoletePackageDirectories(string yooRoot) |
| | | { |
| | | if (!System.IO.Directory.Exists(yooRoot)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | var validPackages = new System.Collections.Generic.HashSet<string>(GetAllPackageNames(), StringComparer.OrdinalIgnoreCase); |
| | | foreach (var dir in System.IO.Directory.GetDirectories(yooRoot)) |
| | | { |
| | | var dirName = System.IO.Path.GetFileName(dir); |
| | | if (validPackages.Contains(dirName) || IsReservedYooDirectory(dirName)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | System.IO.Directory.Delete(dir, true); |
| | | var metaPath = dir + ".meta"; |
| | | if (System.IO.File.Exists(metaPath)) |
| | | { |
| | | System.IO.File.Delete(metaPath); |
| | | } |
| | | |
| | | Debug.Log($"[YooAssetBuildTool] 已清理过期 Package 目录: {dirName}"); |
| | | } |
| | | } |
| | | |
| | | private static bool IsReservedYooDirectory(string dirName) |
| | | { |
| | | return string.Equals(dirName, AssetVersionUtility.OPConfigDirectory, StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | public static void DeleteStartupConfigsFromStreamingAssets() |
| | | { |
| | | string yooRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(); |
| | | string initialFunctionPath = System.IO.Path.Combine(yooRoot, "InitialFunction.txt"); |
| | | string initialFunctionMetaPath = initialFunctionPath + ".meta"; |
| | | string configDir = System.IO.Path.Combine(yooRoot, "config"); |
| | | string configDir = System.IO.Path.Combine(yooRoot, AssetVersionUtility.OPConfigDirectory); |
| | | string configMetaPath = configDir + ".meta"; |
| | | |
| | | if (System.IO.File.Exists(initialFunctionPath)) |
| | |
| | | } |
| | | |
| | | AssetDatabase.Refresh(); |
| | | Debug.Log("[YooAssetBuildTool] 已清理 StreamingAssets/yoo 下的 InitialFunction.txt 和 config 目录"); |
| | | Debug.Log("[YooAssetBuildTool] 已清理 StreamingAssets/yoo 下的 InitialFunction.txt 和 OPConfig 目录"); |
| | | } |
| | | |
| | | private static string ResolveOutputDirectory(string outputPath) |
| | |
| | | { |
| | | string sourceConfigDir = System.IO.Path.Combine(Application.dataPath, "ResourcesOut", "Config"); |
| | | string yooDir = targetYooDir; |
| | | string streamingConfigDir = System.IO.Path.Combine(yooDir, "config"); |
| | | string streamingConfigDir = System.IO.Path.Combine(yooDir, AssetVersionUtility.OPConfigDirectory); |
| | | |
| | | if (!System.IO.Directory.Exists(sourceConfigDir)) |
| | | { |
| | |
| | | return; |
| | | } |
| | | |
| | | DeleteObsoletePackageDirectories(destRoot); |
| | | |
| | | int copiedCount = 0; |
| | | foreach (string pkgName in ALL_PACKAGES) |
| | | foreach (string pkgName in GetAllPackageNames()) |
| | | { |
| | | string pkgBuildDir = System.IO.Path.Combine(srcRoot, pkgName); |
| | | if (!System.IO.Directory.Exists(pkgBuildDir)) continue; |
| | |
| | | |
| | | /// <summary> |
| | | /// 扫描 StreamingAssets 中实际存在的 Package 子目录,写入 Resources/YooBuildinPackages.txt。 |
| | | /// 运行时通过 YooAssetInitializer.HasBuildinPackage() 读取,决定是否创建 BuildinFileSystem。 |
| | | /// 该文件仅用于打包诊断和旧包兼容;运行时 HostPlayMode 会探测 APK 内 |
| | | /// yoo/{PackageName}/BuildinCatalog.bytes,有索引才挂载 BuildinFileSystem。 |
| | | /// </summary> |
| | | public static void WriteBuildinPackageList() |
| | | { |
| | | string yooRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(); |
| | | var existing = new System.Collections.Generic.List<string>(); |
| | | var validPackages = new System.Collections.Generic.HashSet<string>(GetAllPackageNames(), StringComparer.OrdinalIgnoreCase); |
| | | if (System.IO.Directory.Exists(yooRoot)) |
| | | { |
| | | foreach (var dir in System.IO.Directory.GetDirectories(yooRoot)) |
| | | { |
| | | existing.Add(System.IO.Path.GetFileName(dir)); |
| | | var dirName = System.IO.Path.GetFileName(dir); |
| | | if (validPackages.Contains(dirName)) |
| | | existing.Add(dirName); |
| | | } |
| | | } |
| | | existing.Sort(); |
| | |
| | | if (!ok) |
| | | { |
| | | EditorUtility.DisplayDialog("Dll 打包失败", "Dll Package 打包失败,已中止构建。\n请查看 Console 日志。", "确定"); |
| | | return; |
| | | } |
| | | |
| | | if (!CopySinglePackageBuildOutput("Dll", null, version)) |
| | | { |
| | | EditorUtility.DisplayDialog("Dll 拷贝失败", "Dll Package 打包成功,但拷贝到 StreamingAssets 失败,已中止构建。\n请查看 Console 日志。", "确定"); |
| | | return; |
| | | } |
| | | |
| | |
| | | // 单个 Package 打包 |
| | | // ==================================================================== |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Prefab", false, 300)] |
| | | private static void BuildPrefab() => BuildSingleWithDialog("Prefab"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/UI", false, 301)] |
| | | private static void BuildUI() => BuildSingleWithDialog("UI"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/UIEffect", false, 302)] |
| | | private static void BuildUIEffect() => BuildSingleWithDialog("UIEffect"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Battle", false, 303)] |
| | | private static void BuildBattle() => BuildSingleWithDialog("Battle"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Audio", false, 304)] |
| | | private static void BuildAudio() => BuildSingleWithDialog("Audio"); |
| | | [MenuItem("YooAsset工具/打包单个Package/Video", false, 305)] |
| | | private static void BuildVideo() => BuildSingleWithDialog("Video"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Builtin", false, 306)] |
| | | [MenuItem("YooAsset工具/打包单个Package/Builtin", false, 300)] |
| | | private static void BuildBuiltin() => BuildSingleWithDialog("Builtin"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Dll (HybridCLR)", false, 307)] |
| | | [MenuItem("YooAsset工具/打包单个Package/Config", false, 301)] |
| | | private static void BuildConfig() => BuildSingleWithDialog("Config"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Shader", false, 302)] |
| | | private static void BuildShader() => BuildSingleWithDialog("Shader"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Materials", false, 303)] |
| | | private static void BuildMaterials() => BuildSingleWithDialog("Materials"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/ScriptableObject", false, 304)] |
| | | private static void BuildScriptableObject() => BuildSingleWithDialog("ScriptableObject"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Scenes", false, 305)] |
| | | private static void BuildScenes() => BuildSingleWithDialog("Scenes"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/UI", false, 306)] |
| | | private static void BuildUI() => BuildSingleWithDialog("UI"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/UIComp", false, 307)] |
| | | private static void BuildUIComp() => BuildSingleWithDialog("UIComp"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/UIEffect", false, 308)] |
| | | private static void BuildUIEffect() => BuildSingleWithDialog("UIEffect"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Battle", false, 309)] |
| | | private static void BuildBattle() => BuildSingleWithDialog("Battle"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Hero", false, 310)] |
| | | private static void BuildHero() => BuildSingleWithDialog("Hero"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Sprite", false, 311)] |
| | | private static void BuildSprite() => BuildSingleWithDialog("Sprite"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Texture", false, 312)] |
| | | private static void BuildTexture() => BuildSingleWithDialog("Texture"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Font", false, 313)] |
| | | private static void BuildFont() => BuildSingleWithDialog("Font"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Audio", false, 314)] |
| | | private static void BuildAudio() => BuildSingleWithDialog("Audio"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Video", false, 315)] |
| | | private static void BuildVideo() => BuildSingleWithDialog("Video"); |
| | | |
| | | [MenuItem("YooAsset工具/打包单个Package/Dll (HybridCLR)", false, 316)] |
| | | private static void BuildDll() |
| | | { |
| | | string version = GenerateVersion(); |
| | |
| | | EditorUtility.ClearProgressBar(); |
| | | |
| | | if (ok) |
| | | EditorUtility.DisplayDialog("打包成功", "Package 'Dll' 打包完成!", "确定"); |
| | | { |
| | | if (CopySinglePackageBuildOutput("Dll", null, version)) |
| | | EditorUtility.DisplayDialog("打包成功", "Package 'Dll' 打包完成!", "确定"); |
| | | else |
| | | EditorUtility.DisplayDialog("拷贝失败", "Package 'Dll' 打包成功,但拷贝到 StreamingAssets 失败,请查看 Console 日志。", "确定"); |
| | | } |
| | | else |
| | | { |
| | | EditorUtility.DisplayDialog("打包失败", "Package 'Dll' 打包失败,请查看 Console 日志。", "确定"); |
| | | } |
| | | |
| | | AssetDatabase.Refresh(); |
| | | } |
| | |
| | | |
| | | if (ok) |
| | | { |
| | | EditorUtility.DisplayDialog("打包成功", $"Package '{packageName}' 打包完成!", "确定"); |
| | | if (CopySinglePackageBuildOutput(packageName, null, version)) |
| | | EditorUtility.DisplayDialog("打包成功", $"Package '{packageName}' 打包完成!", "确定"); |
| | | else |
| | | EditorUtility.DisplayDialog("拷贝失败", $"Package '{packageName}' 打包成功,但拷贝到 StreamingAssets 失败,请查看 Console 日志。", "确定"); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | EditorUtility.DisplayDialog("YooAsset 状态", msg, "确定"); |
| | | } |
| | | |
| | | [MenuItem("YooAsset工具/同步资源PackRule配置", false, 203)] |
| | | public static void SyncCollectorPackRulesMenu() |
| | | { |
| | | var changed = SyncCollectorPackRules(); |
| | | EditorUtility.DisplayDialog( |
| | | "YooAsset PackRule", |
| | | changed ? "PackRule 配置已同步。" : "PackRule 配置已经是最新。", |
| | | "确定"); |
| | | } |
| | | |
| | | private static readonly CollectorPackRule[] CollectorPackRules = |
| | | { |
| | | new CollectorPackRule("UI", "Assets/ResourcesOut/Font", "PackFontAssetGroup"), |
| | | new CollectorPackRule("UI", "Assets/ResourcesOut/Sprite", "PackSeparately"), |
| | | new CollectorPackRule("Hero", "Assets/ResourcesOut/Hero", "PackTopDirectorySubDirectory"), |
| | | new CollectorPackRule("UIEffect", "Assets/ResourcesOut/UIEffect", "PackTopDirectorySubDirectory"), |
| | | }; |
| | | |
| | | private static bool SyncCollectorPackRules() |
| | | { |
| | | var setting = AssetBundleCollectorSettingData.Setting; |
| | | var changed = false; |
| | | |
| | | foreach (var rule in CollectorPackRules) |
| | | { |
| | | var package = setting.Packages.Find(item => string.Equals(item.PackageName, rule.PackageName, StringComparison.OrdinalIgnoreCase)); |
| | | if (package == null) |
| | | { |
| | | Debug.LogWarning($"[YooAssetBuildTool] 找不到 Package: {rule.PackageName}"); |
| | | continue; |
| | | } |
| | | |
| | | foreach (var group in package.Groups) |
| | | { |
| | | foreach (var collector in group.Collectors) |
| | | { |
| | | if (!IsSameAssetPath(collector.CollectPath, rule.CollectPath)) |
| | | continue; |
| | | |
| | | if (collector.PackRuleName == rule.PackRuleName) |
| | | continue; |
| | | |
| | | collector.PackRuleName = rule.PackRuleName; |
| | | AssetBundleCollectorSettingData.ModifyCollector(group, collector); |
| | | changed = true; |
| | | Debug.Log($"[YooAssetBuildTool] 同步 PackRule: {rule.PackageName} -> {rule.PackRuleName}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (changed) |
| | | { |
| | | AssetBundleCollectorSettingData.SaveFile(); |
| | | AssetDatabase.Refresh(); |
| | | } |
| | | |
| | | return changed; |
| | | } |
| | | |
| | | private static bool IsSameAssetPath(string lhs, string rhs) |
| | | { |
| | | return NormalizeAssetPath(lhs).Equals(NormalizeAssetPath(rhs), StringComparison.OrdinalIgnoreCase); |
| | | } |
| | | |
| | | private static string NormalizeAssetPath(string assetPath) |
| | | { |
| | | return string.IsNullOrEmpty(assetPath) ? string.Empty : assetPath.Replace('\\', '/').TrimEnd('/'); |
| | | } |
| | | |
| | | private readonly struct CollectorPackRule |
| | | { |
| | | public readonly string PackageName; |
| | | public readonly string CollectPath; |
| | | public readonly string PackRuleName; |
| | | |
| | | public CollectorPackRule(string packageName, string collectPath, string packRuleName) |
| | | { |
| | | PackageName = packageName; |
| | | CollectPath = collectPath; |
| | | PackRuleName = packRuleName; |
| | | } |
| | | } |
| | | } |
| | |
| | | #else
|
| | | Debug.unityLogger.logEnabled = true;
|
| | | #endif
|
| | |
|
| | | }
|
| | |
|
| | | // 启动入口
|
| | |
| | | AOTMetaAssemblyFiles.Add(dllName);
|
| | |
|
| | | var location = $"Assets/HybridCLRDlls/{dllName}";
|
| | | bool needRemote = false;
|
| | | int downloadCount = 0;
|
| | | long downloadBytes = 0;
|
| | | float downloadStartTime = 0f;
|
| | | try
|
| | | {
|
| | | if (YooAssetInitializer.Instance.PlayMode == EPlayMode.HostPlayMode && dllPackage.PackageValid && dllPackage.IsNeedDownloadFromRemote(location))
|
| | | {
|
| | | var downloader = dllPackage.CreateBundleDownloader(location, false, 1, 0);
|
| | | downloadCount = downloader != null ? downloader.TotalDownloadCount : 0;
|
| | | downloadBytes = downloader != null ? downloader.TotalDownloadBytes : 0;
|
| | | needRemote = downloadCount > 0 || downloadBytes > 0;
|
| | | downloadStartTime = Time.realtimeSinceStartup;
|
| | | Debug.Log($"[YooAssetDownload] Start on-demand source=Launch.ReadDllBytes, package={dllPackage.PackageName}, location='{location}', files={downloadCount}, size={FormatBytes(downloadBytes)}");
|
| | | }
|
| | | }
|
| | | catch (Exception ex)
|
| | | {
|
| | | Debug.LogWarning($"[YooAssetDownload] Check DLL download failed. location='{location}', error={ex.Message}");
|
| | | }
|
| | |
|
| | | var handle = dllPackage.LoadAssetAsync<TextAsset>(location);
|
| | | await handle.ToUniTask();
|
| | |
|
| | | if (handle.Status != EOperationStatus.Succeed)
|
| | | {
|
| | | if (needRemote)
|
| | | {
|
| | | float cost = Time.realtimeSinceStartup - downloadStartTime;
|
| | | Debug.LogError($"[YooAssetDownload] Failed on-demand source=Launch.ReadDllBytes, package={dllPackage.PackageName}, location='{location}', files={downloadCount}, size={FormatBytes(downloadBytes)}, cost={cost:F2}s, error={handle.LastError}");
|
| | | }
|
| | | Debug.LogError($"[Launch] 加载 DLL 失败: {dllName}: {handle.LastError}");
|
| | | }
|
| | | else
|
| | | {
|
| | | if (needRemote)
|
| | | {
|
| | | float cost = Time.realtimeSinceStartup - downloadStartTime;
|
| | | Debug.Log($"[YooAssetDownload] Finish on-demand source=Launch.ReadDllBytes, package={dllPackage.PackageName}, location='{location}', files={downloadCount}, size={FormatBytes(downloadBytes)}, cost={cost:F2}s");
|
| | | }
|
| | | s_assetDatas[dllName] = ((TextAsset)handle.AssetObject).bytes;
|
| | | Debug.Log($"[Launch] Loaded DLL: {dllName} size:{s_assetDatas[dllName].Length}");
|
| | | }
|
| | |
| | | callback?.Invoke();
|
| | | }
|
| | |
|
| | | private static string FormatBytes(long bytes)
|
| | | {
|
| | | if (bytes < 1024L)
|
| | | return $"{bytes} B";
|
| | | if (bytes < 1024L * 1024L)
|
| | | return $"{bytes / 1024f:F2} KB";
|
| | | if (bytes < 1024L * 1024L * 1024L)
|
| | | return $"{bytes / 1024f / 1024f:F2} MB";
|
| | | return $"{bytes / 1024f / 1024f / 1024f:F2} GB";
|
| | | }
|
| | |
|
| | | #if UNITY_EDITOR
|
| | | /// <summary>
|
| | | /// Editor 专用:递归扫描本地目录,建立文件名→URI 索引,模拟 CDN Remote File System。
|
| | |
| | | private const int YOO_MAX_RETRY = 3; |
| | | private const int YOO_BASE_DELAY_MS = 500; |
| | | |
| | | // package 为 null 时默认使用启动配置包(当前为 Builtin) |
| | | private struct DownloadLogContext |
| | | { |
| | | public bool Enabled; |
| | | public string Source; |
| | | public string PackageName; |
| | | public string Location; |
| | | public int Count; |
| | | public long Bytes; |
| | | public float StartTime; |
| | | } |
| | | |
| | | // package 为 null 时默认使用启动 Builtin 包 |
| | | // BuiltIn 路径下的资源(Sprites/Prefabs)应传入 DefaultPackage(= Builtin 包) |
| | | private async UniTask<T> LoadAssetWithRetryAsync<T>(string location, ResourcePackage package = null) where T : UnityEngine.Object |
| | | { |
| | | package ??= YooAssetInitializer.Instance.PrefabPackage; |
| | | package ??= YooAssetInitializer.Instance.DefaultPackage; |
| | | Exception lastEx = null; |
| | | for (int attempt = 0; attempt <= YOO_MAX_RETRY; attempt++) |
| | | { |
| | |
| | | if (!package.PackageValid) |
| | | throw new Exception($"YooAsset package '{package.PackageName}' has no active manifest. State={YooAssetInitializer.Instance.State}, location='{location}'"); |
| | | |
| | | var downloadLog = BeginOnDemandDownloadLog(package, location, $"Launch.LoadAssetAsync<{typeof(T).Name}>"); |
| | | var handle = package.LoadAssetAsync<T>(location); |
| | | await handle.ToUniTask(); |
| | | if (handle.Status != EOperationStatus.Succeed) |
| | | { |
| | | EndOnDemandDownloadLog(downloadLog, false, handle.LastError); |
| | | throw new Exception($"YooAsset load failed for '{location}': {handle.LastError}"); |
| | | } |
| | | EndOnDemandDownloadLog(downloadLog, true); |
| | | return handle.GetAssetObject<T>(); |
| | | } |
| | | catch (Exception ex) |
| | |
| | | } |
| | | Debug.LogError($"[LocalResManager] Load '{location}' failed after {YOO_MAX_RETRY + 1} attempts: {lastEx?.Message}"); |
| | | return null; |
| | | } |
| | | |
| | | private DownloadLogContext BeginOnDemandDownloadLog(ResourcePackage package, string location, string source) |
| | | { |
| | | var context = new DownloadLogContext |
| | | { |
| | | Enabled = false, |
| | | Source = source, |
| | | PackageName = package != null ? package.PackageName : "NULL", |
| | | Location = location, |
| | | StartTime = Time.realtimeSinceStartup, |
| | | }; |
| | | |
| | | try |
| | | { |
| | | if (YooAssetInitializer.Instance.PlayMode != EPlayMode.HostPlayMode || package == null || !package.PackageValid) |
| | | return context; |
| | | |
| | | if (!package.IsNeedDownloadFromRemote(location)) |
| | | return context; |
| | | |
| | | var downloader = package.CreateBundleDownloader(location, false, 1, 0); |
| | | context.Count = downloader != null ? downloader.TotalDownloadCount : 0; |
| | | context.Bytes = downloader != null ? downloader.TotalDownloadBytes : 0; |
| | | context.Enabled = context.Count > 0 || context.Bytes > 0; |
| | | |
| | | if (context.Enabled) |
| | | { |
| | | Debug.Log($"[YooAssetDownload] Start on-demand source={source}, package={context.PackageName}, location='{location}', files={context.Count}, size={FormatBytes(context.Bytes)}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogWarning($"[YooAssetDownload] Check on-demand download failed. source={source}, package={context.PackageName}, location='{location}', error={ex.Message}"); |
| | | } |
| | | |
| | | return context; |
| | | } |
| | | |
| | | private void EndOnDemandDownloadLog(DownloadLogContext context, bool succeed, string error = null) |
| | | { |
| | | if (!context.Enabled) |
| | | return; |
| | | |
| | | float cost = Time.realtimeSinceStartup - context.StartTime; |
| | | if (succeed) |
| | | { |
| | | Debug.Log($"[YooAssetDownload] Finish on-demand source={context.Source}, package={context.PackageName}, location='{context.Location}', files={context.Count}, size={FormatBytes(context.Bytes)}, cost={cost:F2}s"); |
| | | } |
| | | else |
| | | { |
| | | Debug.LogError($"[YooAssetDownload] Failed on-demand source={context.Source}, package={context.PackageName}, location='{context.Location}', files={context.Count}, size={FormatBytes(context.Bytes)}, cost={cost:F2}s, error={error}"); |
| | | } |
| | | } |
| | | |
| | | private static string FormatBytes(long bytes) |
| | | { |
| | | if (bytes < 1024L) |
| | | return $"{bytes} B"; |
| | | if (bytes < 1024L * 1024L) |
| | | return $"{bytes / 1024f:F2} KB"; |
| | | if (bytes < 1024L * 1024L * 1024L) |
| | | return $"{bytes / 1024f / 1024f:F2} MB"; |
| | | return $"{bytes / 1024f / 1024f / 1024f:F2} GB"; |
| | | } |
| | | |
| | | #if UNITY_WEBGL || TEST_BUILD |
| | |
| | | #if UNITY_EDITOR |
| | | await TryLoadInitialFunctionFromResourcesAsync(); |
| | | #else |
| | | bool configReady = await TryLoadInitialFunctionFromCdnAsync(initFuncUrl); |
| | | if (!configReady) |
| | | { |
| | | await InitializeYooAssetAndEnterReadBytesAsync(); |
| | | } |
| | | bool configReady = await TryLoadInitialFunctionFromCdnAsync(initFuncUrl); |
| | | if (!configReady) |
| | | { |
| | | await InitializeYooAssetAndEnterReadBytesAsync(); |
| | | } |
| | | #endif |
| | | await InitializeYooAssetAndEnterReadBytesAsync(); |
| | | } |
| | |
| | | } |
| | | await UniTask.Yield(); |
| | | #else |
| | | var spritePath = $"Assets/ResourcesOut/BuiltIn/Sprites/{name}.png"; |
| | | // BuiltIn/Sprites 在 Builtin 包(DefaultPackage) |
| | | sprite = await LoadAssetWithRetryAsync<Sprite>(spritePath, YooAssetInitializer.Instance.DefaultPackage); |
| | | if (excludePngs.Contains(StringUtility.Concat(name, ".png"))) |
| | | { |
| | | var spritePath = $"Assets/ResourcesOut/BuiltIn/Sprites/{name}.png"; |
| | | sprite = await LoadAssetWithRetryAsync<Sprite>(spritePath, YooAssetInitializer.Instance.DefaultPackage); |
| | | } |
| | | else |
| | | { |
| | | var atlas = await LoadAssetWithRetryAsync<SpriteAtlas>("Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2", YooAssetInitializer.Instance.DefaultPackage); |
| | | sprite = atlas != null ? atlas.GetSprite(name) : null; |
| | | } |
| | | #endif |
| | | if (sprite == null) |
| | | { |
| | |
| | | sprite = spriteAtlas.GetSprite(name); |
| | | } |
| | | #else |
| | | // BuiltIn/Sprites 在 Builtin 包(DefaultPackage) |
| | | var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetSync<Sprite>( |
| | | $"Assets/ResourcesOut/BuiltIn/Sprites/{name}.png"); |
| | | if (handle.Status == EOperationStatus.Succeed) |
| | | sprite = handle.GetAssetObject<Sprite>(); |
| | | if (excludePngs.Contains(StringUtility.Concat(name, ".png"))) |
| | | { |
| | | var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetSync<Sprite>( |
| | | $"Assets/ResourcesOut/BuiltIn/Sprites/{name}.png"); |
| | | if (handle.Status == EOperationStatus.Succeed) |
| | | sprite = handle.GetAssetObject<Sprite>(); |
| | | } |
| | | else |
| | | { |
| | | var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetSync<SpriteAtlas>( |
| | | "Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2"); |
| | | if (handle.Status == EOperationStatus.Succeed) |
| | | { |
| | | var spriteAtlas = handle.GetAssetObject<SpriteAtlas>(); |
| | | sprite = spriteAtlas != null ? spriteAtlas.GetSprite(name) : null; |
| | | } |
| | | } |
| | | #endif |
| | | if (sprite == null) |
| | | { |
| | |
| | | |
| | | public const string DEFAULT_PACKAGE_NAME = BUILTIN_PACKAGE_NAME; |
| | | |
| | | public const string CONFIG_PACKAGE_NAME = BUILTIN_PACKAGE_NAME; |
| | | // Launch 阶段读取的启动配置文件被 CollectResBeforeUpdate 额外收进 Builtin 包。 |
| | | // Main 阶段的 ResourcesOut/Config 由独立 Config 包负责。 |
| | | public const string LAUNCH_CONFIG_PACKAGE_NAME = BUILTIN_PACKAGE_NAME; |
| | | |
| | | /// <summary> |
| | | /// Launch 阶段需要初始化的包名(与 Collector 一致)。 |
| | |
| | | private ResourcePackage _configPackage; |
| | | |
| | | private readonly Dictionary<string, ResourcePackage> _packages = new Dictionary<string, ResourcePackage>(); |
| | | |
| | | /// <summary> |
| | | /// 随包安装的 Package 列表(从 Resources/YooBuildinPackages.txt 读取)。 |
| | | /// 打包时由 YooAssetBuildTool.WriteBuildinPackageList() 写入。 |
| | | /// null 表示未找到标记文件(Editor / 旧包),此时默认所有包都有 Buildin。 |
| | | /// </summary> |
| | | private static HashSet<string> _buildinPackages; |
| | | private static bool _buildinPackagesLoaded; |
| | | |
| | | /// <summary> |
| | | /// 检查指定包是否存在于 StreamingAssets(随包安装)。 |
| | | /// Editor 或未找到标记文件时返回 true(向后兼容)。 |
| | | /// </summary> |
| | | public static bool HasBuildinPackage(string packageName) |
| | | { |
| | | if (!_buildinPackagesLoaded) |
| | | { |
| | | _buildinPackagesLoaded = true; |
| | | var textAsset = Resources.Load<TextAsset>("YooBuildinPackages"); |
| | | if (textAsset != null) |
| | | { |
| | | _buildinPackages = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
| | | foreach (var line in textAsset.text.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) |
| | | { |
| | | _buildinPackages.Add(line.Trim()); |
| | | } |
| | | Resources.UnloadAsset(textAsset); |
| | | Debug.Log($"[YooAssetInitializer] Buildin packages: [{string.Join(", ", _buildinPackages)}]"); |
| | | } |
| | | else |
| | | { |
| | | Debug.Log("[YooAssetInitializer] YooBuildinPackages.txt not found, assuming all packages have buildin."); |
| | | } |
| | | } |
| | | |
| | | // 未找到标记文件 → 默认都有(兼容旧包和 Editor) |
| | | if (_buildinPackages == null) return true; |
| | | return _buildinPackages.Contains(packageName); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 当前初始化状态 |
| | |
| | | |
| | | public ResourcePackage DllPackage => GetPackage(DLL_PACKAGE_NAME); |
| | | |
| | | public ResourcePackage LaunchConfigPackage => _configPackage; |
| | | |
| | | [Obsolete("Use LaunchConfigPackage or BuiltinPackage instead.")] |
| | | public ResourcePackage PrefabPackage => _configPackage; |
| | | |
| | | /// <summary> |
| | |
| | | try |
| | | { |
| | | // 先验证初始化参数(如 SimulateBuild),避免 CreatePackage 后抛异常留下僵尸包裹 |
| | | bool enableBuildinFileSystem; |
| | | InitializeParameters initParams; |
| | | try |
| | | { |
| | | initParams = CreateInitParameters(playMode, remoteServices, pkgName); |
| | | enableBuildinFileSystem = await ShouldEnableBuildinFileSystemAsync(playMode, pkgName, nameof(YooAssetInitializer)); |
| | | initParams = CreateInitParameters(playMode, remoteServices, pkgName, enableBuildinFileSystem); |
| | | } |
| | | catch (Exception paramEx) |
| | | { |
| | |
| | | } |
| | | |
| | | var package = YooAssets.CreatePackage(pkgName); |
| | | var initOp = package.InitializeAsync(initParams); |
| | | await initOp.ToUniTask(); |
| | | |
| | | if (initOp.Status != EOperationStatus.Succeed) |
| | | try |
| | | { |
| | | Debug.LogError($"[YooAssetInitializer] Package '{pkgName}' init failed: {initOp.Error}"); |
| | | try |
| | | { |
| | | var destroyOp = package.DestroyAsync(); |
| | | await destroyOp.ToUniTask(); |
| | | YooAssets.RemovePackage(pkgName); |
| | | } |
| | | catch { /* ignore cleanup errors */ } |
| | | continue; |
| | | await InitializePackageOperationAsync(pkgName, package, initParams); |
| | | } |
| | | catch (Exception initEx) when (playMode == EPlayMode.HostPlayMode && enableBuildinFileSystem) |
| | | { |
| | | Debug.LogWarning($"[YooAssetInitializer] Package '{pkgName}' init with BuildinFileSystem failed, retry cache-only: {initEx.Message}"); |
| | | await RemovePackageSafelyAsync(pkgName, package); |
| | | |
| | | package = YooAssets.CreatePackage(pkgName); |
| | | initParams = CreateInitParameters(playMode, remoteServices, pkgName, false); |
| | | await InitializePackageOperationAsync(pkgName, package, initParams); |
| | | } |
| | | |
| | | _packages[pkgName] = package; |
| | |
| | | YooAssets.SetDefaultPackage(package); |
| | | } |
| | | |
| | | // CONFIG_PACKAGE_NAME 包作为启动配置包 |
| | | if (pkgName == CONFIG_PACKAGE_NAME) |
| | | // LAUNCH_CONFIG_PACKAGE_NAME 包作为启动配置包 |
| | | if (pkgName == LAUNCH_CONFIG_PACKAGE_NAME) |
| | | { |
| | | _configPackage = package; |
| | | } |
| | |
| | | // 如果 CreatePackage 成功但后续失败,清理僵尸包裹 |
| | | var zombiePkg = YooAssets.TryGetPackage(pkgName); |
| | | if (zombiePkg != null) |
| | | { |
| | | try |
| | | { |
| | | if (zombiePkg.InitializeStatus == EOperationStatus.None) |
| | | { |
| | | // 未初始化可以直接移除 |
| | | YooAssets.RemovePackage(pkgName); |
| | | } |
| | | else |
| | | { |
| | | // 已初始化需先销毁再移除(但这里是 catch 块,无法 await) |
| | | // 配合 YooAssetService 的自愈机制处理 |
| | | } |
| | | } |
| | | catch { /* ignore cleanup errors */ } |
| | | } |
| | | await RemovePackageSafelyAsync(pkgName, zombiePkg); |
| | | Debug.LogError($"[YooAssetInitializer] Package '{pkgName}' init exception (skipped): {ex.Message}"); |
| | | } |
| | | } |
| | |
| | | #endif |
| | | |
| | | // 1. 请求版本号(对关键包最多重试3次,间隔1s) |
| | | int versionRetryMax = string.Equals(pkgName, CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase) ? 3 : 0; |
| | | int versionRetryMax = string.Equals(pkgName, LAUNCH_CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase) ? 3 : 0; |
| | | EOperationStatus versionStatus = EOperationStatus.Failed; |
| | | string versionOpError = string.Empty; |
| | | string packageVersion = string.Empty; |
| | |
| | | bundleTotalCount = details.BundleTotalCount; |
| | | packageVersion = details.PackageVersion ?? "null"; |
| | | |
| | | if (string.Equals(pkgName, CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase)) |
| | | if (string.Equals(pkgName, LAUNCH_CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase)) |
| | | { |
| | | initialFunctionValid = package.CheckLocationValid("Assets/ResourcesOut/Config/InitialFunction.txt").ToString(); |
| | | } |
| | | } |
| | | else if (string.Equals(pkgName, CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase)) |
| | | else if (string.Equals(pkgName, LAUNCH_CONFIG_PACKAGE_NAME, StringComparison.OrdinalIgnoreCase)) |
| | | { |
| | | initialFunctionValid = "manifest-null"; |
| | | } |
| | |
| | | return; |
| | | } |
| | | |
| | | Debug.Log($"[YooAssetInitializer] Start downloading {downloader.TotalDownloadCount} files, total {downloader.TotalDownloadBytes} bytes"); |
| | | BindDownloadLogCallbacks(downloader, "Launch.DownloadAsync"); |
| | | |
| | | float startTime = Time.realtimeSinceStartup; |
| | | float lastLogTime = 0f; |
| | | int lastLogPercent = -1; |
| | | downloader.BeginDownload(); |
| | | |
| | | while (!downloader.IsDone) |
| | | { |
| | | progress?.Report(downloader.Progress); |
| | | LogDownloaderProgress(downloader, "Launch.DownloadAsync", startTime, ref lastLogTime, ref lastLogPercent); |
| | | await UniTask.Yield(); |
| | | } |
| | | |
| | |
| | | long pkgBytes = downloader.TotalDownloadBytes; |
| | | |
| | | Debug.Log($"[YooAssetInitializer] Downloading package '{pkgName}': {downloader.TotalDownloadCount} files, {pkgBytes / 1024f / 1024f:F2} MB"); |
| | | string source = $"Launch.DownloadAllPending package='{pkgName}'"; |
| | | BindDownloadLogCallbacks(downloader, source); |
| | | |
| | | float startTime = Time.realtimeSinceStartup; |
| | | float lastLogTime = 0f; |
| | | int lastLogPercent = -1; |
| | | downloader.BeginDownload(); |
| | | |
| | | while (!downloader.IsDone) |
| | |
| | | ? (downloadedBytes + (long)(pkgBytes * currentPkgProgress)) / (float)totalBytes |
| | | : 0f; |
| | | progress?.Report(overallProgress); |
| | | LogDownloaderProgress(downloader, source, startTime, ref lastLogTime, ref lastLogPercent, overallProgress); |
| | | await UniTask.Yield(); |
| | | } |
| | | |
| | |
| | | Debug.Log($"[YooAssetInitializer] All pending downloads finished. {downloaders.Count} packages processed."); |
| | | } |
| | | |
| | | private static void BindDownloadLogCallbacks(ResourceDownloaderOperation downloader, string source) |
| | | { |
| | | if (downloader == null) |
| | | return; |
| | | |
| | | float startTime = Time.realtimeSinceStartup; |
| | | Debug.Log($"[YooAssetDownload] Start downloader source={source}, files={downloader.TotalDownloadCount}, size={FormatBytes(downloader.TotalDownloadBytes)}"); |
| | | |
| | | downloader.DownloadFileBeginCallback = data => |
| | | { |
| | | Debug.Log($"[YooAssetDownload] File begin source={source}, package={data.PackageName}, file='{data.FileName}', size={FormatBytes(data.FileSize)}"); |
| | | }; |
| | | downloader.DownloadErrorCallback = data => |
| | | { |
| | | float cost = Time.realtimeSinceStartup - startTime; |
| | | Debug.LogError($"[YooAssetDownload] File error source={source}, package={data.PackageName}, file='{data.FileName}', cost={cost:F2}s, error={data.ErrorInfo}"); |
| | | }; |
| | | downloader.DownloadFinishCallback = data => |
| | | { |
| | | float cost = Time.realtimeSinceStartup - startTime; |
| | | string result = data.Succeed ? "Finish" : "Failed"; |
| | | Debug.Log($"[YooAssetDownload] {result} downloader source={source}, package={data.PackageName}, files={downloader.CurrentDownloadCount}/{downloader.TotalDownloadCount}, size={FormatBytes(downloader.CurrentDownloadBytes)}/{FormatBytes(downloader.TotalDownloadBytes)}, cost={cost:F2}s"); |
| | | }; |
| | | } |
| | | |
| | | private static void LogDownloaderProgress(ResourceDownloaderOperation downloader, string source, float startTime, |
| | | ref float lastLogTime, ref int lastLogPercent, float overallProgress = -1f) |
| | | { |
| | | if (downloader == null) |
| | | return; |
| | | |
| | | float now = Time.realtimeSinceStartup; |
| | | int percent = Mathf.Clamp(Mathf.FloorToInt(downloader.Progress * 100f), 0, 100); |
| | | if (percent < 100 && percent < lastLogPercent + 5 && now - lastLogTime < 1f) |
| | | return; |
| | | |
| | | lastLogTime = now; |
| | | lastLogPercent = percent; |
| | | |
| | | string overall = overallProgress >= 0f ? $", overall={Mathf.Clamp01(overallProgress) * 100f:F1}%" : string.Empty; |
| | | Debug.Log($"[YooAssetDownload] Progress source={source}, progress={percent}%, files={downloader.CurrentDownloadCount}/{downloader.TotalDownloadCount}, size={FormatBytes(downloader.CurrentDownloadBytes)}/{FormatBytes(downloader.TotalDownloadBytes)}, cost={now - startTime:F2}s{overall}"); |
| | | } |
| | | |
| | | private static string FormatBytes(long bytes) |
| | | { |
| | | if (bytes < 1024L) |
| | | return $"{bytes} B"; |
| | | if (bytes < 1024L * 1024L) |
| | | return $"{bytes / 1024f:F2} KB"; |
| | | if (bytes < 1024L * 1024L * 1024L) |
| | | return $"{bytes / 1024f / 1024f:F2} MB"; |
| | | return $"{bytes / 1024f / 1024f / 1024f:F2} GB"; |
| | | } |
| | | |
| | | // ==================================================================== |
| | | // 辅助方法 |
| | | // ==================================================================== |
| | | |
| | | private InitializeParameters CreateInitParameters(EPlayMode playMode, IRemoteServices remoteServices, string packageName) |
| | | public static async UniTask<bool> HasBuildinCatalogAsync(string packageName) |
| | | { |
| | | if (string.IsNullOrEmpty(packageName)) |
| | | return false; |
| | | |
| | | #if UNITY_ANDROID && !UNITY_EDITOR |
| | | return AndroidAssetExists($"yoo/{packageName}/BuildinCatalog.bytes"); |
| | | #else |
| | | string catalogUrl = $"{Application.streamingAssetsPath}/yoo/{packageName}/BuildinCatalog.bytes"; |
| | | catalogUrl = catalogUrl.Replace('\\', '/'); |
| | | |
| | | #if !UNITY_WEBGL |
| | | if (!catalogUrl.StartsWith("jar:", StringComparison.OrdinalIgnoreCase) && |
| | | !catalogUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && |
| | | !catalogUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && |
| | | !catalogUrl.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) |
| | | return System.IO.File.Exists(catalogUrl); |
| | | #endif |
| | | |
| | | try |
| | | { |
| | | using var request = UnityEngine.Networking.UnityWebRequest.Get(catalogUrl); |
| | | request.timeout = 3; |
| | | await request.SendWebRequest().ToUniTask(); |
| | | return request.result == UnityEngine.Networking.UnityWebRequest.Result.Success; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogWarning($"[YooAssetInitializer] Probe buildin catalog exception. package='{packageName}', url='{catalogUrl}', error={ex.Message}"); |
| | | return false; |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | public static async UniTask<bool> ShouldEnableBuildinFileSystemAsync(EPlayMode playMode, string packageName, string logPrefix) |
| | | { |
| | | bool enableBuildinFileSystem = true; |
| | | if (playMode == EPlayMode.HostPlayMode) |
| | | { |
| | | enableBuildinFileSystem = await HasBuildinCatalogAsync(packageName); |
| | | if (enableBuildinFileSystem) |
| | | Debug.Log($"[{logPrefix}] Package '{packageName}' has buildin catalog, enable BuildinFileSystem."); |
| | | else |
| | | Debug.Log($"[{logPrefix}] Package '{packageName}' has no buildin catalog, skip BuildinFileSystem."); |
| | | } |
| | | |
| | | return enableBuildinFileSystem; |
| | | } |
| | | |
| | | #if UNITY_ANDROID && !UNITY_EDITOR |
| | | private static bool AndroidAssetExists(string assetPath) |
| | | { |
| | | try |
| | | { |
| | | using var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); |
| | | using var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); |
| | | using var assets = activity.Call<AndroidJavaObject>("getAssets"); |
| | | using var stream = assets.Call<AndroidJavaObject>("open", assetPath); |
| | | stream.Call("close"); |
| | | return true; |
| | | } |
| | | catch |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | private async UniTask RemovePackageSafelyAsync(string packageName, ResourcePackage package) |
| | | { |
| | | try |
| | | { |
| | | if (package != null && package.InitializeStatus != EOperationStatus.None) |
| | | { |
| | | var destroyOp = package.DestroyAsync(); |
| | | await destroyOp.ToUniTask(); |
| | | } |
| | | |
| | | YooAssets.RemovePackage(packageName); |
| | | } |
| | | catch |
| | | { |
| | | // ignore cleanup errors |
| | | } |
| | | } |
| | | |
| | | private async UniTask InitializePackageOperationAsync(string packageName, ResourcePackage package, InitializeParameters initParams) |
| | | { |
| | | var initOp = package.InitializeAsync(initParams); |
| | | await initOp.ToUniTask(); |
| | | |
| | | if (initOp.Status != EOperationStatus.Succeed) |
| | | throw new InvalidOperationException(initOp.Error); |
| | | } |
| | | |
| | | private async UniTask<InitializeParameters> CreateInitParametersAsync(EPlayMode playMode, IRemoteServices remoteServices, string packageName) |
| | | { |
| | | bool enableBuildinFileSystem = await ShouldEnableBuildinFileSystemAsync(playMode, packageName, nameof(YooAssetInitializer)); |
| | | |
| | | return CreateInitParameters(playMode, remoteServices, packageName, enableBuildinFileSystem); |
| | | } |
| | | |
| | | private InitializeParameters CreateInitParameters(EPlayMode playMode, IRemoteServices remoteServices, string packageName, bool enableBuildinFileSystem) |
| | | { |
| | | switch (playMode) |
| | | { |
| | |
| | | } |
| | | case EPlayMode.HostPlayMode: |
| | | { |
| | | bool hasBuildin = HasBuildinPackage(packageName); |
| | | // 有 remoteCdnBaseUrl 时为每个包单独创建带子路径的 RemoteServices |
| | | // 例:{cdnBase}/android/{packageName}/{fileName} |
| | | var effectiveRemote = !string.IsNullOrEmpty(_remoteCdnBaseUrl) |
| | |
| | | : remoteServices; |
| | | return new HostPlayModeParameters |
| | | { |
| | | BuildinFileSystemParameters = hasBuildin |
| | | BuildinFileSystemParameters = enableBuildinFileSystem |
| | | ? FileSystemParameters.CreateDefaultBuildinFileSystemParameters() |
| | | : null, |
| | | CacheFileSystemParameters = FileSystemParameters |
| | |
| | | |
| | | void Awake() |
| | | { |
| | | SetProgressBarImagesVisible(false); |
| | | InitSpritesAsync().Forget(); |
| | | UpdateProgress(); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | imageCircle.sprite = sprites.Item2; |
| | | imagebg3.sprite = sprites.Item3; |
| | | imageloding.sprite = sprites.Item4; |
| | | if (sprites.Item3 != null && sprites.Item4 != null) |
| | | { |
| | | SetProgressBarImagesVisible(true); |
| | | } |
| | | else |
| | | { |
| | | Debug.LogError($"[LaunchExWin] Progress bar sprite load failed. LoadingBottom={sprites.Item3 != null}, LoadingSlider={sprites.Item4 != null}"); |
| | | } |
| | | } |
| | | |
| | | private void SetProgressBarImagesVisible(bool visible) |
| | | { |
| | | if (imagebg3 != null) |
| | | { |
| | | imagebg3.enabled = visible; |
| | | } |
| | | |
| | | if (imageloding != null) |
| | | { |
| | | imageloding.enabled = visible; |
| | | } |
| | | } |
| | | |
| | | private void OnEnable() |