// ============================================================================
// YooAssetService.cs — YooAsset 封装服务
// 实现 IYooAssetService 和 IYooAssetBridge,替代 AssetBundleUtility
// ============================================================================
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using YooAsset;
namespace ProjSG.Resource
{
///
/// YooAsset 资源加载服务单例。
/// 封装 YooAsset ResourcePackage 的核心加载能力,提供 UniTask 异步 API。
/// 同时实现 IYooAssetBridge 供 Launch 程序集跨程序集调用。
///
public class YooAssetService : Singleton, IYooAssetService, IYooAssetBridge
{
private readonly Dictionary _packages = new Dictionary();
private ResourcePackage _defaultPackage;
private IRemoteServices _remoteServices;
private bool _isInitialized;
private EPlayMode _playMode;
// ====================================================================
// IYooAssetService Properties
// ====================================================================
///
public bool IsInitialized => _isInitialized;
///
public EPlayMode PlayMode => _playMode;
// ====================================================================
// IYooAssetBridge Properties
// ====================================================================
bool IYooAssetBridge.IsRegistered => _isInitialized;
// ====================================================================
// Initialization
// ====================================================================
///
public async UniTask InitializeAsync(EPlayMode playMode, IRemoteServices remoteServices = null)
{
if (_isInitialized)
{
Debug.LogWarning("[YooAssetService] Already initialized.");
return;
}
_playMode = playMode;
_remoteServices = remoteServices;
// YooAsset 全局初始化(幂等操作)
YooAssets.Initialize();
// 初始化所有配置中的包裹
foreach (var pkgName in YooAssetPackageConfig.AllPackages)
{
try
{
// 优先复用 Launch 阶段已创建的包裹
var package = YooAssets.TryGetPackage(pkgName);
if (package != null)
{
// 验证包裹是否已成功初始化
if (package.InitializeStatus == EOperationStatus.Succeed)
{
Debug.Log($"[YooAssetService] Reusing existing package '{pkgName}' (InitializeStatus=Succeed)");
}
else
{
// 包裹存在但初始化未完成或失败(僵尸包裹)
// 销毁后重新创建并初始化
Debug.LogWarning($"[YooAssetService] Package '{pkgName}' exists but InitializeStatus={package.InitializeStatus}, destroying and re-creating...");
// 根据状态清理僵尸包裹
if (package.InitializeStatus == EOperationStatus.None)
{
// 未初始化状态可以直接移除
YooAssets.RemovePackage(pkgName);
}
else
{
// Failed/Processing 状态需先销毁再移除
var destroyOp = package.DestroyAsync();
await destroyOp.ToUniTask();
YooAssets.RemovePackage(pkgName);
}
package = YooAssets.CreatePackage(pkgName);
var initParams = CreateInitParameters(playMode, remoteServices, pkgName);
var initOp = package.InitializeAsync(initParams);
await initOp.ToUniTask();
if (initOp.Status != EOperationStatus.Succeed)
{
Debug.LogWarning($"[YooAssetService] Package '{pkgName}' re-init failed: {initOp.Error}");
continue;
}
Debug.Log($"[YooAssetService] Package '{pkgName}' re-initialized successfully.");
// 重新初始化后必须请求版本并更新 Manifest
await RequestVersionAndUpdateForPackageAsync(pkgName, package);
}
}
else
{
// 自行创建并初始化(首次启动或该包未在 Launch 阶段创建)
package = YooAssets.CreatePackage(pkgName);
var initParams = CreateInitParameters(playMode, remoteServices, pkgName);
var initOp = package.InitializeAsync(initParams);
await initOp.ToUniTask();
if (initOp.Status != EOperationStatus.Succeed)
{
Debug.LogWarning($"[YooAssetService] Package '{pkgName}' init failed: {initOp.Error}");
continue;
}
// 初始化后必须请求版本并更新 Manifest,否则 ActiveManifest 为 null
await RequestVersionAndUpdateForPackageAsync(pkgName, package);
Debug.Log($"[YooAssetService] Package '{pkgName}' newly initialized.");
}
_packages[pkgName] = package;
// 设置默认包
if (_defaultPackage == null || pkgName == YooAssetPackageConfig.DefaultPackage)
{
_defaultPackage = package;
YooAssets.SetDefaultPackage(package);
}
}
catch (Exception ex)
{
// EditorSimulateMode 下包不在 Collector 中会抛异常,跳过
Debug.LogWarning($"[YooAssetService] Package '{pkgName}' init exception (skipped): {ex.Message}");
}
}
if (_defaultPackage == null)
{
Debug.LogError("[YooAssetService] No packages initialized successfully!");
throw new InvalidOperationException("YooAsset initialization failed: no packages available.");
}
_isInitialized = true;
// 输出初始化摘要 — 帮助诊断缺失的包裹
var allPkgs = YooAssetPackageConfig.AllPackages;
var missingPkgs = new System.Collections.Generic.List();
foreach (var p in allPkgs)
{
if (!_packages.ContainsKey(p))
missingPkgs.Add(p);
}
if (missingPkgs.Count > 0)
{
Debug.LogError($"[YooAssetService] WARNING: {missingPkgs.Count} package(s) FAILED to initialize: [{string.Join(", ", missingPkgs)}]. " +
$"Assets routed to these packages will fail to load! Check earlier console errors for SimulateBuild failures.");
}
Debug.Log($"[YooAssetService] Initialized {_packages.Count}/{allPkgs.Length} packages with PlayMode={playMode}. " +
$"Active: [{string.Join(", ", _packages.Keys)}]");
#if UNITY_WEBGL
// WebGL 诊断:输出每个包的 Manifest 和 Bundle 详情
DiagDumpPackageStatus();
#endif
}
///
/// 初始化指定名称的额外资源包裹。
///
public async UniTask InitializePackageAsync(string packageName, EPlayMode playMode,
IRemoteServices remoteServices = null)
{
if (_packages.ContainsKey(packageName))
{
Debug.LogWarning($"[YooAssetService] Package '{packageName}' already initialized.");
return;
}
// 优先复用已存在的包裹(可能由 Launch 阶段创建)
var package = YooAssets.TryGetPackage(packageName);
bool needManifest = false;
if (package == null)
{
package = YooAssets.CreatePackage(packageName);
var initParams = CreateInitParameters(playMode, remoteServices ?? _remoteServices, packageName);
var initOp = package.InitializeAsync(initParams);
await initOp.ToUniTask();
if (initOp.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] Initialize package '{packageName}' failed: {initOp.Error}");
throw new InvalidOperationException($"YooAsset package '{packageName}' initialization failed: {initOp.Error}");
}
needManifest = true;
}
_packages[packageName] = package;
// 确保 ActiveManifest 已加载
if (needManifest)
{
await RequestVersionAndUpdateForPackageAsync(packageName, package);
}
Debug.Log($"[YooAssetService] Package '{packageName}' initialized.");
}
private InitializeParameters CreateInitParameters(EPlayMode playMode, IRemoteServices remoteServices, string packageName)
{
switch (playMode)
{
case EPlayMode.EditorSimulateMode:
{
#if UNITY_EDITOR
var simulateResult = EditorSimulateModeHelper.SimulateBuild(packageName);
return new EditorSimulateModeParameters
{
EditorFileSystemParameters = FileSystemParameters
.CreateDefaultEditorFileSystemParameters(simulateResult.PackageRootDirectory)
};
#else
throw new InvalidOperationException("EditorSimulateMode is only available in Unity Editor.");
#endif
}
case EPlayMode.HostPlayMode:
{
return new HostPlayModeParameters
{
BuildinFileSystemParameters = FileSystemParameters
.CreateDefaultBuildinFileSystemParameters(),
CacheFileSystemParameters = FileSystemParameters
.CreateDefaultCacheFileSystemParameters(remoteServices)
};
}
case EPlayMode.OfflinePlayMode:
{
return new OfflinePlayModeParameters
{
BuildinFileSystemParameters = FileSystemParameters
.CreateDefaultBuildinFileSystemParameters()
};
}
case EPlayMode.WebPlayMode:
{
var webParams = new WebPlayModeParameters();
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITOR
string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE";
webParams.WebServerFileSystemParameters = WechatFileSystemCreater
.CreateFileSystemParameters(packageRoot, remoteServices);
#elif UNITY_WEBGL && DOUYINMINIGAME && !UNITY_EDITOR
string packageRoot = TTSDK.TTFileSystem.USER_DATA_PATH + "/__GAME_FILE_CACHE";
webParams.WebServerFileSystemParameters = TiktokFileSystemCreater
.CreateFileSystemParameters(packageRoot, remoteServices);
#else
webParams.WebServerFileSystemParameters = FileSystemParameters
.CreateDefaultWebServerFileSystemParameters();
if (remoteServices != null)
{
webParams.WebRemoteFileSystemParameters = FileSystemParameters
.CreateDefaultWebRemoteFileSystemParameters(remoteServices);
}
#endif
return webParams;
}
default:
throw new ArgumentOutOfRangeException(nameof(playMode), playMode, "Unsupported PlayMode.");
}
}
///
/// 对单个包裹执行版本请求和 Manifest 更新。
/// 所有运行模式(包括 EditorSimulateMode)都需要此步骤来填充 ActiveManifest。
///
private async UniTask RequestVersionAndUpdateForPackageAsync(string pkgName, ResourcePackage package)
{
try
{
var versionOp = package.RequestPackageVersionAsync();
await versionOp.ToUniTask();
if (versionOp.Status != EOperationStatus.Succeed)
{
Debug.LogWarning($"[YooAssetService] RequestPackageVersion failed for '{pkgName}': {versionOp.Error}");
return;
}
var manifestOp = package.UpdatePackageManifestAsync(versionOp.PackageVersion);
await manifestOp.ToUniTask();
if (manifestOp.Status != EOperationStatus.Succeed)
{
Debug.LogWarning($"[YooAssetService] UpdatePackageManifest failed for '{pkgName}': {manifestOp.Error}");
return;
}
Debug.Log($"[YooAssetService] Package '{pkgName}' manifest loaded (version={versionOp.PackageVersion}).");
}
catch (Exception ex)
{
Debug.LogWarning($"[YooAssetService] RequestVersionAndUpdate for '{pkgName}' exception: {ex.Message}");
}
}
// ====================================================================
// Asset Loading
// ====================================================================
///
/// 资源加载重试配置
///
private const int MAX_RETRY_COUNT = 3;
private const int BASE_RETRY_DELAY_MS = 500; // 500ms, 1000ms, 2000ms (exponential)
///
/// 带重试的异步操作执行器。
/// 使用指数退避策略(500ms → 1000ms → 2000ms)。
///
/// 要执行的异步操作
/// 操作名称(用于日志)
/// 取消令牌
/// 操作结果
private async UniTask ExecuteWithRetryAsync(
Func> operation,
string operationName,
CancellationToken ct = default)
{
Exception lastException = null;
for (int attempt = 0; attempt <= MAX_RETRY_COUNT; attempt++)
{
try
{
ct.ThrowIfCancellationRequested();
return await operation();
}
catch (OperationCanceledException)
{
throw; // Don't retry cancellations
}
catch (Exception ex)
{
lastException = ex;
if (attempt < MAX_RETRY_COUNT)
{
int delayMs = BASE_RETRY_DELAY_MS * (1 << attempt); // Exponential backoff
Debug.LogWarning($"[YooAssetService] {operationName} failed (attempt {attempt + 1}/{MAX_RETRY_COUNT + 1}), retrying in {delayMs}ms: {ex.Message}");
await UniTask.Delay(delayMs, cancellationToken: ct);
}
}
}
Debug.LogError($"[YooAssetService] {operationName} failed after {MAX_RETRY_COUNT + 1} attempts: {lastException?.Message}");
return default;
}
private void ThrowIfNotInitialized()
{
if (!_isInitialized)
throw new InvalidOperationException("[YooAssetService] Service not initialized. Call InitializeAsync first.");
}
///
/// 根据资源路径查找应使用的 ResourcePackage。
/// 使用 YooAssetPackageConfig 路由表确定目标包,找不到则回退到默认包。
///
private ResourcePackage FindPackageForAsset(string location)
{
var packageName = YooAssetPackageConfig.GetPackageForLocation(location);
if (_packages.TryGetValue(packageName, out var package))
return package;
// 路由到的包尚未初始化,回退到默认包 — 发出明确警告
Debug.LogWarning($"[YooAssetService] Package '{packageName}' not available for location '{location}'. " +
$"Available packages: [{string.Join(", ", _packages.Keys)}]. " +
$"Falling back to default package '{_defaultPackage?.PackageName ?? "NULL"}'." +
$"\n → This usually means SimulateBuild failed for '{packageName}'. Check earlier console errors.");
return _defaultPackage;
}
///
public async UniTask LoadAssetAsync(string location, uint priority = 0,
CancellationToken ct = default) where T : UnityEngine.Object
{
ThrowIfNotInitialized();
if (string.IsNullOrEmpty(location))
{
Debug.LogError("[YooAssetService] LoadAssetAsync: location is null or empty.");
return null;
}
var package = FindPackageForAsset(location);
return await ExecuteWithRetryAsync(async () =>
{
var handle = package.LoadAssetAsync(location, priority);
await handle.ToUniTask(cancellationToken: ct);
if (handle.Status != EOperationStatus.Succeed)
{
throw new InvalidOperationException($"LoadAssetAsync failed for '{location}': {handle.LastError}");
}
return handle.GetAssetObject();
}, $"LoadAssetAsync<{typeof(T).Name}>('{location}')", ct);
}
public void UnloadAsset(string location)
{
ThrowIfNotInitialized();
if (string.IsNullOrEmpty(location))
{
Debug.LogError("[YooAssetService] UnloadAsset: location is null or empty.");
return;
}
var package = FindPackageForAsset(location);
if (null != package)
{
YooAsset.AssetInfo assetInfo = package.GetAssetInfo(location);
if (null != assetInfo)
{
package.TryUnloadUnusedAsset(assetInfo);
}
}
}
///
public async UniTask LoadAssetAsync(string location, Type type, uint priority = 0,
CancellationToken ct = default)
{
ThrowIfNotInitialized();
if (string.IsNullOrEmpty(location))
{
Debug.LogError("[YooAssetService] LoadAssetAsync: location is null or empty.");
return null;
}
var package = FindPackageForAsset(location);
// Debug.LogError($"[YooAssetService] LoadAssetAsync: Loading asset '{location}' of package '{package.PackageName}'.");
return await ExecuteWithRetryAsync(async () =>
{
var handle = package.LoadAssetAsync(location, type, priority);
await handle.ToUniTask(cancellationToken: ct);
if (handle.Status != EOperationStatus.Succeed)
{
throw new InvalidOperationException($"LoadAssetAsync failed for '{location}': {handle.LastError}");
}
return handle.AssetObject;
}, $"LoadAssetAsync('{location}', {type.Name})", ct);
}
///
/// 同步加载资产(仅在非 WebGL 平台过渡期使用)。
///
[System.Obsolete("Use LoadAssetAsync instead. Sync loading will be removed in US2.")]
public T LoadAssetSync(string location) where T : UnityEngine.Object
{
throw new NotSupportedException("同步资源加载接口已禁用,请使用异步API");
}
///
public async UniTask LoadSubAssetsAsync(string location, uint priority = 0,
CancellationToken ct = default) where T : UnityEngine.Object
{
ThrowIfNotInitialized();
var package = FindPackageForAsset(location);
var handle = package.LoadSubAssetsAsync(location, priority);
await handle.ToUniTask();
ct.ThrowIfCancellationRequested();
if (handle.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] LoadSubAssetsAsync failed for '{location}': {handle.LastError}");
}
return handle;
}
///
public async UniTask LoadAllAssetsAsync(string location, uint priority = 0,
CancellationToken ct = default) where T : UnityEngine.Object
{
ThrowIfNotInitialized();
var package = FindPackageForAsset(location);
var handle = package.LoadAllAssetsAsync(location, priority);
await handle.ToUniTask();
ct.ThrowIfCancellationRequested();
if (handle.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] LoadAllAssetsAsync failed for '{location}': {handle.LastError}");
}
return handle;
}
// ====================================================================
// RawFile Loading
// ====================================================================
///
public async UniTask LoadRawFileTextAsync(string location, CancellationToken ct = default)
{
ThrowIfNotInitialized();
var rawPackage = FindPackageForAsset(location);
return await ExecuteWithRetryAsync(async () =>
{
var handle = rawPackage.LoadRawFileAsync(location);
await handle.ToUniTask(cancellationToken: ct);
if (handle.Status != EOperationStatus.Succeed)
{
throw new InvalidOperationException($"LoadRawFileTextAsync failed for '{location}': {handle.LastError}");
}
#if UNITY_ANDROID && !UNITY_EDITOR
// 真机:StreamingAssets在apk内,需用UnityWebRequest读取
string filePath = handle.GetRawFilePath();
using var uwr = UnityEngine.Networking.UnityWebRequest.Get(filePath);
await uwr.SendWebRequest().ToUniTask(cancellationToken: ct);
if (uwr.result != UnityEngine.Networking.UnityWebRequest.Result.Success)
throw new InvalidOperationException($"LoadRawFileTextAsync UWR failed for '{location}': {uwr.error}");
return uwr.downloadHandler.text;
#else
return handle.GetRawFileText();
#endif
}, $"LoadRawFileTextAsync('{location}')", ct);
}
///
public async UniTask LoadRawFileBytesAsync(string location, CancellationToken ct = default)
{
ThrowIfNotInitialized();
var rawPackage = FindPackageForAsset(location);
return await ExecuteWithRetryAsync(async () =>
{
var handle = rawPackage.LoadRawFileAsync(location);
await handle.ToUniTask(cancellationToken: ct);
if (handle.Status != EOperationStatus.Succeed)
{
throw new InvalidOperationException($"LoadRawFileBytesAsync failed for '{location}': {handle.LastError}");
}
#if UNITY_ANDROID && !UNITY_EDITOR
// 真机:StreamingAssets在apk内,需用UnityWebRequest读取
string filePath = handle.GetRawFilePath();
using var uwr = UnityEngine.Networking.UnityWebRequest.Get(filePath);
await uwr.SendWebRequest().ToUniTask(cancellationToken: ct);
if (uwr.result != UnityEngine.Networking.UnityWebRequest.Result.Success)
throw new InvalidOperationException($"LoadRawFileBytesAsync UWR failed for '{location}': {uwr.error}");
return uwr.downloadHandler.data;
#else
return handle.GetRawFileData();
#endif
}, $"LoadRawFileBytesAsync('{location}')", ct);
}
// ====================================================================
// Scene Loading
// ====================================================================
///
public async UniTask LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single,
LocalPhysicsMode physicsMode = LocalPhysicsMode.None, bool suspendLoad = false, uint priority = 0, CancellationToken ct = default)
{
ThrowIfNotInitialized();
var package = FindPackageForAsset(location);
var handle = package.LoadSceneAsync(location, sceneMode, physicsMode, suspendLoad, priority);
await handle.ToUniTask();
ct.ThrowIfCancellationRequested();
if (handle.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] LoadSceneAsync failed for '{location}': {handle.LastError}");
}
return handle;
}
// ====================================================================
// Query
// ====================================================================
///
public bool CheckLocationValid(string location)
{
ThrowIfNotInitialized();
// 先用路由包检查,找不到则遍历所有包
var package = FindPackageForAsset(location);
if (package.CheckLocationValid(location))
return true;
foreach (var kvp in _packages)
{
if (kvp.Value != package && kvp.Value.CheckLocationValid(location))
return true;
}
return false;
}
///
public YooAsset.AssetInfo[] GetAssetInfosByTag(string tag)
{
ThrowIfNotInitialized();
// 从所有包收集指定标签的资源信息
var allInfos = new List();
foreach (var kvp in _packages)
{
var infos = kvp.Value.GetAssetInfos(tag);
if (infos != null && infos.Length > 0)
allInfos.AddRange(infos);
}
return allInfos.ToArray();
}
///
public bool IsNeedDownloadFromRemote(string location)
{
ThrowIfNotInitialized();
var package = FindPackageForAsset(location);
return package.IsNeedDownloadFromRemote(location);
}
// ====================================================================
// Download
// ====================================================================
///
public async UniTask DownloadByTagsAsync(string[] tags, int downloadingMaxNumber = 10,
int failedTryAgain = 3, IProgress progress = null, CancellationToken ct = default)
{
ThrowIfNotInitialized();
foreach (var tag in tags)
{
// 对所有包按标签创建下载器
foreach (var kvp in _packages)
{
var downloader = kvp.Value.CreateResourceDownloader(tag, downloadingMaxNumber, failedTryAgain);
if (downloader.TotalDownloadCount == 0)
continue;
downloader.BeginDownload();
while (!downloader.IsDone)
{
ct.ThrowIfCancellationRequested();
progress?.Report(downloader.Progress);
await UniTask.Yield();
}
if (downloader.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] Download tag '{tag}' from package '{kvp.Key}' failed: {downloader.Error}");
throw new InvalidOperationException($"Resource download failed for tag '{tag}': {downloader.Error}");
}
}
}
progress?.Report(1f);
}
// ====================================================================
// Version Management
// ====================================================================
///
public async UniTask RequestPackageVersionAsync(CancellationToken ct = default)
{
ThrowIfNotInitialized();
var op = _defaultPackage.RequestPackageVersionAsync();
await op.ToUniTask();
ct.ThrowIfCancellationRequested();
if (op.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] RequestPackageVersion failed: {op.Error}");
throw new InvalidOperationException($"Request package version failed: {op.Error}");
}
return op.PackageVersion;
}
///
public async UniTask UpdatePackageManifestAsync(string packageVersion, CancellationToken ct = default)
{
ThrowIfNotInitialized();
var op = _defaultPackage.UpdatePackageManifestAsync(packageVersion);
await op.ToUniTask();
ct.ThrowIfCancellationRequested();
if (op.Status != EOperationStatus.Succeed)
{
Debug.LogError($"[YooAssetService] UpdatePackageManifest failed: {op.Error}");
throw new InvalidOperationException($"Update package manifest failed: {op.Error}");
}
}
// ====================================================================
// Release
// ====================================================================
///
public void ReleaseHandle(HandleBase handle)
{
if (handle == null) return;
handle.Release();
}
///
public async UniTask UnloadUnusedAssetsAsync()
{
ThrowIfNotInitialized();
// 对所有包执行卸载
foreach (var kvp in _packages)
{
var op = kvp.Value.UnloadUnusedAssetsAsync();
await op.ToUniTask();
}
}
///
public async UniTask UnloadAllAssetsAsync()
{
ThrowIfNotInitialized();
// 对所有包执行卸载
foreach (var kvp in _packages)
{
var op = kvp.Value.UnloadAllAssetsAsync();
await op.ToUniTask();
}
}
// ====================================================================
// IYooAssetBridge Implementation
// ====================================================================
async UniTask IYooAssetBridge.LoadAssetAsync(string location)
{
return await LoadAssetAsync(location);
}
async UniTask IYooAssetBridge.LoadRawFileTextAsync(string location)
{
return await LoadRawFileTextAsync(location);
}
async UniTask IYooAssetBridge.LoadRawFileBytesAsync(string location)
{
return await LoadRawFileBytesAsync(location);
}
async UniTask IYooAssetBridge.PreloadAsync(string[] locations)
{
// 批量预加载,使用 UniTask.WhenAll 并行
var tasks = new List(locations.Length);
foreach (var loc in locations)
{
tasks.Add(LoadAssetAsync(loc).AsUniTask());
}
await UniTask.WhenAll(tasks);
}
T IYooAssetBridge.GetCached(string location)
{
// 委托给 ResourceCacheManager(US4 已集成)
if (ProjSG.Resource.ResourceCacheManager.IsValid())
{
return ProjSG.Resource.ResourceCacheManager.Instance.GetCached(location);
}
return null;
}
// ====================================================================
// Sync Wrappers (Transitional — removed in US2)
// ====================================================================
///
/// 同步加载所有同类型资源(过渡期使用)。
///
[System.Obsolete("Use LoadAllAssetsAsync instead. Sync loading will be removed in US2.")]
public AllAssetsHandle LoadAllAssetsSync(string location) where T : UnityEngine.Object
{
ThrowIfNotInitialized();
var package = FindPackageForAsset(location);
return package.LoadAllAssetsSync(location);
}
#if UNITY_WEBGL
///
/// WebGL 诊断:输出每个 YooAsset 包的初始化状态和资源数量。
///
private void DiagDumpPackageStatus()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("[YooAssetService][WebGL-Diag] Package status dump:");
foreach (var kv in _packages)
{
var pkg = kv.Value;
var status = pkg.InitializeStatus;
// 尝试获取清单中的资源信息数量
int assetCount = 0;
try
{
// GetAssetInfos 返回该包所有资源信息
var infos = pkg.GetAssetInfos(string.Empty);
assetCount = infos != null ? infos.Length : -1;
}
catch
{
assetCount = -1;
}
sb.AppendLine($" [{kv.Key}] status={status}, assetInfoCount={assetCount}");
}
Debug.Log(sb.ToString());
}
#endif
}
}