要开始做游戏了

每当周围漂亮的小姐姐和别人打游戏“嗨”到飞起而我无法加入其中时,一股挫败感便会直冲我的天灵盖

为何我打游戏可以到如此抠脚!!!怎么练都上不了分,日复一日,我终于由黄金成长为了青铜

罢了,我还是以"小视频"相伴吧!毕竟只要动动手指就可以了。

不,我要雄起,不会打游戏,我可以做游戏啊!

于是我加入了公司一夜狼人杀游戏的开发,并成为了苦逼的包工头

项目还没开始就要结束?

在这个项目之前,公司有多个自主研发的游戏,所以基础建设基本不用从零开始搭了,脚手架一把梭就可以开干…

但万万没想到,正当我想撸起袖子准备搞起的时候,却遇到了一个尴尬而扭捏的问题。

什么问题?

后端丢给我一个长达510多行的信令接口文件,它大概是长这样的。 里面包含了游戏中前后端交互的各个消息定义。

不幸的是,按照现有的游戏架子,需要前端根据信令文件手动编写这样一个JS配置

XDM,你怎么看? 我估计你此时和我一样,心中一万只草泥马在辽阔的大草原奔腾不止。

让你痛苦的地方,往往是可以提升的地方

工作中我们往往会遇到很多低效易错痛苦的点。如果你能主动解决这些让你(往往也是让其他人)感到不爽的问题。

相信我,你一定会收获良多,技术上、软实力上、装逼技巧上,都能得到一定的提升。

比如上面这个问题,我们要写一个脚本自动生成符合条件的配置文件

问题分析

我们先来看几组消息定义,看看其内容都有什么规律。

1.消息接口

// -301 通知所有用户游戏配置变更消息 message GameConfigChangeNotify { int32 actionTime = 1; //角色行动时长, int32 speakOrderTime = 2;//玩家顺序发言时长 int32 round = 3; // 顺序发言次数 int32 speakFreedomTime = 4;//玩家自由发言时长 bool speakAuth = 5; // 是否允许用户游戏中自主开闭麦 false不允许 true允许 int64 selfSetRoleUid = 6; //可自主选着身份的用户 }

JS配置

{ GameConfigChangeNotify: -301 }

2.消息接口

// 1. 注意后面跟着问号? // -350 猎人发动技能提醒 ? message HunterActionNotify{ //战斗ID int64 battleId = 1; int32 duration = 2; } // 2. 注意后面跟有&和()等特殊符号 // -352 胜负判定&复盘结果(此时游戏结束) message FinalNotify{ //战斗ID int64 battleId = 1; int32 duration = 2; FinalRes finalRes = 3; // 胜负结果 Review review = 5; // 复盘结果 } // 3. 注意跟着中文的括号(),并且//后面的数字没有空格,且{前面没有空格 //345 结束发言(自己结束) message SpeakEndReq{ //战斗ID int64 battleId = 1; }

JS配置

{ HunterActionNotify: -350, FinalNotify: -352, SpeakEndReq: 345 }

规则总结

你看,规则其实挺简单的,分成以下几条看

  1. //后面跟着一个或者多个空格,紧接着就是数字(正数或者负数),这个数字就是配置value。
  2. 数字(例如345)与message之间是一段注释,可能由中文或一些特殊字符构成。
  3. message与下一个{之间的英文字母就是配置的key。

正则解析脚本

有了上面的解析,就不难写出解析转换配置的脚本了。

const fs = require('fs') let dayWerwolfFileContent = fs.readFileSync('./.protofile/DayWerwolf.proto', 'utf-8') let dayWerwolfMap = {} dayWerwolfFileContent.replace(/\/\/\s*?(-?\d+)[^\w]*?message\s+(\w+)\s*?{/g, ($0, $1, $2) => { if ($1 && $2) { dayWerwolfMap[$2] = +`${$1}` } }) fs.writeFileSync('.protofile/map.js', ` module.exports = { DayWerwolf: ${JSON.stringify(dayWerwolfMap, null, 2)} } `)

最后只需要执行脚本node parse.js就完事啦!

module.exports = { DayWerwolf: { "GameConfigChangeNotify": -301, "GameRoleChangeNotify": -302, "GameAutoNextReq": 303, "GameStartNotify": -320, "ShuffleNotify": -321, "ChooseIdentityNotify": -322, "ChooseIdentityReq": 322, "AllIdentityNotify": -323, "ConfirmIdentityReq": 323, "DarkNotify": -324, "ActionNotify": -325, "GhostActionNotify": -326, "GhostActionReq": 326, "GhostCopyResNotify": -327, "GhostChangeIdentityReq": 327, "ActionEndNotify": -328, "WolfActionNotify": -329, "WolfActionReq": 329, "WolfActionResNotify": -330, "LackeyActionNotify": -331, "LackeyActionReq": 331, "NightWatcherActionNotify": -332, "NightWatcherActionReq": 332, "SeerActionNotify": -333, "SeerActionReq": 333, "SeerActionResNotify": -334, "RobberActionNotify": -335, "RobberActionReq": 335, "RobberActionResNotify": -336, "TroublemakerActionNotify": -337, "TroublemakerActionReq": 337, "TroublemakerActionResNotify": -338, "DrunkardActionNotify": -339, "DrunkardActionReq": 339, "DrunkardActionResNotify": -340, "InsomniacActionNotify": -341, "InsomniacActionRes": 341, "PullIdentityReq": 342, "IdentityNotify": -342, "DaybreakNotify": -343, "SpeakRoundsNotify": -344, "SpeakNotify": -345, "SpeakEndReq": 345, "SpeakEndNotify": -346, "VoteNotify": -347, "VoteReq": 347, "VoteResNotify": -348, "OutNotify": -349, "HunterActionNotify": -350, "HunterActionReq": 350, "OutResNotify": -351, "FinalNotify": -352, "MsgNotify": -357, "UserStatusChangeNotify": -600 } }

为了让其他项目也可以省掉手动编写配置文件的时间,我赶紧将该脚本内置到了公司的脚手架里。