MVC是开发过程中最常见的开发模式,在一个游戏或者一个应用开发过程中其实看不见的数据才是中间的灵魂和关键。无论是根据网络数据回调后反序列化还是直接从本地文件中读取数据,软件运行过程其实都是数据在中间运转。
数据怎么来的呢?
策划会将数据写成Excel 表,你需要做的就是把数据读取出来。
Excel数据有了,现在就需要读取数据了。可是Unity直接读取Excel数据吗??数据就这么明白的袒露出来吗??
这里我们需要开发一个工具把Excel数据读取出来,然后加密或者混淆等方式写成自定义文件类型,Unity那边读取这个自定义类型文件就Ok了。
开发工具可以使用Python或者WinForm等方式,操作Excel数据需要
Microsoft.Office.Interop.Excel.dll
这个类库。下面直接上代码
#region ReadData 读取数据
/// <summary>
/// 读取数据
/// </summary>
/// <param name="path"></param>
private void ReadData(string path)
{
if (string.IsNullOrEmpty(path)) return;
string tableName = GetFirstSheetNameFromExcelFileName(path, 1);
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + path + ";" + "Extended Properties='Excel 8.0;HDR=NO;IMEX=1';";
DataTable dt = null;
using (OleDbConnection conn = new OleDbConnection(strConn))
{
conn.Open();
string strExcel = "";
OleDbDataAdapter myCommand = null;
DataSet ds = null;
strExcel = string.Format("select * from [{0}$]", tableName);
myCommand = new OleDbDataAdapter(strExcel, strConn);
ds = new DataSet();
myCommand.Fill(ds, "table1");
dt = ds.Tables[0];
myCommand.Dispose();
}
CreateData(path, dt);
}
#endregion
#region CreateData 生成加密后的文件
/// <summary>
/// 生成加密后的文件
/// </summary>
/// <param name="path"></param>
/// <param name="dt"></param>
private void CreateData(string path, DataTable dt)
{
//数据格式 行数 列数 二维数组每项的值 这里不做判断 都用string存储
string filePath = path.Substring(0, path.LastIndexOf('\\') + 1);
string fileFullName = path.Substring(path.LastIndexOf('\\') + 1);
string fileName = fileFullName.Substring(0, fileFullName.LastIndexOf('.'));
byte[] buffer = null;
string[,] dataArr = null;
using (MemoryStreamBuffer ms = new MemoryStreamBuffer())
{
int row = dt.Rows.Count;
int columns = dt.Columns.Count;
dataArr = new string[columns, 3];
ms.WriteInt(row);
ms.WriteInt(columns);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < columns; j++)
{
if (i < 3)
{
dataArr[j, i] = dt.Rows[i][j].ToString().Trim();
}
ms.WriteUTF8String(dt.Rows[i][j].ToString().Trim());
}
}
buffer = ms.ToArray();
}
//------------------
//第1步:xor加密
//------------------
int iScaleLen = xorScale.Length;
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(buffer[i] ^ xorScale[i % iScaleLen]);
}
//------------------
//第2步:压缩
//------------------
//压缩后的字节流
buffer = ZlibHelper.CompressBytes(buffer);
//------------------
//第3步:写入文件
//------------------
FileStream fs = new FileStream(string.Format("{0}{1}", filePath, fileName + ".data"), FileMode.Create);
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
#endregion
运行后生成为 .data 类型的文件,Unity端直接加载文件后通过解压,解密后得到Byte[] 数据,然后通过字节流读取出来就Ok了。
抽象封装一个实体类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 数据实体基类
/// </summary>
public class AbstractEntity {
/// <summary>
/// 编号
/// </summary>
public int Id
{
get;
set;
}
}
这边的
Id
为
数据编号
,可以理解为SQL 中的主键。
好像每一个Excel存储的数据类型都不一样哦,每次手动去写实体类,太麻烦了,怎么办呢? 还是用工具帮忙写一下把。
/// <summary>
/// 创建实体
/// </summary>
private void CreateEntity(string filePath, string fileName, string[,] dataArr)
{
if (dataArr == null) return;
if (!Directory.Exists(string.Format("{0}Create", filePath)))
{
Directory.CreateDirectory(string.Format("{0}Create", filePath));
}
if (!Directory.Exists(string.Format("{0}CreateLua", filePath)))
{
Directory.CreateDirectory(string.Format("{0}CreateLua", filePath));
}
StringBuilder sbr = new StringBuilder();
sbr.Append("using System.Collections;\r\n");
sbr.Append("\r\n");
sbr.Append("/// <summary>\r\n");
sbr.AppendFormat("/// {0}实体\r\n", fileName);
sbr.Append("/// </summary>\r\n");
sbr.AppendFormat("public partial class {0}Entity : AbstractEntity\r\n", fileName);
sbr.Append("{\r\n");
for (int i = 0; i < dataArr.GetLength(0); i++)
{
if (i == 0) continue;
sbr.Append(" /// <summary>\r\n");
sbr.AppendFormat(" /// {0}\r\n", dataArr[i, 2]);
sbr.Append(" /// </summary>\r\n");
sbr.AppendFormat(" public {0} {1} {{ get; set; }}\r\n", dataArr[i, 1], dataArr[i, 0]);
sbr.Append("\r\n");
}
sbr.Append("}\r\n");
using (FileStream fs = new FileStream(string.Format("{0}Create/{1}Entity.cs", filePath, fileName), FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(sbr.ToString());
}
}
}
封装数据Model层,这里的Model主要适用于列表类型的数据。实例化操作Entity的数据管理类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class AbstractDBModel<T,P>
where T:class,new()
where P:AbstractEntity
{
protected List<P> m_List;
protected Dictionary<int, P> m_dic;
public AbstractDBModel()
{
m_List = new List<P>();
m_dic = new Dictionary<int, P>();
LoadData();
}
public static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = new T();
// instance.;
}
return instance;
}
}
//获取文件名称
protected abstract string FileName { get; }
//获取实体
protected abstract P MakeEntity(GameDataTableParser parse);
/// <summary>
/// 加载数据
/// </summary>
private void LoadData()
{
string path = null;
#if DISABLE_ASSETBUNDLE && UNITY_EDITOR
path = Application.dataPath + "/Download/DataTable/" + FileName;
#else
path = Application.persistentDataPath + "/Download/DataTable/" + FileName;
#endif
//读文件
using (DataTableParser parse = new DataTableParser(path))
{
while (!parse.Eof)
{
//创建实体
P p = MakeEntity(parse);
m_List.Add(p);
m_dic[p.Id] = p;
parse.Next();
}
}
//解压缩
}
/// <summary>
/// 获取数据列表
/// </summary>
/// <returns></returns>
public List<P> GetList()
{
return m_List;
}
/// <summary>
/// 根据编号查询
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public P Get(int id)
{
if (m_dic.ContainsKey(id))
{
return m_dic[id];
}
return null;
}
}
利用工具生成数据管理类
/// <summary>
/// 创建数据管理类
/// </summary>
private void CreateDBModel(string filePath, string fileName, string[,] dataArr)
{
if (dataArr == null) return;
if (!Directory.Exists(string.Format("{0}Create", filePath)))
{
Directory.CreateDirectory(string.Format("{0}Create", filePath));
}
StringBuilder sbr = new StringBuilder();
sbr.Append("\r\n");
sbr.Append("//===================================================\r\n");
sbr.AppendFormat("//创建时间:{0}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
sbr.Append("//===================================================\r\n");
sbr.Append("using System.Collections;\r\n");
sbr.Append("using System.Collections.Generic;\r\n");
sbr.Append("using System;\r\n");
sbr.Append("\r\n");
sbr.Append("/// <summary>\r\n");
sbr.AppendFormat("/// {0}数据管理\r\n", fileName);
sbr.Append("/// </summary>\r\n");
sbr.AppendFormat("public partial class {0}DBModel : AbstractDBModel<{0}DBModel, {0}Entity>\r\n", fileName);
sbr.Append("{\r\n");
sbr.Append(" /// <summary>\r\n");
sbr.Append(" /// 文件名称\r\n");
sbr.Append(" /// </summary>\r\n");
sbr.AppendFormat(" protected override string FileName {{ get {{ return \"{0}.data\"; }} }}\r\n", fileName);
sbr.Append("\r\n");
sbr.Append(" /// <summary>\r\n");
sbr.Append(" /// 创建实体\r\n");
sbr.Append(" /// </summary>\r\n");
sbr.Append(" /// <param name=\"parse\"></param>\r\n");
sbr.Append(" /// <returns></returns>\r\n");
sbr.AppendFormat(" protected override {0}Entity MakeEntity(GameDataTableParser parse)\r\n", fileName);
sbr.Append(" {\r\n");
sbr.AppendFormat(" {0}Entity entity = new {0}Entity();\r\n", fileName);
for (int i = 0; i < dataArr.GetLength(0); i++)
{
sbr.AppendFormat(" entity.{0} = parse.GetFieldValue(\"{0}\"){1};\r\n", dataArr[i, 0], ChangeTypeName(dataArr[i, 1]));
}
sbr.Append(" return entity;\r\n");
sbr.Append(" }\r\n");
sbr.Append("}\r\n");
using (FileStream fs = new FileStream(string.Format("{0}Create/{1}DBModel.cs", filePath, fileName), FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(sbr.ToString());
}
}
}
版权声明:本文为weixin_44813507原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。