【一个重复id让游戏卡在62%,聊聊配置表检查】

一个重复id让游戏卡在62%,聊聊配置表检查 先说那天的事。 11月4号晚上导完表进游戏,加载条走到62%就不动了,控制台一片红,第一条是 ArgumentException,意思是字典里加了一个已经存在的key,key是2004001,后面跟着一大串 not find LanguageId,就是按语言id找文字找不到。 我第一反应是语言表坏了,但只是一个id重复,为什么后面全找不到?这个后面说。 查下来是这样的,那天为了省事用 Python 脚本批量改了道具表和语言表,脚本用的是 openpyxl(一个读写Excel的Python库),改完存盘,结果两张表都被弄坏了,坏的还不止一处。这篇就把这次踩的坑和后面怎么检查整理一下,做游戏的同学应该多少都会遇到。 先说下配置表是什么 没做过游戏的可以这么理解,游戏里道具叫什么、多少钱、图标用哪张、任务要做什么、按钮上写什么字,这些数据程序一般不写在代码里,而是策划在Excel里填,一行一条数据,每行开头有个id(也叫主键,就是这条数据的编号,不能重复)。 然后用导表工具把Excel导成游戏能读的文件,我们项目是Unity编辑器里的导表工具,导出来是一堆 cfg_xxx.txt,游戏启动的时候一张一张读进来,代码里用id去拿,比如 ItemConfigData.Data.GetItem(id) 就是按id拿一条道具数据。 所以流程是:策划填Excel,导表,游戏读表,代码按id取。中间任何一步出问题,最后都是游戏里显示不对或者直接报错。 这次踩的几个坑 坑1,重复id。 语言表(放所有中文文字的表)里,脚本往表尾加了一千多行道具语言,士兵道具的描述行用了和名字同一个id,因为道具表里描述那一列的公式写成了 =2000000+A,跟名字那列算出来一样,一共60个重复,还多了id是0和89906的两行。 为什么一个重复整张表都完了,看读表代码就明白了,语言表读的时候是一行一行往字典里 Add,字典(Dictionary,按key存东西的容器)遇到重复key直接抛异常,抛了之后后面的行就都没读进去,所以后面几万条文字全部 not find,加载也卡住了。 坑2,公式丢了,导表直接丢行。 这个是最隐蔽的。Excel里有些id不是手填的,是公式算出来的,比如 =A10+1 这种,Excel存盘的时候会把公式算出来的结果也存一份,叫缓存值。 我们的导表工具读的是缓存值,不会自己去算公式。openpyxl存盘的时候只存公式,不存缓存值,所以这些格子在导表工具眼里就是空的,空id的行直接跳过,导出来就少了。 11月3号我就遇到过一次,改完语言表导出少了22行(8002、5100151012、900001900114这些),游戏里没有报错,只是对应的地方显示不出字,当时找了好一会儿。 坑3,数据贴错表。 还是那个脚本,本来想补道具名的语言,结果把语言数据(id加文字)贴进了道具表,从1258行到2933行,1676行,道具表直接乱了,好在当时还没重新导道具表,不然又是一轮。 坑4,引用了不存在的id。 这个不是那天的,是之前的。主城上锁着的区域下面显示一个"20",点树林也飘"20",一开始以为是哪里写死了,查下来是条件类型表里好几种条件的提示文字id都填的20,语言表里根本没有20,我们的取文字方法找不到的时候就把id本身返回了,所以界面上直接显示了"20"。 还有一次所有错误码都提示"错误码不存在",结果是代码读的是一张只有2行旧数据的错误码模板表,真正的错误码表是另一张。表本身没问题,是读错了表,这种也算引用不对。 那怎么检查 我现在会看这几样: 重复id,同一张表里id不能重复,语言表这种被很多地方引用的尤其要查 id是0或者空的行,基本都是填错了或者脚本加出来的脏数据 公式有没有缓存值,id列是公式的,值是空的就说明缓存丢了,这一行导出来会没 引用存不存在,表里填了别的表的id(比如道具名填的语言id),要去对应的表里能找到 谁存的这张表,xlsx其实是个压缩包,解压后 docProps/app.xml 里的 Application 写着最后是什么软件存的,那天两张坏表这里写的都是 Openpyxl 3.1.5,不是Excel,一看就知道被脚本动过 导出前后行数对一下,导出的txt第3行有"行数 最小key 最大key",改表前记一下,改完再看,少了就有问题 做成自动检查 一张张手看肯定不现实,我写了个简单的Python脚本,只读不写,读完不保存,专门查上面说的重复id、id为0、公式缓存丢失、是不是脚本存的。

python 复制代码
import sys, zipfile, openpyxl

#2026.11.05配置表检查,只读不写,读完不要save
def check(path):
    #先看是谁存的这张表,不是Excel存的就要小心了
    app = zipfile.ZipFile(path).read('docProps/app.xml').decode('utf-8')
    if 'Openpyxl' in app:
        print('警告 这张表是脚本存的不是Excel', path)

    #data_only=True读的是缓存值,公式格子缓存丢了这里就是None
    wb_val = openpyxl.load_workbook(path, data_only=True)
    wb_fml = openpyxl.load_workbook(path, data_only=False)
    ws = wb_val['##']
    ws_f = wb_fml['##']

    ids = {}
    #前6行是表头,第5行是字段名,第7行开始才是数据
    for row in range(7, ws.max_row + 1):
        id_val = ws.cell(row, 1).value
        id_fml = ws_f.cell(row, 1).value
        if isinstance(id_val, str):
            id_val = id_val.strip()
        if id_val is None or id_val == '':
            #值是空但公式不空,就是公式缓存丢了,导表会把这行丢掉
            if isinstance(id_fml, str) and id_fml.startswith('='):
                print('公式没有缓存值 第', row, '行', id_fml)
            continue
        if id_val == 0:
            print('id是0 第', row, '行')
        if id_val in ids:
            print('重复id', id_val, '第', ids[id_val], '行和第', row, '行')
        else:
            ids[id_val] = row
    print('检查完', path, '一共', len(ids), '个id')
    return ids

if __name__ == '__main__':
    for p in sys.argv[1:]:
        check(p)

用法就是 python check_table.py 表1.xlsx 表2.xlsx,表头几行、数据从第几行开始要按自己项目的表格式改,我们项目的表数据页叫"##",前6行是表名、主键、中文名、字段名、类型这些,第7行开始是数据。 引用检查也是同一个思路,check返回了这张表所有的id,把语言表的id拿出来,再去道具表里把名字、描述那几列的值挨个看在不在里面,不在就打出来。 这里有个反着的坑要提醒一下,openpyxl读没问题,千万别用它存策划的表,存了就是上面坑2的结果。真要用脚本改表,我现在是把xlsx解压了直接改里面的sheet XML,其他文件原样放回去,改完再对一下导出的行数。 能放进导表流程里最好,导表前先跑一遍,有重复或者丢公式的直接不让导,这个我还没接进去,后面接了再写。 最后说几句 表的问题尽量在导表前拦住,进了游戏再查就是看一堆红字倒推 读表那里一个Add就能把整张表废掉,报错的时候第一条最重要,后面的大多是连锁反应 代码里不要因为表里没有就写死,比如引导的步骤类型、关卡id,表里缺字段就找策划加列,不然下次改表代码也得跟着改 用脚本改表一定要先备份,改完跑一遍检查 这是第一篇,写的比较散,有问题欢迎留言。

相关推荐
ryn4839835 分钟前
01 一个功能模块,怎么分层才不乱
前端·ai编程·claude
Amos_Web38 分钟前
通过 Rspack 源码学 Rust(五):读懂 Result 与问号运算符的错误返回
前端
杨航 AI1 小时前
JEV的用法
java·前端·数据库
Amos_Web1 小时前
Rspack 源码解析(三十五):rspack_error 如何用 miette 渲染带源码定位的错误链
前端
去伪存真1 小时前
高敏资产场景下的大模型协同设计架构
前端·agent
修炼的dance1 小时前
OCR预处理测了108组,纠斜去噪有用,坑在顺序和力度
前端
疯华整猫1 小时前
Android 16 后台常驻适配:用 Trae 搭一套“前台服务 + 加急 Job”的可存活架构
前端
不可能片场1 小时前
AI视频成片 帧间差分把拼接缝照出来
前端·electron
写的都是BUG1 小时前
APK 里的钥匙,一直就放在门口:聊聊加固真正该做什么
前端·算法