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),用来通过字段找到相应的数据,配置文件如下Unity3d 读取配置文本自动生成C#类 (二)

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

好了,再完成了需要的函数之后,是时候该添加数据了,先定义一个能添加数据的函数,并从配置表中读取数据

Unity3d 读取配置文本自动生成C#类 (二)

配置表的信息比较好理解 每一行的每列数据对应之前生成类的配置表的对应属性 

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

  至此,就完成了这个脚本的所有内容,生成后的脚本可以调用之前生成的类 来实现数据的保存和使用。如果想添加别的字典或者是查询函数需求 只要在配置文件中做修改即可!

实现例子如下:

点击按钮 ->选择配置文件

Unity3d 读取配置文本自动生成C#类 (二)

确定后生成了2个脚本

Unity3d 读取配置文本自动生成C#类 (二)

之后 便可以直接使用这个脚本进行数据的读取

    private void Start()
    {
        Item text = ItemCfgTable.getInstace().GetDateByid(100105);
        Debug.LogError(text.name);
    }