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