GameFramework源码分析(三)- 数据表模块与读取解析
数据表模块
在GF中,只提供了数据表的数据结构,以及数据表管理器和数据解析前的流程。具体的解析操作,没有实现。
先看看解析前的整个流程:
创建表对象
dataTable = m_DataTableManager.CreateDataTable ->
/// <summary>
/// 创建数据表。
/// </summary>
/// <param name="dataRowType">数据表行的类型。</param>
/// <param name="name">数据表名称。</param>
/// <returns>要创建的数据表。</returns>
public DataTableBase CreateDataTable(Type dataRowType, string name)
{
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.");
}
if (dataRowType == null)
{
throw new GameFrameworkException("Data row type is invalid.");
}
if (!typeof(IDataRow).IsAssignableFrom(dataRowType))
{
throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName));
}
TypeNamePair typeNamePair = new TypeNamePair(dataRowType, name);
if (HasDataTable(dataRowType, name))
{
throw new GameFrameworkException(Utility.Text.Format("Already exist data table '{0}'.", typeNamePair));
}
Type dataTableType = typeof(DataTable<>).MakeGenericType(dataRowType);
DataTableBase dataTable = (DataTableBase)Activator.CreateInstance(dataTableType, name);
dataTable.SetResourceManager(m_ResourceManager);
dataTable.SetDataProviderHelper(m_DataProviderHelper);
m_DataTables.Add(typeNamePair, dataTable);
return dataTable;
}
......
......
读取数据
dataTable.ReadData -> DataProvider.ReadData ->resource.loadAsset ->
/// <summary>
/// 读取数据表。
/// </summary>
/// <param name="dataTableAssetName">数据表资源名称。</param>
public void ReadData(string dataTableAssetName)
{
m_DataProvider.ReadData(dataTableAssetName);
}
/// <summary>
/// 读取数据表。
/// </summary>
/// <param name="dataTableAssetName">数据表资源名称。</param>
/// <param name="priority">加载数据表资源的优先级。</param>
public void ReadData(string dataTableAssetName, int priority)
{
m_DataProvider.ReadData(dataTableAssetName, priority);
}
......
......
[在Unity端实现]读取数据
DataTableHelperBase.ReadData ->
/// <summary>
/// 读取数据表。
/// </summary>
/// <param name="dataTable">数据表。</param>
/// <param name="dataTableAssetName">数据表资源名称。</param>
/// <param name="dataTableAsset">数据表资源。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否读取数据表成功。</returns>
public abstract bool ReadData(DataTableBase dataTable, string dataTableAssetName, object dataTableAsset, object userData);
/// <summary>
/// 读取数据表。
/// </summary>
/// <param name="dataTable">数据表。</param>
/// <param name="dataTableAssetName">数据表资源名称。</param>
/// <param name="dataTableBytes">数据表二进制流。</param>
/// <param name="startIndex">数据表二进制流的起始位置。</param>
/// <param name="length">数据表二进制流的长度。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否读取数据表成功。</returns>
public abstract bool ReadData(DataTableBase dataTable, string dataTableAssetName, byte[] dataTableBytes, int startIndex, int length, object userData);
/// <summary>
/// 解析数据表。
/// </summary>
/// <param name="dataTable">数据表。</param>
/// <param name="dataTableString">要解析的数据表字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表成功。</returns>
public abstract bool ParseData(DataTableBase dataTable, string dataTableString, object userData);
解析数据表
DataTableBase.ParseData ->DataProvider.ParseData ->
/// <summary>
/// 解析数据表。
/// </summary>
/// <param name="dataTableString">要解析的数据表字符串。</param>
/// <returns>是否解析数据表成功。</returns>
public bool ParseData(string dataTableString)
{
return m_DataProvider.ParseData(dataTableString);
}
/// <summary>
/// 解析数据表。
/// </summary>
/// <param name="dataTableString">要解析的数据表字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表成功。</returns>
public bool ParseData(string dataTableString, object userData)
{
return m_DataProvider.ParseData(dataTableString, userData);
}
......
......
[在Unity端实现]解析数据表
DataTableHelperBase.ParseData ->
/// <summary>
/// 解析数据表。
/// </summary>
/// <param name="dataTable">数据表。</param>
/// <param name="dataTableString">要解析的数据表字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表成功。</returns>
public abstract bool ParseData(DataTableBase dataTable, string dataTableString, object userData);
/// <summary>
/// 解析数据表。
/// </summary>
/// <param name="dataTable">数据表。</param>
/// <param name="dataTableBytes">要解析的数据表二进制流。</param>
/// <param name="startIndex">数据表二进制流的起始位置。</param>
/// <param name="length">数据表二进制流的长度。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表成功。</returns>
public abstract bool ParseData(DataTableBase dataTable, byte[] dataTableBytes, int startIndex, int length, object userData);
向数据结构追加行
DataTableBase.AddDataRow ->
/// <summary>
/// 增加数据表行。
/// </summary>
/// <param name="dataRowString">要解析的数据表行字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否增加数据表行成功。</returns>
public abstract bool AddDataRow(string dataRowString, object userData);
/// <summary>
/// 增加数据表行。
/// </summary>
/// <param name="dataRowBytes">要解析的数据表行二进制流。</param>
/// <param name="startIndex">数据表行二进制流的起始位置。</param>
/// <param name="length">数据表行二进制流的长度。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否增加数据表行成功。</returns>
public abstract bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData);
解析行
IDataRow.ParseDataRow ->
/// <summary>
/// 解析数据表行。
/// </summary>
/// <param name="dataRowString">要解析的数据表行字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表行成功。</returns>
bool ParseDataRow(string dataRowString, object userData);
/// <summary>
/// 解析数据表行。
/// </summary>
/// <param name="dataRowBytes">要解析的数据表行二进制流。</param>
/// <param name="startIndex">数据表行二进制流的起始位置。</param>
/// <param name="length">数据表行二进制流的长度。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表行成功。</returns>
bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData);
[在Unity端实现] 解析行
DataRowBase.ParseDataRow
/// <summary>
/// 解析数据表行。
/// </summary>
/// <param name="dataRowString">要解析的数据表行字符串。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表行成功。</returns>
public virtual bool ParseDataRow(string dataRowString, object userData)
{
Log.Warning("Not implemented ParseDataRow(string dataRowString, object userData).");
return false;
}
/// <summary>
/// 解析数据表行。
/// </summary>
/// <param name="dataRowBytes">要解析的数据表行二进制流。</param>
/// <param name="startIndex">数据表行二进制流的起始位置。</param>
/// <param name="length">数据表行二进制流的长度。</param>
/// <param name="userData">用户自定义数据。</param>
/// <returns>是否解析数据表行成功。</returns>
public virtual bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
{
Log.Warning("Not implemented ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData).");
return false;
}
m_DataSet更新
private sealed class DataTable<T> : DataTableBase, IDataTable<T> where T : class, IDataRow, new()
{
private readonly Dictionary<int, T> m_DataSet;
......
......
private void InternalAddDataRow(T dataRow)
{
if (m_DataSet.ContainsKey(dataRow.Id))
{
throw new GameFrameworkException(Utility.Text.Format("Already exist '{0}' in data table '{1}'.", dataRow.Id, new TypeNamePair(typeof(T), Name)));
}
m_DataSet.Add(dataRow.Id, dataRow);
if (m_MinIdDataRow == null || m_MinIdDataRow.Id > dataRow.Id)
{
m_MinIdDataRow = dataRow;
}
if (m_MaxIdDataRow == null || m_MaxIdDataRow.Id < dataRow.Id)
{
m_MaxIdDataRow = dataRow;
}
}
}
以上的流程中,读取和解析工作由DataProvider与DataTableHelperBase实现类共同来完成。其中引入DataTableHelperBase(IDataProviderHelp)的原因可能是需要使用到unity端的接口。
获取数据
dataTable = datamgr.GetDataTable<T>
datas = dataTable.GetDataAllRow()
读取与解析
很多模块都涉及到数据读取与处理,而他们所作的工作可能都有所不同,比如处理的格式。
GF抽象出了IDataProvider接口,就用于负责数据读取与解析。这样通过实现重写IDataProvider接口,模块只需要接入IDataProvider的实现,就可以完成不同的具体工作。所有读取操作,不仅是IDataProvider,在进行读取前都需要将文件部分内容载入内存读写,这部分是高度可抽象的。因此这部分又可以抽象为IResourceManager。
读取过程大体如下:
模块->IDataProvider.ReadData -> IResourceManager.Load ->(也可能用到IDataProviderHelper,基本都会用到,大多数都用Helper再去发起解析) ->
IDataProviderHelper.ReadData->模块.ParseData -> IDataProvider.ParseData -> IDataProviderHelper.ParseData。
来源:麦瑞克博客
链接:https://www.playcreator.cn/archives/unity/4351/
本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议,转载请注明!