打开 Excel 目录下的 UnitConfig.xlsx
A1:根据该单元格内是否存在 AppType.ClientH 区别生成的是客户端还是服务器的配置
C3:从这里开始读取数据
读写规则:
第3行:该行为注释行内容不读取, # 开头该列不读取, s 开头该字段服务器专用
第4行:该行内容作为字段的名称,不可为空
第5行:该行内容作为字段的类型,不可为空
第6行及以下:配置的数据
当你需要在列表里面嵌套的时候,我觉得你应该重新审视一下你的逻辑
如果你实在不想考虑了,一定要嵌套!那么你可以再开一个表,这个表就是嵌套的数据,然后在需要嵌套的表里面填写该表的数据的ID!
需要嵌套的表:
被嵌套的表:
大约这么去访问,就可以得到完整数据,对扩展也友好:
var testConfig = Game.Scene.GetComponent<ConfigComponent>().Get(typeof(TestConfig),1001) as TestConfig; var test2 = Game.Scene.GetComponent<ConfigComponent>().Get(typeof(Test2Config), testConfig.a);
// 读取 TestConfig 类型所有数据 var array = Game.Scene.GetComponent<ConfigComponent>().GetAll(typeof(TestConfig)); foreach (TestConfig config in array) { Log.Debug($"{config.a}"); }
id字段是不可缺少的,不能移除id字段
点击导出客户端配置或服务器配置时报一下错误,这是由于你正在使用独占模式打开Excel导致的,关闭正在修改的Excel就好
可读取字段中存在空白数据,字段数据是不允许空白的,必须写点什么
当然你觉得这很麻烦和自己的习惯不符,你也可以修改一下源码读到空白数据直接给与一个默认值之类的
但是并不赞成这么做。直接写在表上可以直接查询该值,更有利于阅读。
并且其他人阅读的时候不会疑惑这里为什么空白一片
删除了,又没有完全删除,按下delete删除了黄色列,但实际上读取的时候还是会读到,需要删除单元格才能正常读取
点击导出客户端配置或导出服务器配置即可
正常没有报错的情况下将会在 ET\Unity\Assets\Res\Config 文件夹生成对应的配置数据
并且在
Assets/Model/Module/Demo/Config
Assets/Hotfix/Module/Demo/Config
Server/Model/Module/Demo/Config
目录下生成配置类
目录:ET\Unity\Assets\Editor\ExcelExporterEditor\ExcelExporterEditor.cs
修改类生成目录,下面路径按照自己放置位置修改就行:
private void OnGUI() { try { const string clientPath = "./Assets/Res/Config"; if (GUILayout.Button("导出客户端配置")) { this.isClient = true; ExportAll(clientPath); ExportAllClass(@"./Assets/Model/Module/Demo/Config", "namespace ETModel\n{\n"); ExportAllClass(@"./Assets/Hotfix/Module/Demo/Config", "using ETModel;\n\nnamespace ETHotfix\n{\n"); Log.Info($"导出客户端配置完成!"); } if (GUILayout.Button("导出服务端配置")) { this.isClient = false; ExportAll(ServerConfigPath); ExportAllClass(@"../Server/Model/Module/Demo/Config", "namespace ETModel\n{\n"); Log.Info($"导出服务端配置完成!"); } } catch (Exception e) { Log.Error(e); } }
扩展配置表支持的字段类型,需要支持更多类型在这里添加就可以了:
private static string Convert(string type, string value) { switch (type) { case "int[]": case "int32[]": case "long[]": return $"[{value}]"; case "string[]": return $"[{value}]"; case "int": case "int32": case "int64": case "long": case "float": case "double": return value; case "string": return $"\"{value}\""; default: throw new Exception($"不支持此类型: {type}"); } }
配置组件: ConfigComponent.cs
遍历所有配置类型,BeginInit初始化后添加到缓存
public void Load() { this.allConfig.Clear(); List<Type> types = Game.EventSystem.GetTypes(); foreach (Type type in types) { object[] attrs = type.GetCustomAttributes(typeof (ConfigAttribute), false); if (attrs.Length == 0) { continue; } ConfigAttribute configAttribute = attrs[0] as ConfigAttribute; // 只加载指定的配置 if (!configAttribute.Type.Is(AppType.ClientH)) { continue; } object obj = Activator.CreateInstance(type); ACategory iCategory = obj as ACategory; if (iCategory == null) { throw new Exception($"class: {type.Name} not inherit from ACategory"); } iCategory.BeginInit(); iCategory.EndInit(); this.allConfig[iCategory.ConfigType] = iCategory; } }
配置每一行作为一个类数据,反序列化json后保存到字典中
public override void BeginInit() { this.dict = new Dictionary<long, IConfig>(); string configStr = ConfigHelper.GetText(typeof (T).Name); foreach (string str in configStr.Split(new[] { "\n" }, StringSplitOptions.None)) { try { string str2 = str.Trim(); if (str2 == "") { continue; } T t = ConfigHelper.ToObject<T>(str2); this.dict.Add(t.Id, t); } catch (Exception e) { throw new Exception($"parser json fail: {str}", e); } } }