近几年移动端游戏大热,Unity + Lua更是手游行业的标配技术。如何有效利用有限的硬件条件,实现当前高品质、高规格的游戏产品是持久不变的话题。 Lua作为一个极为精简的嵌入型脚本语言,已经广泛地用在了游戏业,Lua的存在一般是两种场合,一种用于实现游戏上层业务逻辑,一种则利用了Lua语言本身灵活简单的数据表达能力而被广大程序员用于数据的存储,也就是常说的配置文件。

一般来说配置文件的初始来源是策划维护的有着一定格式约束的Excel表格,经由程序员提供的导出工具,把Excel的表格数据导出成为游戏能直接读取使用的Lua源码。

这些源码文件以Lua table的形式存储与Excel等价的数据,通常可以简单把这个配置表看成是一组2维数组,转换成配置就是一个key(Excel第一列)对应一组子数据(Excel中一行),那么整个配置数据就是一个大表包含着若干小表转换成配置就是一个key(Excel第一列)对应一组子数据(Excel中一行),那么整个配置数据就是一个大表包含着若干小表,如下:

原始配置表:


转换成Lua后大致是这样:
local mapsetting =
{[1] = {name = "map1",useminimap = "map1000",show_name = "十里桃林",cam_pitch = 40,cam_yaw = 230,cam_dis = 10,pkflag_support = 1,pkflag_punish = 1,maxnum = 50,scheduleConf = {},scriptId = {},...},[2] = {name = "map2",useminimap = "map1000",show_name = "碧波潭",cam_pitch = 40,cam_yaw = 230,cam_dis = 10,pkflag_support = 1,pkflag_punish = 1,maxnum = 50,scheduleConf = {},scriptId = {10002},...},[3] = {name = "map3",useminimap = "map1000",show_name = "梵音谷",cam_pitch = 40,cam_yaw = 230,cam_dis = 10,pkflag_support = 1,pkflag_punish = 1,maxnum = 50,scheduleConf = {},scriptId = {},...}...
}
return mapsetting

如果配置文件中的数据过大,或着是有冗余的无用数据,那么势必会导致输出的lua文件过大,这将严重影响加载速度和增大内存占用量。本文将介绍一种消除配置文件中冗余数据,达到压缩和优化数据存储的方法。

介绍该方法前,大家现来看看一般数据冗余在哪些地方由上面的示例图我们可以清晰的看到数据的冗余点:

  • 大量的数据是重复的,或着是代表没有意义的空值(比如0,[]等)
  • 大量的中文字符串是需要游戏后期做本地化处理的
  • 很多复合型数据(子表,数组)内容是一样的

搞清楚了数据冗余的原因,我们就可以制定优化方案:

  • 对于Excel中的一列,出现次数最多的值认定为默认值,然后把它从lua表中剔除掉,然后利用metatable机制实现全局默认值存储
  • 对于中文字符串,替换为一个唯一的id标识,写回到lua表中,读取的时候加上相应的查找替换
  • 对于一些复杂的子表或着数组,做唯一化替换处理,替换后写回到原始数据中
  • 能看出来,上面的操作其实做的都是唯一化处理,所以有个要求就是整个lua表的数据必须是只读的,如果不满足以上条件,一切优化都是错误的。所以在最后我们需要把整个表改为只读以保护数据不被错误篡改

优化后变成了下面这样:
local __rt_1 = {0
}
local __rt_2 = {
}
local __rt_3 = {10004
}
...
local __rt_34 = {desc = "@40313",drop_show = __rt_33,scriptId = {10001,10011},shield = 6,show_name = "@470882",subtype = 4
}
...
--超出Lua局部变量个数,则需要另外单独存储和引用
--createtable是把c中创建表的函数导入到lua中,这样通过创建一个预分配
--的表,能有效的避免table re-hash,有效利用内存
--下面创建一个预分配919个数组array-part、0个元素的空hash-part
local __rt = createtable and createtable( 919, 0 ) or {}
__rt[1] = {2861,1,46,8
}
__rt[2] = {2861,1,55,12
}
__rt[3] = {2861,1,50,7
}
...
local mapsetting = {{name = "map1",scriptId = __rt_2,shield = 0,show_name = "@384651",type = 0,...},{desc = "@424100",music = "map2_r",name = "map2",scriptId = {10002},shield = 0,show_name = "@424100",...},{bloomtype = 1,scriptId = __rt_2,shield = 0,show_name = "@491800",type = 0,...},{cam_yaw = 1,scriptId = __rt_2,shield = 0,show_name = "@499116",type = 0,...}
}
...
--大量的默认值存储在这里
local __default_values = {Belongto = 0,Instance_Show = 0,Instance_group = 0,daily_getcount = 9,damage_modify = 1,desc = "@282313",difficult = 0,pkflag_support = 1,scheduleConf = __rt_2,scriptId = __rt_32,...
}
...
dolocal base = {__index = __default_values, --基类,默认值存取__newindex = function()--禁止写入新的键值error( "Attempt to modify read-only table" )end}for k, v in pairs( mapsetting ) dosetmetatable( v, base )endbase.__metatable = false --不让外面获取到元表,防止被无意修改
endreturn mapsetting

看上去可读性没有原始的那么高了,一些被多处引用的子表已经被替换成了一个变量,这些变量是以local的形式存储在作用域的,由于lua本身的一些限制,一个作用域内能够存放的最大local变量的个数是200个(lparser.c #define MAXVARS 200),所以超过个数限制的多余部分表会被放入一个临时数组中,初始化的时候需要额外的查表,稍微多一些开销,但可以接受。

一般来说配置表文件优化后只有之前不到一半的大小,大量的重复数据被优化掉了,极大的提升了加载时间和内存占用。


前后文件对比如下:

最后说下宿主语言环境中,如果需要读取lua表中的子表数据,我们可以把该表的pointer拿出来作为键值,存放于查找表中,这样宿主环境中也能读取到一个唯一的数组,节约内存。


本文中使用的配置表优化工具源码已经放在github,需要的朋友可以自取,喜欢的朋友别忘了给个小星星哟:)

https://github.com/lujian101/LuaTableOptimizer

Lua配置表存储优化方案相关推荐

  1. 导出配置_Lua配置表导出优化

    随着游戏的开发,项目的配置表数据越来越多,占用的内存越来越:配置表占用太大就会影响游戏加载速度,游戏流畅度的每一毫秒都是我们的必争之路. [1] = {DungeonID=10000, Dungeon ...

  2. Tomcat 配置详解/优化方案

    Server.xml [原地址:http://blog.csdn.net/cicada688/article/details/14451541] Server.xml配置文件用于对整个容器进行相关的配 ...

  3. mysql 修改单表导入大小_MySQL更改大库大表存储引擎方案

    一. 概述 检查库中myisam的表, sql如下: SELECT * FROM `tables` WHERE table_schema = 'UAR_STATISTIC' AND ENGINE = ...

  4. mysql每10万条数据分区_WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案...

    1. 背景 项目中有1000万条历史案卷,为某地方坐标系数据,我们的真实需求是将地方坐标系坐标反转成WGS84坐标,如果现在需要将其转换成百度坐标系数据.常规方案是先建立好整个该市的本地坐标和百度坐标 ...

  5. Tomcat 配置详解/优化方案

    Service.xml Server.xml配置文件用于对整个容器进行相关的配置. <Server>元素: 是整个配置文件的根元素.表示整个Catalina容器. 属性: classNam ...

  6. spark-大表join优化方案

    数据量: 1~2G左右的表与3~4T的大表进行Join 拆分 将任务数据分为多个结果RDD,将各个RDD的数据写入临时的hdfs目录,最后合并 取所需的字段和数据,并去重,减少data shuffle ...

  7. mysql导出为lua配置表文件_利用lua生成一个导出数据库的bat脚本文件

    function getExportDbSql(db, index)-- 获取导出一个数据库实例的sql语句 local sql = string.format('mysqldump -u%s -p% ...

  8. 追踪app崩溃率、事件响应链、Run Loop、线程和进程、数据表的优化、动画库、Restful架构、SDWebImage的原理...

    1.如何追踪app崩溃率,如何解决线上闪退 当 iOS设备上的App应用闪退时,操作系统会生成一个crash日志,保存在设备上.crash日志上有很多有用的信息,比如每个正在执行线程的完整堆栈 跟踪信 ...

  9. 表格存储技术方案实践及客户案例分享

    表格存储是一款2014年10月份正式商业化的NoSQL数据存储服务,在商业化之前,早在2010年就在阿里云内部开始使用,云邮箱和云OS都是表格存储最早的一批用户.到目前,无论是在阿里集团内部还是在公共 ...

最新文章

  1. 解题报告(八) prufer 序列与 Cayley 公式(ACM / OI)超高质量题解
  2. 使用 OPEN SQL 语句读取数据库表数据的一个补充练习
  3. 线程管理(九)使用本地线程变量
  4. Spring MVC @SessionAttributes注解
  5. HTML语法初探(一)
  6. 揭秘新的供应链攻击:一研究员靠它成功入侵微软、苹果等 35 家科技公司
  7. 语音识别技术原理概述!
  8. android中得到屏幕的高宽(像素)
  9. 一款简单的取色器:ObtainColor拾色器
  10. 坚果云云盘告诉你如何保护自己的文件不被泄露?
  11. 【python教程入门学习】Python转义字符及用法
  12. 通俗解释机器学习中的召回率、精确率、准确率
  13. wps云文档 wps自动备份怎么设置和取消
  14. 算术编码 matlab程序,实验二算术编码及MATLAB实现.doc
  15. 关于vs2013系统找不到指定的文件
  16. Android幻灯片式图片浏览器
  17. 基于UWB的隧道管廊定位系统、井下定位构建方式
  18. 免费API接口整理(聚合数据和API Store)
  19. http://shijian.javaeye.com/blog/208190
  20. (十一)在线编辑模块(FreeTextBox插入图片,内容保存到数据库)

热门文章

  1. 能被某些数整除的数的特征
  2. Plan Stitch:一种使用缝合物理计划解决查询计划性能退化问题的方法
  3. 巧用Unity的Animator的动画层(Layer)实现跑动中攻击和受击
  4. 大牛整理的线段树集锦
  5. 常见远程控制工具协议(MSRDP/VNC/TEAMVIEWER/PCANYWHERE/TELNET)检测
  6. java中单例_Java中单例
  7. OFFICE使用技巧总结
  8. BAT大量裁人,快35岁的程序员该何去何从,Android并发原理解析
  9. 魔兽世界人最多的服务器部落,《魔兽世界》怀旧服哪边人多 联盟部落人数对比一览...
  10. 陷入回忆个性伤感签名_爱不说满到自己快湮灭