//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 loyalsoft. All rights reserved.
// Homepage: http://www.game7000.com/
// Feedback: http://www.game7000.com/
//------------------------------------------------------------
using GameFramework.Resource;
using System;
namespace GameFramework
{
///
/// 数据提供者。
///
/// 数据提供者的持有者的类型。
internal sealed class DataProvider : IDataProvider
{
private const int BlockSize = 1024 * 4;
private static byte[] s_CachedBytes = null;
private readonly T m_Owner;
private readonly LoadAssetCallbacks m_LoadAssetCallbacks;
private readonly LoadBinaryCallbacks m_LoadBinaryCallbacks;
private IResourceManager m_ResourceManager;
private IDataProviderHelper m_DataProviderHelper;
private EventHandler m_ReadDataSuccessEventHandler;
private EventHandler m_ReadDataFailureEventHandler;
private EventHandler m_ReadDataUpdateEventHandler;
private EventHandler m_ReadDataDependencyAssetEventHandler;
///
/// 初始化数据提供者的新实例。
///
/// 数据提供者的持有者。
public DataProvider(T owner)
{
m_Owner = owner;
m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetOrBinaryFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback);
m_LoadBinaryCallbacks = new LoadBinaryCallbacks(LoadBinarySuccessCallback, LoadAssetOrBinaryFailureCallback);
m_ResourceManager = null;
m_DataProviderHelper = null;
m_ReadDataSuccessEventHandler = null;
m_ReadDataFailureEventHandler = null;
m_ReadDataUpdateEventHandler = null;
m_ReadDataDependencyAssetEventHandler = null;
}
///
/// 获取缓冲二进制流的大小。
///
public static int CachedBytesSize
{
get
{
return s_CachedBytes != null ? s_CachedBytes.Length : 0;
}
}
///
/// 读取数据成功事件。
///
public event EventHandler ReadDataSuccess
{
add
{
m_ReadDataSuccessEventHandler += value;
}
remove
{
m_ReadDataSuccessEventHandler -= value;
}
}
///
/// 读取数据失败事件。
///
public event EventHandler ReadDataFailure
{
add
{
m_ReadDataFailureEventHandler += value;
}
remove
{
m_ReadDataFailureEventHandler -= value;
}
}
///
/// 读取数据更新事件。
///
public event EventHandler ReadDataUpdate
{
add
{
m_ReadDataUpdateEventHandler += value;
}
remove
{
m_ReadDataUpdateEventHandler -= value;
}
}
///
/// 读取数据时加载依赖资源事件。
///
public event EventHandler ReadDataDependencyAsset
{
add
{
m_ReadDataDependencyAssetEventHandler += value;
}
remove
{
m_ReadDataDependencyAssetEventHandler -= value;
}
}
///
/// 确保二进制流缓存分配足够大小的内存并缓存。
///
/// 要确保二进制流缓存分配内存的大小。
public static void EnsureCachedBytesSize(int ensureSize)
{
if (ensureSize < 0)
{
throw new GameFrameworkException("Ensure size is invalid.");
}
if (s_CachedBytes == null || s_CachedBytes.Length < ensureSize)
{
FreeCachedBytes();
int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize;
s_CachedBytes = new byte[size];
}
}
///
/// 释放缓存的二进制流。
///
public static void FreeCachedBytes()
{
s_CachedBytes = null;
}
///
/// 读取数据。
///
/// 内容资源名称。
public void ReadData(string dataAssetName)
{
ReadData(dataAssetName, Constant.DefaultPriority, null);
}
///
/// 读取数据。
///
/// 内容资源名称。
/// 加载数据资源的优先级。
public void ReadData(string dataAssetName, int priority)
{
ReadData(dataAssetName, priority, null);
}
///
/// 读取数据。
///
/// 内容资源名称。
/// 用户自定义数据。
public void ReadData(string dataAssetName, object userData)
{
ReadData(dataAssetName, Constant.DefaultPriority, userData);
}
///
/// 读取数据。
///
/// 内容资源名称。
/// 加载数据资源的优先级。
/// 用户自定义数据。
public void ReadData(string dataAssetName, int priority, object userData)
{
if (m_ResourceManager == null)
{
throw new GameFrameworkException("You must set resource manager first.");
}
if (m_DataProviderHelper == null)
{
throw new GameFrameworkException("You must set data provider helper first.");
}
HasAssetResult result = m_ResourceManager.HasAsset(dataAssetName);
switch (result)
{
case HasAssetResult.AssetOnDisk:
case HasAssetResult.AssetOnFileSystem:
m_ResourceManager.LoadAsset(dataAssetName, priority, m_LoadAssetCallbacks, userData);
break;
case HasAssetResult.BinaryOnDisk:
m_ResourceManager.LoadBinary(dataAssetName, m_LoadBinaryCallbacks, userData);
break;
case HasAssetResult.BinaryOnFileSystem:
int dataLength = m_ResourceManager.GetBinaryLength(dataAssetName);
EnsureCachedBytesSize(dataLength);
if (dataLength != m_ResourceManager.LoadBinaryFromFileSystem(dataAssetName, s_CachedBytes))
{
throw new GameFrameworkException(Utility.Text.Format("Load binary '{0}' from file system with internal error.", dataAssetName));
}
try
{
if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, s_CachedBytes, 0, dataLength, userData))
{
throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName));
}
if (m_ReadDataSuccessEventHandler != null)
{
ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, 0f, userData);
m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs);
ReferencePool.Release(loadDataSuccessEventArgs);
}
}
catch (Exception exception)
{
if (m_ReadDataFailureEventHandler != null)
{
ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData);
m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs);
ReferencePool.Release(loadDataFailureEventArgs);
return;
}
throw;
}
break;
default:
throw new GameFrameworkException(Utility.Text.Format("Data asset '{0}' is '{1}'.", dataAssetName, result));
}
}
///
/// 解析内容。
///
/// 要解析的内容字符串。
/// 是否解析内容成功。
public bool ParseData(string dataString)
{
return ParseData(dataString, null);
}
///
/// 解析内容。
///
/// 要解析的内容字符串。
/// 用户自定义数据。
/// 是否解析内容成功。
public bool ParseData(string dataString, object userData)
{
if (m_DataProviderHelper == null)
{
throw new GameFrameworkException("You must set data helper first.");
}
if (dataString == null)
{
throw new GameFrameworkException("Data string is invalid.");
}
try
{
return m_DataProviderHelper.ParseData(m_Owner, dataString, userData);
}
catch (Exception exception)
{
if (exception is GameFrameworkException)
{
throw;
}
throw new GameFrameworkException(Utility.Text.Format("Can not parse data string with exception '{0}'.", exception), exception);
}
}
///
/// 解析内容。
///
/// 要解析的内容二进制流。
/// 是否解析内容成功。
public bool ParseData(byte[] dataBytes)
{
if (dataBytes == null)
{
throw new GameFrameworkException("Data bytes is invalid.");
}
return ParseData(dataBytes, 0, dataBytes.Length, null);
}
///
/// 解析内容。
///
/// 要解析的内容二进制流。
/// 用户自定义数据。
/// 是否解析内容成功。
public bool ParseData(byte[] dataBytes, object userData)
{
if (dataBytes == null)
{
throw new GameFrameworkException("Data bytes is invalid.");
}
return ParseData(dataBytes, 0, dataBytes.Length, userData);
}
///
/// 解析内容。
///
/// 要解析的内容二进制流。
/// 内容二进制流的起始位置。
/// 内容二进制流的长度。
/// 是否解析内容成功。
public bool ParseData(byte[] dataBytes, int startIndex, int length)
{
return ParseData(dataBytes, startIndex, length, null);
}
///
/// 解析内容。
///
/// 要解析的内容二进制流。
/// 内容二进制流的起始位置。
/// 内容二进制流的长度。
/// 用户自定义数据。
/// 是否解析内容成功。
public bool ParseData(byte[] dataBytes, int startIndex, int length, object userData)
{
if (m_DataProviderHelper == null)
{
throw new GameFrameworkException("You must set data helper first.");
}
if (dataBytes == null)
{
throw new GameFrameworkException("Data bytes is invalid.");
}
if (startIndex < 0 || length < 0 || startIndex + length > dataBytes.Length)
{
throw new GameFrameworkException("Start index or length is invalid.");
}
try
{
return m_DataProviderHelper.ParseData(m_Owner, dataBytes, startIndex, length, userData);
}
catch (Exception exception)
{
if (exception is GameFrameworkException)
{
throw;
}
throw new GameFrameworkException(Utility.Text.Format("Can not parse data bytes with exception '{0}'.", exception), exception);
}
}
///
/// 设置资源管理器。
///
/// 资源管理器。
internal void SetResourceManager(IResourceManager resourceManager)
{
if (resourceManager == null)
{
throw new GameFrameworkException("Resource manager is invalid.");
}
m_ResourceManager = resourceManager;
}
///
/// 设置数据提供者辅助器。
///
/// 数据提供者辅助器。
internal void SetDataProviderHelper(IDataProviderHelper dataProviderHelper)
{
if (dataProviderHelper == null)
{
throw new GameFrameworkException("Data provider helper is invalid.");
}
m_DataProviderHelper = dataProviderHelper;
}
private void LoadAssetSuccessCallback(string dataAssetName, object dataAsset, float duration, object userData)
{
try
{
if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, dataAsset, userData))
{
throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName));
}
if (m_ReadDataSuccessEventHandler != null)
{
ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, duration, userData);
m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs);
ReferencePool.Release(loadDataSuccessEventArgs);
}
}
catch (Exception exception)
{
if (m_ReadDataFailureEventHandler != null)
{
ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData);
m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs);
ReferencePool.Release(loadDataFailureEventArgs);
return;
}
throw;
}
finally
{
m_DataProviderHelper.ReleaseDataAsset(m_Owner, dataAsset);
}
}
private void LoadAssetOrBinaryFailureCallback(string dataAssetName, LoadResourceStatus status, string errorMessage, object userData)
{
string appendErrorMessage = Utility.Text.Format("Load data failure, data asset name '{0}', status '{1}', error message '{2}'.", dataAssetName, status, errorMessage);
if (m_ReadDataFailureEventHandler != null)
{
ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, appendErrorMessage, userData);
m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs);
ReferencePool.Release(loadDataFailureEventArgs);
return;
}
throw new GameFrameworkException(appendErrorMessage);
}
private void LoadAssetUpdateCallback(string dataAssetName, float progress, object userData)
{
if (m_ReadDataUpdateEventHandler != null)
{
ReadDataUpdateEventArgs loadDataUpdateEventArgs = ReadDataUpdateEventArgs.Create(dataAssetName, progress, userData);
m_ReadDataUpdateEventHandler(this, loadDataUpdateEventArgs);
ReferencePool.Release(loadDataUpdateEventArgs);
}
}
private void LoadAssetDependencyAssetCallback(string dataAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData)
{
if (m_ReadDataDependencyAssetEventHandler != null)
{
ReadDataDependencyAssetEventArgs loadDataDependencyAssetEventArgs = ReadDataDependencyAssetEventArgs.Create(dataAssetName, dependencyAssetName, loadedCount, totalCount, userData);
m_ReadDataDependencyAssetEventHandler(this, loadDataDependencyAssetEventArgs);
ReferencePool.Release(loadDataDependencyAssetEventArgs);
}
}
private void LoadBinarySuccessCallback(string dataAssetName, byte[] dataBytes, float duration, object userData)
{
try
{
if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, dataBytes, 0, dataBytes.Length, userData))
{
throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName));
}
if (m_ReadDataSuccessEventHandler != null)
{
ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, duration, userData);
m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs);
ReferencePool.Release(loadDataSuccessEventArgs);
}
}
catch (Exception exception)
{
if (m_ReadDataFailureEventHandler != null)
{
ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData);
m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs);
ReferencePool.Release(loadDataFailureEventArgs);
return;
}
throw;
}
}
}
}