unity强力配置插件

您所在的位置:网站首页 unity拼界面 unity强力配置插件

unity强力配置插件

2023-03-14 02:18| 来源: 网络整理| 查看: 265

文章目录 前言一、安装二、使用三、单表加载四、单表保存五、思路(额外扩展)总结

前言

Luban是一种配置工具,生成c#等各种语言的代码,支持导出成bytes或json等多种格式,且能检查数据错误。unity只是其中支持的一种引擎,可以想象其功能非常强大。 不但如此,在使用的时候非常简单、方便,支持类型丰富,初学者也能迅速掌握。 插件地址

一、安装

以下使用参照官方文档步骤,非初学者可直接跳过看官方文档即可,也可直接参考b站大佬的教学视频。 1、下载如下示例,找到LubanLib示例文件复制到unity项目Assets里即可(不要求和示例一样的Assets根目录) 示例 在这里插入图片描述 2、在项目的根目录新建,找到下载示例将如下三个文件移进去,MiniTemplate改为Config(别的也行) 在这里插入图片描述 在这里插入图片描述 3、编辑移过来的.bat文件,至于命名自己决定,规则如下:

dotnet %Luban.ClientServer.dll% -j cfg ^ -- ^ --define_file ^ --input_data_dir ^ --output_code_dir ^ --output_data_dir ^ --service all ^ --gen_types "code_cs_unity_json,data_json"

示例(本人项目基础类目录Assets/Scripts/Game/Base):

set WORKSPACE=.. set GEN_CLIENT=%WORKSPACE%\Luban\Tools\Luban.ClientServer\Luban.ClientServer.exe set CONF_ROOT=%WORKSPACE%\Luban\Config %GEN_CLIENT% -j cfg --^ -d %CONF_ROOT%\Defines\__root__.xml ^ --input_data_dir %CONF_ROOT%\Datas ^ --output_code_dir %WORKSPACE%/Assets/Scripts/Game/Base ^ --output_data_dir ..\Assets\StreamingAssets ^ --gen_types code_cs_unity_json,data_json ^ -s all pause 二、使用

1、运行.bat文件(如有jenkins就配置该文件即可)

using SimpleJSON; using System.IO; ... void xx(){ //加载配置表 var tables = new cfg.Tables(file => JSON.Parse(File.ReadAllText(Application.streamingAssetsPath + "/" + file + ".json"))); //使用配置表 cfg.item.Item itemInfo = tables.TbItem.Get(10000); Debug.Log(itemInfo.ToString()); // 支持 operator []用法 Debug.Log(tables.TbBaseObject[10000].Id); }

2、删除并修改unity项目的Luban/Config/Datas文件夹里的表格为自己项目的表格,即可快速食用 在这里插入图片描述

三、单表加载

细心的朋友可能发现了,上文中的默认加载方式是将表统一加载进游戏。如果有特殊需求想要将表分开加载就得自行修改,本来想改动一下,结果发现有大佬(明天不吃鱼)已经写了相关文章就直接贴这里了。 如果想改加载方式,直接修改DataManager中的ReadData和GetVOData方法改成自己的就行。 下面是我改的脚本,仅供参考:

readonly Dictionary tables = new Dictionary(); public T GetVOData(string fileName,string language = "cn") where T : IVOFun, new() { var path = Application.streamingAssetsPath +"/" + language + "/" + fileName + ".json"; if (tables.ContainsKey(fileName)) { return (T)tables[fileName]; } else { var data = new T(); if (File.Exists(path)) { //创建一个StreamReader,用来读取流 using StreamReader sr = new StreamReader(path); //将读取到的流赋值给jsonStr string text = sr.ReadToEnd(); data._LoadData(text); tables.Add(fileName, data); } else { Debug.LogError("存档文件不存在"); } return data; } } 四、单表保存

比细心的朋友更细的朋友可能发现了,只有加载功能,要是项目需要保存数据还得自己写吗?事实上,这类打表工具一般是给策划使用记录游戏数据、关卡数据,方便程序使用和热更。现在不少游戏需要随机生成地形、npc等自己存储下来的需求,储存下来后可能就代表了一个存档,如果还要自己写就太不美了。 我们想到可以自行添加修改保存json的方法,奈何自己对scriban模板引擎不太熟悉,使用示例来偷懒下。 1、示例工程Unity_Editor_json 找到目录下的EditorText移动到工程 在这里插入图片描述 2、替换文件 在这里插入图片描述 3、给tables添加接口,并修改IVOFun添加保存方法

public interface IVOFun { void _LoadData(string data); void _SaveData(string file); } public interface EditorBeanBase { public void LoadJson(JSONObject json); public void SaveJson(JSONObject json); }

4、修改bean文件的命名空间、保存方法

using Bright.Serialization; using System.Collections.Generic; using SimpleJSON; {{ name = x.name parent_def_type = x.parent_def_type parent = x.parent hierarchy_fields = x.hierarchy_fields fields = x.fields export_fields = x.export_fields hierarchy_export_fields = x.hierarchy_export_fields }} {{cs_start_name_space_grace x.namespace_with_top_module}} {{~if x.comment != '' ~}} /// /// {{x.escape_comment}} /// {{~end~}} public {{x.cs_class_modifier}} partial class {{name}} : {{if parent_def_type}} {{parent}} {{else}} EditorBeanBase {{end}} { public {{name}}() { {{~ for field in fields ~}} {{~if (cs_editor_need_init field.ctype) && !field.ctype.is_nullable ~}} {{field.convention_name}} = {{cs_editor_init_value field.ctype}}; {{~end~}} {{~end~}} } {{~if !x.is_abstract_type~}} public void LoadJson(JSONObject _json) { {{~ for field in hierarchy_fields ~}} { var _fieldJson = _json["{{field.name}}"]; if (_fieldJson != null) { {{cs_unity_editor_json_load '_fieldJson' field.convention_name field.ctype}} } } {{~end~}} } public void SaveJson(JSONObject _json) { {{~if parent~}} _json["{{x.json_type_name_key}}"] = "{{x.full_name}}"; {{~end~}} {{~ for field in hierarchy_fields ~}} {{~if field.ctype.is_nullable}} if ({{field.convention_name}} != null) { {{cs_unity_editor_json_save '_json' field.name field.convention_name field.ctype}} } {{~else~}} { {{~if (cs_is_editor_raw_nullable field.ctype)}} if ({{field.convention_name}} == null) { throw new System.ArgumentNullException(); } {{~end~}} {{cs_unity_editor_json_save '_json' field.name field.convention_name field.ctype}} } {{~end~}} {{~end~}} } {{~end~}} public static {{name}} LoadJson{{name}}(JSONNode _json) { {{~if x.is_abstract_type~}} string type = _json["{{x.json_type_name_key}}"]; {{name}} obj; switch (type) { {{~for child in x.hierarchy_not_abstract_children~}} {{~if child.namespace == x.namespace && x.namespace != '' ~}} case "{{child.full_name}}": {{~end~}} case "{{cs_impl_data_type child x}}":obj = new {{child.full_name}}(); break; {{~end~}} default: throw new SerializationException(); } {{~else~}} {{name}} obj = new {{x.full_name}}(); {{~end~}} obj.LoadJson((JSONObject)_json); return obj; } public static void SaveJson{{name}}({{name}} _obj, JSONNode _json) { {{~if x.is_abstract_type~}} _json["{{x.json_type_name_key}}"] = _obj.GetType().Name; {{~end~}} _obj.SaveJson((JSONObject)_json); } {{~ for field in fields ~}} {{~if field.comment != '' ~}} /// /// {{field.escape_comment}} /// {{~end~}} public {{cs_editor_define_type field.ctype}} {{field.convention_name}} { get; set; } {{~end~}} public {{x.cs_method_modifier}} void Resolve(Dictionary _tables) { {{~if parent_def_type~}} base.Resolve(_tables); {{~end~}} {{~ for field in export_fields ~}} {{~if field.gen_ref~}} {{cs_ref_validator_resolve field}} {{~else if field.has_recursive_ref~}} {{cs_recursive_resolve field '_tables'}} {{~end~}} {{~end~}} PostResolve(); } public {{x.cs_method_modifier}} void TranslateText(System.Func translator) { {{~if parent_def_type~}} base.TranslateText(translator); {{~end~}} {{~ for field in export_fields ~}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~ for field in hierarchy_export_fields ~}} + "{{field.convention_name}}:" + {{cs_to_string field.convention_name field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); partial void PostResolve(); } {{cs_end_name_space_grace x.namespace_with_editor_top_module}}

4、使用以下代码保存,把现有的表格进行单独保存,如果要实现存档功能把表格存在同一个文件下即可

TbBaseObject tables = new TbBaseObject(); string fileA2 = Application.streamingAssetsPath + "/a2.json"; tables._SaveData(fileA2);

注意:这里使用Editor参考修改自己的模板后,文件属性的生成格式进行了改变,部分属性(long?)格式没法用了。我这里项目不需要特殊的属性倒是没啥影响,有能力的就别替换editor模板直接进行修改吧。 还有模板的TranslateText不能使用了,进行了屏蔽,大家可以把三个模板里面的TranslateText方法全删掉。当然本地化方面有了加载单表的方法,需要切换语言的时候进行切换json即可。

下面是修改过后的三个模板: bean.tql

using Bright.Serialization; using System.Collections.Generic; using SimpleJSON; {{ name = x.name parent_def_type = x.parent_def_type parent = x.parent hierarchy_fields = x.hierarchy_fields fields = x.fields export_fields = x.export_fields hierarchy_export_fields = x.hierarchy_export_fields }} {{cs_start_name_space_grace x.namespace_with_top_module}} {{~if x.comment != '' ~}} /// /// {{x.escape_comment}} /// {{~end~}} public {{x.cs_class_modifier}} partial class {{name}} : {{if parent_def_type}} {{parent}} {{else}} EditorBeanBase {{end}} { public {{name}}() { {{~ for field in fields ~}} {{~if (cs_editor_need_init field.ctype) && !field.ctype.is_nullable ~}} {{field.convention_name}} = {{cs_editor_init_value field.ctype}}; {{~end~}} {{~end~}} } {{~if !x.is_abstract_type~}} public void LoadJson(JSONObject _json) { {{~ for field in hierarchy_fields ~}} { var _fieldJson = _json["{{field.name}}"]; if (_fieldJson != null) { {{cs_unity_editor_json_load '_fieldJson' field.convention_name field.ctype}} } } {{~end~}} } public void SaveJson(JSONObject _json) { {{~if parent~}} _json["{{x.json_type_name_key}}"] = "{{x.full_name}}"; {{~end~}} {{~ for field in hierarchy_fields ~}} {{~if field.ctype.is_nullable}} if ({{field.convention_name}} != null) { {{cs_unity_editor_json_save '_json' field.name field.convention_name field.ctype}} } {{~else~}} { {{~if (cs_is_editor_raw_nullable field.ctype)}} if ({{field.convention_name}} == null) { throw new System.ArgumentNullException(); } {{~end~}} {{cs_unity_editor_json_save '_json' field.name field.convention_name field.ctype}} } {{~end~}} {{~end~}} } {{~end~}} public static {{name}} LoadJson{{name}}(JSONNode _json) { {{~if x.is_abstract_type~}} string type = _json["{{x.json_type_name_key}}"]; {{name}} obj; switch (type) { {{~for child in x.hierarchy_not_abstract_children~}} {{~if child.namespace == x.namespace && x.namespace != '' ~}} case "{{child.full_name}}": {{~end~}} case "{{cs_impl_data_type child x}}":obj = new {{child.full_name}}(); break; {{~end~}} default: throw new SerializationException(); } {{~else~}} {{name}} obj = new {{x.full_name}}(); {{~end~}} obj.LoadJson((JSONObject)_json); return obj; } public static void SaveJson{{name}}({{name}} _obj, JSONNode _json) { {{~if x.is_abstract_type~}} _json["{{x.json_type_name_key}}"] = _obj.GetType().Name; {{~end~}} _obj.SaveJson((JSONObject)_json); } {{~ for field in fields ~}} {{~if field.comment != '' ~}} /// /// {{field.escape_comment}} /// {{~end~}} public {{cs_editor_define_type field.ctype}} {{field.convention_name}} { get; set; } {{~end~}} public {{x.cs_method_modifier}} void Resolve(Dictionary _tables) { {{~if parent_def_type~}} base.Resolve(_tables); {{~end~}} {{~ for field in export_fields ~}} {{~if field.gen_ref~}} {{cs_ref_validator_resolve field}} {{~else if field.has_recursive_ref~}} {{cs_recursive_resolve field '_tables'}} {{~end~}} {{~end~}} PostResolve(); } public override string ToString() { return "{{full_name}}{ " {{~ for field in hierarchy_export_fields ~}} + "{{field.convention_name}}:" + {{cs_to_string field.convention_name field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); partial void PostResolve(); } {{cs_end_name_space_grace x.namespace_with_editor_top_module}}

table.tql

using Bright.Serialization; using System.Collections.Generic; using SimpleJSON; {{ name = x.name key_type = x.key_ttype key_type1 = x.key_ttype1 key_type2 = x.key_ttype2 value_type = x.value_ttype }} {{cs_start_name_space_grace x.namespace_with_top_module}} {{~if x.comment != '' ~}} /// /// {{x.escape_comment}} /// {{~end~}} public sealed partial class {{name}} : IVOFun { {{~if x.is_map_table ~}} private readonly Dictionary{cs_define_type value_type}}> _dataMap; private readonly List{name}}() { _dataMap = new Dictionary{cs_define_type value_type}}>(); _dataList = new List{cs_define_type key_type}}, {{cs_define_type value_type}}> DataMap => _dataMap; public List{~if value_type.is_dynamic~}} public T GetOrDefaultAs({{cs_define_type key_type}} key) where T : {{cs_define_type value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; public T GetAs({{cs_define_type key_type}} key) where T : {{cs_define_type value_type}} => (T)_dataMap[key]; {{~end~}} public {{cs_define_type value_type}} GetOrDefault({{cs_define_type key_type}} key) => _dataMap.TryGetValue(key, out var v) ? v : null; public {{cs_define_type value_type}} Get({{cs_define_type key_type}} key) => _dataMap[key]; public {{cs_define_type value_type}} this[{{cs_define_type key_type}} key] => _dataMap[key]; public void Resolve(Dictionary _tables) { foreach(var v in _dataList) { v.Resolve(_tables); } PostResolve(); } {{~else if x.is_list_table ~}} private readonly List{~if x.is_union_index~}} private {{cs_table_union_map_type_name x}} _dataMapUnion; {{~else if !x.index_list.empty?~}} {{~for idx in x.index_list~}} private Dictionary{cs_define_type value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} public {{name}}(JSONNode _json) { _dataList = new List var _v = {{cs_define_type value_type}}.Deserialize{{value_type.bean.name}}(_row); _dataList.Add(_v); } {{~if x.is_union_index~}} _dataMapUnion = new {{cs_table_union_map_type_name x}}(); foreach(var _v in _dataList) { _dataMapUnion.Add(({{cs_table_key_list x "_v"}}), _v); } {{~else if !x.index_list.empty?~}} {{~for idx in x.index_list~}} _dataMap_{{idx.index_field.name}} = new Dictionary{cs_define_type value_type}}>(); {{~end~}} foreach(var _v in _dataList) { {{~for idx in x.index_list~}} _dataMap_{{idx.index_field.name}}.Add(_v.{{idx.index_field.convention_name}}, _v); {{~end~}} } {{~end~}} PostInit(); } public List{~if x.is_union_index~}} public {{cs_define_type value_type}} Get({{cs_table_get_param_def_list x}}) => _dataMapUnion.TryGetValue(({{cs_table_get_param_name_list x}}), out {{cs_define_type value_type}} __v) ? __v : null; {{~else if !x.index_list.empty? ~}} {{~for idx in x.index_list~}} public {{cs_define_type value_type}} GetBy{{idx.index_field.convention_name}}({{cs_define_type idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{cs_define_type value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public void Resolve(Dictionary _tables) { foreach(var v in _dataList) { v.Resolve(_tables); } PostResolve(); } {{~else~}} private readonly {{cs_define_type value_type}} _data; public {{name}}(JSONNode _json) { if(!_json.IsArray) { throw new SerializationException(); } if (_json.Count != 1) throw new SerializationException("table mode=one, but size != 1"); _data = {{cs_define_type value_type}}.Deserialize{{value_type.bean.name}}(_json[0]); PostInit(); } {{~ for field in value_type.bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{field.escape_comment}} /// {{~end~}} public {{cs_define_type field.ctype}} {{field.convention_name}} => _data.{{field.convention_name}}; {{~end~}} public void Resolve(Dictionary _tables) { _data.Resolve(_tables); PostResolve(); } {{~end~}} public void _LoadData(string data) { JSONNode _json = JSON.Parse(data); foreach(JSONNode _row in _json.Children) { var _v = {{cs_define_type value_type}}.LoadJson{{value_type.bean.name}}(_row); _dataList.Add(_v); _dataMap.Add(_v.{{x.index_field.convention_name}}, _v); } PostInit(); } public void _SaveData(string file) { JSONArray jsons = new JSONArray(); foreach (var v in _dataList) { JSONObject json = new JSONObject(); v.SaveJson(json); jsons.Add(json); } System.IO.File.WriteAllText(file, jsons.ToString(), System.Text.Encoding.UTF8); } partial void PostInit(); partial void PostResolve(); } {{cs_end_name_space_grace x.namespace_with_top_module}}

tables.tql

using Bright.Serialization; using SimpleJSON; {{ name = x.name namespace = x.namespace tables = x.tables }} {{cs_start_name_space_grace x.namespace}} //所有V0对象必须继承该接口 //在数据加载时调用 LoadData(外部读取的源数据) public interface IVOFun { void _LoadData(string data); void _SaveData(string file); } public interface EditorBeanBase { public void LoadJson(JSONObject json); public void SaveJson(JSONObject json); } public sealed partial class {{name}} { {{~for table in tables ~}} {{~if table.comment != '' ~}} /// /// {{table.escape_comment}} /// {{~end~}} public {{table.full_name}} {{table.name}} {get; } {{~end~}} public {{name}}(System.Func loader){ } partial void PostInit(); partial void PostResolve(); } {{cs_end_name_space_grace x.namespace}} 五、思路(额外扩展)

顺便说下个人的项目思路,仅供参考。这里比较麻烦的就是考虑了多语言切换,第一个最简单的办法就是限制只能游戏开始界面切换语言,切换的时候只要刷新界面语言或者重新加载界面即可;第二个就是在游戏中切换语言的时候,将基础数据表格重新加载,游戏中各种对应文本也进行切换。 很明显我做的是pc端游戏,而且考虑到现在切换语言这种东西已经默认在开始界面设置了,毕竟随时切换的那种费时费力还不讨好。

void LoadData(string language) { if ("第一次加载") { //加载表格 var terrain = DataManager.Instance.GetVOData("xxx", language); var character = DataManager.Instance.GetVOData("xxx", language); var story = DataManager.Instance.GetVOData("xxx", language); //通过基础数据进行世界生成 //... //保存存档到TbWorld、tbCharacter等表; //表格内存的基本上都是基本类型的Id,比如人物存的是 人物类型Id、人物名称、人物经历Id的集合、人物的关系Id的集合 //... } else { //加载表格 var v = DataManager.Instance.GetVOData("xxx", language); var character = DataManager.Instance.GetVOData("xxx", language); var story = DataManager.Instance.GetVOData("xxx", language); //加载TbWorld、tbCharacter等表 //... //将真正的(某种语言)游戏数据整合 //... } } 总结

老项目一般都用py写的打表工具,有诸多限制(一般只能是普通的数据类型,支持list、数值,如果有复杂的结构得靠多个表格堆)。Luban很好的解决了不少潜在的问题,使用中也比较稳定,欢迎大家一起使用。 吐槽下csdn保存文章,之前写的有点不全面——于是我进行了小修改,但是登录过期了导致重新登录后没保存上,又重新整了一遍。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3