April 13, 2015

Xenonauts 中文化计划

作为一个 X-COM 老系列的爱好者(1994 年开始一直玩了 3 年),新的官方重制版是满足不了我的。

Xenonauts 作为原作的精神继承者,我很喜欢。

本来这个游戏上手了以后是不太依赖文字的,只是可惜了它写的不错的文案。我在网上搜了一下汉化包,几乎都是机器翻译的,读那个真不如读英文啊。

游戏的官方没有能力做中文化,但是在官方论坛提供了翻译的指引

我按指引用文泉驿制作了游戏用的字体文件,发现游戏引擎本身对中文支持是没有什么问题的,差的只是文字翻译了。

但是这个游戏文字量极大,而且不太容易翻译。我在 github 上创建了一个项目,希望可以集众人之力来完成这个大工程。项目的地址在 https://github.com/cloudwu/xenonauts

阅读全文 "Xenonauts 中文化计划" »

April 10, 2015

对象到数字 ID 的映射

skynet 中使用了一个 hash 表结构来保存服务和 32bit 数字地址的映射关系。

一个 skynet 的服务,其实是一个 C 对象。在有沙盒的系统中,尤其是并行构架,我们很少直接用 C 对象指针来标识一个 C 对象,而是采用数字 id 。用数字做 handle 可以让系统更健壮,更容易校验一个对象是否还有效,还可以减少悬空指针,多次释放对象等潜在问题。比如,操作系统为了把用户程序隔离在用户态,像文件对象就是用数字 id 的形式交给用户程序去用的。

和操作系统通常管理文件句柄的方式不同,skynet 尽量不复用曾经用过的 id 。这样,当你持有了一个已经不存在的 id ,不太会误当作某个新的对象。(操作系统的文件 handle 很容易造成这样的问题:你记住了一个文件,在别的流程中关闭了它,然后又打开了新文件,结果复用了过去的 handle ,导致你操作了错误的文件。很多年前,我就在自己的线上产品中碰到过这样的 bug 。)

但是,一旦尽量不复用 id 。用简单的数组来做映射就很难了。必须使用 hash 表来保证映射效率。在 skynet 中我是这样做的:

每次分配新的 id 时,首先递增上次分配出去的 id (允许回绕,但会跳过 0 。0 被当成无效 id )。然后检查 hash 表中对应的 slot 是否有冲突,若有冲突就继续递增。如果 hash 表的池不够用了,则成倍扩大池,并将内部的数据重新 hash 一次。

这样虽然会浪费一些 id ,但是可以保证 hash 表类的 key 永远不发生碰撞,这样可以让查询速度最快。hash 表的实现也相对简单一些。

我觉得这样的一个数据结构有一定的通用性,今天花了一点时间把 skynet 的这个部分单独抽出来,当成一个独立开源项目重新写了一遍。有兴趣的同学可以在 github 上查看

阅读全文 "对象到数字 ID 的映射" »

April 07, 2015

上次提到的阿瓦隆辅助工具

上次提到过 抵抗组织:阿瓦隆 的辅助工具的一个想法。主要是用手机帮助大家减少天黑请闭眼环节的繁琐工作。参加游戏的人只需要看一眼手机,就可以了解游戏局面。这样就不需要额外的主持人不停的叫大家闭眼,某某睁眼确认等等了。

另外,也可以简化投票任务这些环节(如果是杀人,那就是确认杀掉谁,指认谁等过程)。一旦去掉了额外的道具,我们就不再需要桌子来玩。可以方便的在饭桌上打发时间了。

我在 github 上创建了一个项目。初步的计划是做成一个 web 网站,当然以后改成手机 app 也可以(可以只需要一个 app 做 host,其他玩家还是继续用浏览器访问它,这样就不依赖互联网连接了)。

因为我几乎没有 web 开发的经验,所以之搭了个简单的框架,剩余的部分是同事参与来做的。目前之完成了进入房间分配身份的部分,进度比较慢。如果能有经验的同学加入会好一些 :)

阅读全文 "上次提到的阿瓦隆辅助工具" »

skynet 近期更新及 sproto 若干 bug 的修复

skynet 的 1.0 版已经发布了 3 个 alpha 版,等稳定以后将发布 beta 版本。

最近的问题主要集中在一些我们在老项目中没有使用到的特性上面。尤其是 sproto 这个模块,我希望它将来作为 skynet 推荐的通讯协议,但我们老的项目开始的比 sproto 的项目早,所以早期项目全部使用的是 google protocol buffers (以及我自己做的实现)。 随着新项目的开展,我们公司内部开始大面积使用 sproto ,也就发现了一些 bug ,在最近集中修复。

阅读全文 "skynet 近期更新及 sproto 若干 bug 的修复" »

March 15, 2015

抵抗组织:阿瓦隆及兰斯洛特扩充

昨天下午约了一帮同事去密室,由于在最后 40 秒成功破关,大家都很兴奋,决定再换个地方欢乐一下,结果就在地图上找了家附近的桌游店。

一开始有 8 个人, 我知道这么多人想开桌游实在没有什么好的选择。玩了两局赛马后又来了三个人。一开始,我实在不想再玩 bluffing game 了。无论是狼人或三国杀,还是抵抗组织,都在三年前玩伤了(开桌游店的日子里,长达半年的时间,每周两个晚上抵抗组织)。

这时发现桌游店里有一盒阿瓦隆。一直听说抵抗组织出了这么一个扩充并且口碑非常的好(bgg 上 party game 分类第一),所以饶有兴趣的读了一下规则书。的确有那么一点意思,就组织大家开了几局。正好 11 个人,我可以做主持人。(当然抵抗组织和杀人狼人不同,玩熟了后,完全不需要额外的主持人的)

阅读全文 "抵抗组织:阿瓦隆及兰斯洛特扩充" »

March 13, 2015

给 sproto 增加 unordered map 的支持

花了两天给 sproto 增加了 unordered map 的支持。

问题是这样的:

sproto 支持数组,但很多情况下,业务处理中,我们并不用数组来保存大量的相同类型的结构数据。因为那样不方便检索。

比如你要配置若干地图表、NPC 表等等的信息,固然可以用 sproto 的 array 来保存。但是在运行时,你更希望用定义好的 id 来检索它们。如果 sproto 不支持 unordered map 的话,你就需要在 decode 之后,对 array table 做一次遍历,用一张新表来建立索引。

google protocal buffers 2 也有这个问题,据说第 3 版要增加 map 用来兼容 json ,这个话题最后再说。

阅读全文 "给 sproto 增加 unordered map 的支持" »

March 11, 2015

跳出死循环

在 skynet 中,有一个叫 monitor 的内部模块,它会监测是否有服务可能陷入了死循环。

工作原理是这样的:每次处理一个服务的一个消息时,都会在一个和服务相关的全局变量处自增 1 。而 monitor 是一个独立线程,它每隔一小段时间(5 秒左右)都检测一下所有的工作线程,看有没有长期没有自增的,若有就认为其正在处理的消息可能陷入死循环了。

而发现这种异常情况后,skynet 能做的也仅仅是输出一行 log 。它无法从外部中断消息处理过程,而死循环的服务,将永久占据一个核心,让系统整体性能下降。

采用 skynet 的 kill 指令是无法杀掉死循环的服务的。


当服务用 lua 编写时,我们则有可能做多一点工作。

阅读全文 "跳出死循环" »

Misc

Categories

Archives

Recent Comments