基于Unity的高效配置表读取方案
发表于2017-03-16
Unity 的行为可以通过配置来指定,使用 XML 文件来配置 Unity,也可以从任何格式的文件或者其他数据源中加载配置信息,在做配置表文件配置时因为太大遇到了问题,下面就给大家介绍下基于unity的高效配置表读取方案。
· [StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
· [MarshalAs(UnmanagedType.ByValArray,SizeConst=ResMacros.C_PRE_QUEST_SIZE)]
· string使用int做key,使用时,去查找,而不是在ResSturct里保存一个string指针
1 2 3 | [MarshalAs(UnmanagedType.ByValArray, SizeConst=ResMacros.C_QUEST_REQUEST_MAX_COUNT)] private ResQuestRequest[] _request; private int _commitTraceText_key; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | byte [] bytes = new byte [rowSize]; Type type = typeof (T); IntPtr structPtr = Marshal.AllocHGlobal(rowSize); for ( int i = 0; i < rowCount; i++) { ms.Read(bytes, 0, rowSize); Marshal.Copy(bytes, 0, structPtr, rowSize); object _obj = Marshal.PtrToStructure(structPtr, type); objs[i] = (T)_obj; } Marshal.FreeHGlobal(structPtr); |
好处:
· 本身就是常量,不必引入copy的开销
· 配置表数据结构很多都比较大,copy开销并不能忽视
· Box/UnBox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | [StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)] public struct ResMonsterGs : IResStruct { #region Fields private int _tid; private int _level; private int _gs; #endregion #region Getter Setter public int Tid { get { return this ._tid; } } public int Level { get { return this ._level; } } public int Gs { get { return this ._gs; } } #endregion |
Array的const控制
1 | LoadConfig |
1 | LoadGenericKeyConfig |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | private void LoadConfig { Type t = typeof (ResClass); //System.Type.GetType("Config."+type); object instance = Activator.CreateInstance(t); System.Reflection.MethodInfo method = t.GetMethod( "Load" ); if (method != null ) { ResStruct[] objs = BinaryLoader.Load if (objs == null ) { Console.WriteLine(BinaryLoader.GetErrorInfo()); Debug.Log(BinaryLoader.GetErrorInfo()); return ; } if (keyName.CompareTo( "" ) == 0) method.Invoke(instance, new object [] { objs }); else method.Invoke(instance, new object [] { objs, keyName }); if ( this .table.ContainsKey( typeof (ResClass))) { this .table[ typeof (ResClass)] = (ResClass)instance; } else { this .table.Add( typeof (ResClass), (ResClass)instance); } System.Reflection.MethodInfo callback_method = t.GetMethod( "OnLoad" ); if (callback_method != null ) { callback_method.Invoke(instance, new object [] { }); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private void LoadGenericKeyConfig where ResClass : GenericKeyTable where ResStruct : IResStruct, new () { Type t = typeof (ResClass); ResClass instance = (ResClass)Activator.CreateInstance(t); ResStruct[] objs = BinaryLoader.Load if (objs == null ) { Debug.LogError(BinaryLoader.GetErrorInfo()); return ; } instance.Load(objs, func); this .tables[ typeof (ResClass)] = instance; instance.OnLoad(); } |
添加配置表里是否存在某项的查询接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public virtual bool HasRowByIndex( int index) { if (index < table.Count) return true ; return false ; } public virtual bool HasRowByKey(KeyType key) { if (table.ContainsKey(key)) return true ; return false ; } |
原来判断是否存在的方法:
1 2 3 | ResCbeSpell pRes = pCbeTable.GetRowByKey(pSpell.CbeId); if (pRes.Id != 0) { |
添加了查询表项是否存在的接口,要使用这个接口确认是否存在
由于改成了class,表中没有的话,会返回null
旧版:
新版: