Unity3d 读取配置文本自动生成C#类 (二)
接着上一篇,我们用脚本读取配置文件生成了一个C#类 现在根据配置文件中的需求来生成对应的脚本调用这个类
首先用同样的方式生成脚本的头文件和类名
/*
*生成第二个脚本 将数据存入
*/
String FilePath2 = CurDir + Pathname + "CfgTable.cs";
System.IO.StreamWriter file2 = new System.IO.StreamWriter(FilePath2, false);
//保存数据到文件
file2.Write("using System.Collections;\n");
file2.Write("using System.Collections.Generic;\n");
file2.Write("using UnityEngine;\n");
file2.Write("\n");
file2.Write("public class ");
file2.Write(Pathname+"CfgTable");
file2.Write("\n{\n\t");
定义一些通用的变量和函数
//生成一个数组将所有的类添加进来
file2.Write("private List<"+ Pathname + "> Data = new List<"+Pathname+">();\n\t");
//定义一个整型计算大小
file2.Write("private int size;\n\t");
此时生成后这个脚本的内容如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemCfgTable
{
private List<Item> Data = new List<Item>();
private int size;
}//可能没有这个大括号
这个时候我们需要根据配置信息需求来定义字典(Dictionary),用来通过字段找到相应的数据,配置文件如下
[func]为标识 每一行3条数据:
第一条数据为0或1 指返回的是类还是数组 例如:为0时定义字典为Dictionary<字段类型,Item> 为1 1时定义字典为Dictionary<字段类型,List<Item>>
第二条数据为用来作标识的字段序号,通过定义类的属性时候 第一个属性为0以此类推
public class Item
{
public readonly int id;//id
public readonly string name;//名字
public readonly string des;//描述
public readonly string des_extra;//额外描述
public readonly string des_exchange;//兑换描述
public readonly string des_produce;//产出描述
public readonly int type;//类型
public readonly int quality;//品质
public readonly int sex;//性别
public readonly int job;//职业
public readonly int kingdom;//阵营
public readonly int level;//使用等级
public readonly int out_value;//出售价格
public readonly int overlay;//叠加上限
public readonly int flag;//标志位[NL]
public readonly int expire_type;//过期类型
public readonly int expire_param;//过期参数
public readonly int open_gold;//开启所需元宝
public readonly string effect;//作用效果
public readonly int auction_type;//寄售类型
public readonly string small_icon;//40图标
public readonly string large_icon;//56icon
如图 id序号为0 name为1 以此类推
第三条数据是服务器设置配置信息传出来的备注 可以无视
因此,这里有4个需要生产的字典类型和函数,我们用如下方式生成
//生成对应的字典和查找函数
while ((line = sr.ReadLine()) != null)
{
if (line == "[func]")
{
continue;
}
else if (line == "")
{
break;
}
//读取每一行的数据
//定义字典的头部
file2.Write("private Dictionary<");
//用\t分割字符串将3个数据放入数组中
string[] vs = line.Split('\t');
//定义了2个数组将需要的2个数据添加进去
IsArray.Add(int.Parse(vs[0]));
Parameter.Add(vs[1]);
//判断用作标识的是有2个参数还是1个参数
string[] typelist = vs[1].Split(',');
//如果长度为0说明是单个标识的参数查找
if (typelist.Length == 1)
{
file2.Write(Types[int.Parse(vs[1])] + ",");
//判断返回的是数组还是类
if (int.Parse(vs[0]) == 0)
{
//将对应的标识名词作为字典名词的一部分 尽量规范代码
file2.Write(Pathname+"> DataBy" + PropertyName[int.Parse(vs[1])] + "Dic= new Dictionary<" + Types[int.Parse(vs[1])] + ","+ Pathname + ">();\n\t");
DicName.Add("DataBy" + PropertyName[int.Parse(vs[1])] + "Dic");
}
else if (int.Parse(vs[0]) == 1)
{
file2.Write(" List<"+ Pathname+">> DataBy" + PropertyName[int.Parse(vs[1])] + "Table= new Dictionary<" + Types[int.Parse(vs[1])] + ",List<"+ Pathname+">>();\n\t");
DicName.Add("DataBy" + PropertyName[int.Parse(vs[1])] + "Table");
}
}
//多个参数查找,需要用到Dictionary嵌套来实现
else
{
//先放入第一个
file2.Write(Types[int.Parse(typelist[0])] + ",");
//用for循环遍历所有参数并嵌套进来
for (int i = 1; i< typelist.Length; i++)
{
file2.Write(" Dictionary<" + Types[int.Parse(typelist[i])] + ",");
}
//判断返回的是数组还是类
ManyParameterlookup(file2, typelist, int.Parse(vs[0]));
}
}
此时 我们看看生成的脚本是什么样子的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemCfgTable
{
private List<Item> Data = new List<Item>();
private int size;
private Dictionary<int,Item> DataByidDic= new Dictionary<int,Item>();
private Dictionary<string,Item> DataBynameDic= new Dictionary<string,Item>();
private Dictionary<int, List<Item>> DataBytypeTable= new Dictionary<int,List<Item>>();
private Dictionary<int, Dictionary<string,List<Item>>> DataBytypeeffectTable= new Dictionary<int, Dictionary<string,List<Item>>>();
很好!跟我们需要生成的字典基本一致,现在需要给这个脚本添加几个函数用来调用这些字典
首先,需要有通过传入相应参数返回对应数据的函数
//实现字典的查找函数
//遍历之前存入标识的数组 来生成每个字典对应的返回函数
for (int i = 0; i < IsArray.Count; i++)
{
file2.Write("public ");
//判断返回时数组还是类
if (IsArray[i] == 0)
{
file2.Write(Pathname+" GetDateBy");
}
else
{
file2.Write("List<"+ Pathname + "> GetDateBy");
}
string[] typelist = Parameter[i].Split(',');
//判断是多参数还是单个参数
if (typelist.Length == 1)
{
file2.Write(PropertyName[int.Parse(Parameter[i])]+"("+Types[int.Parse(Parameter[i])]+" "+ PropertyName[int.Parse(Parameter[i])]+")");
file2.Write("\n\t{\n\t\treturn " + DicName[i]);
file2.Write("[" + PropertyName[int.Parse(Parameter[i])] + "];\n\t}\n\t");
}
else
{
//函数名
for (int j = 0; j < typelist.Length; j++)
{
file2.Write(PropertyName[int.Parse(typelist[j])]);
}
file2.Write("(");
//写入参数
for (int j = 0; j < typelist.Length; j++)
{
file2.Write(Types[int.Parse(typelist[j])] + " " + PropertyName[int.Parse(typelist[j])]);
if (j != typelist.Length - 1)
{
file2.Write(",");
}
}
file2.Write(")");
file2.Write("\n\t{\n\t\treturn "+ DicName[i]);
for (int j = 0; j< typelist.Length; j++)
{
file2.Write("[");
file2.Write(PropertyName[int.Parse(typelist[j])]);
file2.Write("]");
}
file2.Write(";\n\t}\n\t");
}
}
//返回字典和List函数
file2.Write("public Dictionary<int, "+ Pathname + "> GetDataTable()\n\t{\n\t\t");
file2.Write("return " + DicName[0] + ";");
file2.Write("\n\t}\n\t");
file2.Write("public List<"+ Pathname + "> GetDataList()\n\t{\n\t\t");
file2.Write("return Data;\n\t}\n\t");
生成的脚本如下:(最后两个函数酌情添加)
public Item GetDateByid(int id)
{
return DataByidDic[id];
}
public Item GetDateByname(string name)
{
return DataBynameDic[name];
}
public List<Item> GetDateBytype(int type)
{
return DataBytypeTable[type];
}
public List<Item> GetDateBytypeeffect(int type,string effect)
{
return DataBytypeeffectTable[type][effect];
}
public Dictionary<int, Item> GetDataTable()
{
return DataByidDic;
}
public List<Item> GetDataList()
{
return Data;
}
在酌情添加一个情况字典和返回长度的函数
//请空所有字典函数
file2.Write("//清空所有数据\n\t");
file2.Write(" public void ResetData()\n\t");
file2.Write("{\n\t\tData.Clear();\n\t\t");
foreach(string temp in DicName)
{
file2.Write(temp+".Clear();\n\t");
if (temp != DicName[DicName.Count - 1])
{
file2.Write("\t");
}
}
file2.Write("}\n\t");
//获取长度函数
file2.Write("public int Get_size()\n\t");
file2.Write("{\n\t\treturn size;\n\t}\n\t");
生成的脚本如下
//清空所有数据
public void ResetData()
{
Data.Clear();
DataByidDic.Clear();
DataBynameDic.Clear();
DataBytypeTable.Clear();
DataBytypeeffectTable.Clear();
}
public int Get_size()
{
return size;
}
好了,再完成了需要的函数之后,是时候该添加数据了,先定义一个能添加数据的函数,并从配置表中读取数据
配置表的信息比较好理解 每一行的每列数据对应之前生成类的配置表的对应属性
file2.Write("private void InitData()\n\t");
file2.Write("{\n\t\tResetData();\n\t\t");
//添加所有的数据
int size = 0;
while ((line = sr.ReadLine()) != null)
{
if (line == "[data]")
{
continue;
}
else if (line == "")
{
break;
}
size++;
string[] vs = line.Split('\t');
//判断是否有数据出现了异常
if (vs.Length != Types.Count)
{
string error = "";
int errornum;
if (vs.Length > Types.Count)
{
error = "多出";
errornum = vs.Length - Types.Count;
}
else
{
error = "少于";
errornum = Types.Count- vs.Length;
}
Debug.LogError("第"+size+"行数据异常,"+ error+ errornum.ToString()+"条");
return null;
}
//先写一个添加的函数名 之后再来定义它
file2.Write("AddData(");
//由于传入字符串类型时需要添加“”这里做一个判断
for(int i = 0; i < vs.Length; i++)
{
if (Types[i]=="int")
{
file2.Write(vs[i].ToString());
}
else if(Types[i] == "string")
{
file2.Write("\"" + vs[i] + "\"");
}
if (i != vs.Length - 1)
{
file2.Write(",");
}
}
file2.Write(");\n\t\t");
}
file2.Write("size=" + size+";\n\t");
file2.Write("}\n\t");
此时,生成的函数应该如下
private void InitData()
{
ResetData();
AddData(100101,"珍玉膏","每3秒回复 800 点血量,持续6秒,共回复2400点血量","冷却时间10秒","","随身商店购买、怪物掉落",1001,1,0,0,0,1,1,200,0,0,0,0,"1001:6",10012,"item_40_100101","item_56_100101");
AddData(100102,"化瘀膏","每3秒回复 1600 点血量,持续6秒,共回复4800点血量","冷却时间10秒","","随身商店购买、怪物掉落",1001,1,0,0,0,30,1,200,0,0,0,0,"1002:6",10012,"item_40_100102","item_56_100102");
AddData(100103,"活血膏","每3秒回复 3200 点血量,持续6秒,共回复9600点血量","冷却时间10秒","","随身商店购买、怪物掉落",1001,1,0,0,0,50,1,200,0,0,0,0,"1003:6",10012,"item_40_100103","item_56_100103");
AddData(100104,"归心膏","每3秒回复 6000 点血量,持续6秒,共回复18000点血量","冷却时间10秒","","随身商店购买、怪物掉落",1001,1,0,0,0,70,1,200,0,0,0,0,"1004:6",10012,"item_40_100104","item_56_100104");
………………
}
然后我们来完成这个AddData函数的构成
//添加数据函数
file2.Write("public void AddData(");
//写入参数
for(int i = 0; i < Types.Count; i++)
{
file2.Write(Types[i] + " " + PropertyName[i]);
if (i != 0 && i % 5 == 0)
{
file2.Write("\n\t\t\t");
}
if (i != Types.Count - 1)
{
file2.Write(",");
}
}
file2.Write(")\n\t{\n\t\t");
file2.Write(Pathname+" m = new "+ Pathname + "(");
//将参数添加到构造函数中
for(int i = 0; i < PropertyName.Count; i++)
{
file2.Write(PropertyName[i]);
if (i != PropertyName.Count - 1)
{
file2.Write(",");
}
if (i != 0 && i % 5 == 0)
{
file2.Write("\n\t\t");
}
}
file2.Write(");\n\t\t");
for (int i = 0; i < IsArray.Count; i++)
{
string[] typelist = Parameter[i].Split(',');
//单个查找参数
if (typelist.Length == 1)
{
//结果为类
if (IsArray[i] == 0)
{
//file2.Write("if(" + DicName[i] + ".ContainsKey(" + PropertyName[int.Parse(Parameter[i])] + "))\n\t\t{\n\t\t\t");
//file2.Write("Debug.LogError(\"有相同" + PropertyName[int.Parse(Parameter[i])] + "出现\");\n\t\t\t");
//file2.Write("return;\n\t\t}\n\t\t");
file2.Write(DicName[i] + ".Add(" + PropertyName[int.Parse(Parameter[i])] + ",m);\n\t\t");
}
//结果为数组
else if (IsArray[i] == 1)
{
file2.Write("if(!" + DicName[i] + ".ContainsKey(" + PropertyName[int.Parse(Parameter[i])] + "))\n\t\t{\n\t\t\t");
file2.Write(" List<"+ Pathname + "> items = new List<"+ Pathname + ">();\n\t\t\t");
file2.Write(DicName[i] + ".Add(" + PropertyName[int.Parse(Parameter[i])] + ",items);\n\t\t}\n\t\t");
file2.Write(DicName[i] + "[" + PropertyName[int.Parse(Parameter[i])] + "].Add(m);\n\t\t");
}
}
//多个查找参数
else if(typelist.Length > 1)
{
//遍历参数的个数
for (int y = 0; y < typelist.Length; y++)
{
//第一次要判断父字典中是否为空
if (y == 0)
{
file2.Write("if(!" + DicName[i] + ".ContainsKey(" + PropertyName[int.Parse(typelist[0])] + "))\n\t\t{\n\t\t\t");
}
else//之后获取子字典的参数名进行判断
{
file2.Write("else if(!" + DicName[i]);
for (int yy = 0; yy < y; yy++)
{
file2.Write("[" + PropertyName[int.Parse(typelist[yy])] + "]");
}
file2.Write(".ContainsKey(" + PropertyName[int.Parse(typelist[y])] + "))\n\t\t{\n\t\t\t");
}
//获取每一行添加子字典的名称
for (int j = y; j < typelist.Length; j++)
{
//最后一条数据的写入方法与其他不同 所以这里进行判断
if (j != typelist.Length - 1)
{
for (int x = j; x < typelist.Length - 1; x++)
{
file2.Write("Dictionary<" + Types[int.Parse(typelist[x + 1])] + ", ");
}
file2.Write("List<"+ Pathname + ">");
for (int x = j; x < typelist.Length - 1; x++)
{
file2.Write(">");
}
file2.Write(" dic" + j + " = new ");
for (int x = j; x < typelist.Length - 1; x++)
{
file2.Write("Dictionary<" + Types[int.Parse(typelist[x + 1])] + ", ");
}
file2.Write("List<"+ Pathname + ">");
for (int x = j; x < typelist.Length - 1; x++)
{
file2.Write(">");
}
file2.Write("();\n\t\t\t");
if (j == y)//判断是否还需要继续添加子字典的添加
{
file2.Write(DicName[i]);
for (int yy = 0; yy < y; yy++)
{
file2.Write("[" + PropertyName[int.Parse(typelist[yy])] + "]");
}
file2.Write(".Add(" + PropertyName[int.Parse(typelist[j])] + ",dic" + j + ");\n\t\t\t");
}
else
{
file2.Write("dic" + (j - 1) + ".Add(" + PropertyName[int.Parse(typelist[j])] + ",dic" + j + ");\n\t\t\t");
}
}
else//如果是最后一条数据 获取对应子字典的名字
{
file2.Write(" List<"+ Pathname+"> items = new List<"+ Pathname + ">();\n\t\t\t");
if (y == typelist.Length - 1)
{
file2.Write(DicName[i]);
for (int z = 0;z<y;z++)
{
file2.Write("[" + PropertyName[int.Parse(typelist[z])] + "]");
}
file2.Write(".Add(" + PropertyName[int.Parse(typelist[j])] + ",items);\n\t\t");
}
else
{
file2.Write("dic" + (j - 1) + ".Add(" + PropertyName[int.Parse(typelist[j])] + ",items);\n\t\t");
}
}
}
file2.Write("}\n\t\t");
}
file2.Write(DicName[i]);
for (int j = 0; j < typelist.Length; j++)
{
file2.Write("[" + PropertyName[int.Parse(typelist[j])] + "]");
}
file2.Write(".Add(m);\n\t\t");
}
}
file2.Write("Data.Add(m);");
file2.Write("\n\t}\n\t");
完成后 生成的函数如下图
public void AddData(int id,string name,string des,string des_extra,string des_exchange,string des_produce
,int type,int quality,int sex,int job,int kingdom
,int level,int out_value,int overlay,int flag,int expire_type
,int expire_param,int open_gold,string effect,int auction_type,string small_icon
,string large_icon)
{
Item m = new Item(id,name,des,des_extra,des_exchange,des_produce,
type,quality,sex,job,kingdom,
level,out_value,overlay,flag,expire_type,
expire_param,open_gold,effect,auction_type,small_icon,
large_icon);
DataByidDic.Add(id,m);
DataBynameDic.Add(name,m);
if(!DataBytypeTable.ContainsKey(type))
{
List<Item> items = new List<Item>();
DataBytypeTable.Add(type,items);
}
DataBytypeTable[type].Add(m);
if(!DataBytypeeffectTable.ContainsKey(type))
{
Dictionary<string, List<Item>> dic0 = new Dictionary<string, List<Item>>();
DataBytypeeffectTable.Add(type,dic0);
List<Item> items = new List<Item>();
dic0.Add(effect,items);
}
else if(!DataBytypeeffectTable[type].ContainsKey(effect))
{
List<Item> items = new List<Item>();
DataBytypeeffectTable[type].Add(effect,items);
}
DataBytypeeffectTable[type][effect].Add(m);
Data.Add(m);
}
最后 我们给这个函数添加上单例函数
file2.Write("private static ItemCfgTable _instance;\n\t");
file2.Write("public static ItemCfgTable getInstace()\n\t{\n\t\t");
file2.Write("if (_instance!=null)\n\t\t{\n\t\t\t");
file2.Write("return _instance;\n\t\t}\n\t\t");
file2.Write("_instance = new ItemCfgTable();\n\t\t");
file2.Write("_instance.InitData();\n\t\t");
file2.Write("return _instance;\n\t}");
file2.Write("\n}\n\t");
//关闭文件
file2.Close();
//释放对象
file2.Dispose();
生成脚本中的函数如下
private static ItemCfgTable _instance;
public static ItemCfgTable getInstace()
{
if (_instance!=null)
{
return _instance;
}
_instance = new ItemCfgTable();
_instance.InitData();
return _instance;
}
至此,就完成了这个脚本的所有内容,生成后的脚本可以调用之前生成的类 来实现数据的保存和使用。如果想添加别的字典或者是查询函数需求 只要在配置文件中做修改即可!
实现例子如下:
点击按钮 ->选择配置文件
确定后生成了2个脚本
之后 便可以直接使用这个脚本进行数据的读取
private void Start()
{
Item text = ItemCfgTable.getInstace().GetDateByid(100105);
Debug.LogError(text.name);
}