261 lines
9.3 KiB
C#
261 lines
9.3 KiB
C#
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;
|
||
}
|
||
} |