Files
JJBB/Assets/Project/Script/AssetManagement/AssetPathHub/AssetPathHub.cs

261 lines
9.3 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
namespace AssetManagement
{
/// <summary>
/// Blastom: 管理整个项目的资源路径,资源是否存在等问题
/// </summary>
public class AssetPathHub
{
// 当前版本可用的streamingAsset资源
public readonly HashSet<string> streamingAssets = new HashSet<string>();
private FileStream _fileStream;
private BinaryFormatter _formatter;
private float _lastSaveTime;
private const float _autoSaveInterval = 300f;
// 网络透传的资源情况
public Dictionary<string, AssetDependencyItem> onlineAssets;
// 当前版本persistent资源情况
public Dictionary<string, string> persistAssets;
private static string persistPath
{
get { return AssetConst.persistentDataPath.Open(AssetConst.pathFile + AssetConst.bytesExtension); }
}
// 下载路径超链接
public string downloadUrl { get; private set; }
// 执行三项对比,确认每个资源的位置
// 简单处理。本身消耗不高,不进行额外优化
public void Init(string uri, AssetDependencyInfo manifest)
{
_formatter = new BinaryFormatter();
var streamingBytes =
Resources.Load<TextAsset>(AssetConst.assetPathDataPath.Open(AssetConst.pathFile)).bytes;
Dictionary<string, string> streamAssets;
using (var ms = new MemoryStream(streamingBytes))
{
streamAssets = _formatter.Deserialize(ms) as Dictionary<string, string>;
}
if (streamAssets == null)
throw new NullReferenceException("Failed to load streamingPathInfo, this is not recoverable!");
if (File.Exists(persistPath))
using (var fs = File.OpenRead(persistPath))
{
try
{
persistAssets = _formatter.Deserialize(fs) as Dictionary<string, string>;
}
catch (Exception e)
{
Debug.LogError(e);
}
}
downloadUrl = uri;
onlineAssets = new Dictionary<string, AssetDependencyItem>();
foreach (var item in manifest.assetList)
onlineAssets.Add(item.name, item);
// 注Persist资源不主动移除
// 因此不能随意排除当前不匹配的项目
if (persistAssets == null)
persistAssets = new Dictionary<string, string>();
// if (EngineManager.IsLocalRes)
// foreach (var item in manifest.assetList)
// streamingAssets.Add(item.name);
// else
// 填充StreamingAsset的情况
// 这个是整个apk阶段都不变的
foreach (var asset in streamAssets)
{
AssetDependencyItem online;
if (onlineAssets.TryGetValue(asset.Key, out online) && online.md5 == asset.Value)
streamingAssets.Add(asset.Key);
}
}
public AssetDependencyItem GetPathData(string bundleName)
{
AssetDependencyItem online;
onlineAssets.TryGetValue(bundleName, out online);
return online;
}
/// <summary>
/// 获得后台下载资源列表
/// </summary>
public List<AssetDependencyItem> GetBackgroundDownloadList()
{
var result = new List<AssetDependencyItem>();
foreach (var item in onlineAssets.Values)
if (GetPathState(item.name) == AssetPathState.online &&
item.level > 0)
result.Add(item);
result.Sort((a, b) => a.importance.CompareTo(b.importance));
return result;
}
public string[] GetAllDependencies(string bundleName)
{
AssetDependencyItem online;
var result = onlineAssets.TryGetValue(bundleName, out online) ? online.dependencies : null;
return result;
}
public int GetPathState(string bundleName)
{
var result = AssetPathState.unmarked;
if (streamingAssets.Contains(bundleName))
{
result = AssetPathState.streaming;
}
else
{
AssetDependencyItem online;
if (onlineAssets.TryGetValue(bundleName, out online))
{
string md5;
if (persistAssets.TryGetValue(bundleName, out md5))
result = md5 == online.md5 ? AssetPathState.persist : AssetPathState.online;
else
result = AssetPathState.online;
}
}
return result;
}
public string GetPersistPath(string bundleName)
{
return AssetConst.GetPersistBundle(bundleName);
}
/// <summary>
/// 强制获得在线路径
/// </summary>
public string GetDownloadPath(string bundleName)
{
string result;
AssetDependencyItem online;
if (onlineAssets.TryGetValue(bundleName, out online))
result = downloadUrl.Open(online.version.ToString()).Open(bundleName);
else
{
Debug.LogError("Unable to get path for unmarked asset " + bundleName);
result = string.Empty;
}
return result;
}
public string GetPath(string bundleName)
{
var state = 0;
string result;
AssetDependencyItem online;
if (onlineAssets.TryGetValue(bundleName, out online))
state = GetPathState(bundleName);
switch (state)
{
case AssetPathState.online:
// ReSharper disable once PossibleNullReferenceException
result = downloadUrl.Open(online.version.ToString()).Open(bundleName);
break;
case AssetPathState.persist:
result = GetPersistPath(bundleName);
break;
case AssetPathState.streaming:
result = AssetConst.streamingAssetsPath.Open(bundleName);
break;
default:
Debug.LogError("Unable to get path for unmarked asset " + bundleName);
result = string.Empty;
break;
}
return result;
}
/// <summary>
/// 加载资源失败的情况下回滚当前Persist的记录
/// </summary>
public void LoadError(string bundle)
{
if (persistAssets.ContainsKey(bundle))
persistAssets.Remove(bundle);
else
Debug.LogError(string.Format("Failed to load a non persist asset {0}! Could be some problem on I/O!", bundle));
// SavePersistPathData();
}
/// <summary>
/// 下载器下载成功后,通知更新资源配置
/// </summary>
public void DownloadComplete(BundleDownloader unit)
{
if (string.IsNullOrEmpty(unit.error))
{
AssetDependencyItem online;
if (onlineAssets.TryGetValue(unit.name, out online))
{
persistAssets[online.name] = online.md5;
if (_autoSaveInterval + Time.realtimeSinceStartup < _lastSaveTime)
SavePersistPathData();
}
else
Debug.LogError(string.Format(
"Download an asset bundle {0}, which is not required for current version!",
unit.name));
}
}
public void SavePersistPathData()
{
_lastSaveTime = Time.realtimeSinceStartup;
// 注:不创建的资源列表,防止出现问题
if (persistAssets.Count > 0)
{
if (_fileStream == null)
_fileStream = File.Open(persistPath, FileMode.OpenOrCreate);
if (_fileStream != null)
try
{
_fileStream.SetLength(0);
_formatter.Serialize(_fileStream, persistAssets);
}
catch (Exception e)
{
Debug.LogError("Failed to Write to FileStream:\n" + e);
}
else
Debug.LogError(string.Format("Failed to Open FileStream at path {0}", persistPath));
}
}
public void Dispose()
{
if (_fileStream != null)
{
_fileStream.Dispose();
_fileStream = null;
}
}
}
// 使用整数以提高Lua互用能力
public static class AssetPathState
{
// 注避开default(int)
public const int streaming = 1;
public const int persist = 2;
public const int online = 3;
public const int unmarked = 4;
}
}