Files
JJBB/Assets/Project/Script/AssetManagement/AssetPathHub/AssetPathHub.cs
2024-08-23 15:49:34 +08:00

261 lines
9.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}