« January 2009 | Main | March 2009 »

February 28, 2009

关于地图编辑器的一些想法

大凡 RPG 游戏(包含 MMORPG),在制作期都需要开发一个地图编辑器。

早年 2d 游戏就有这个需求,基于 Tile 的 Engine 如是,基于整图的 Engine 亦如是。到了 3d 游戏,这个东西更少不了。

对于 3d engine 中附带的地图编辑器,通常有几个用途:拉地形(也有基于模型的地形)、摆放物品(以及特效)、设置玻璃墙(或是设置障碍格);有时也包括设置摄象机、事件触发点、摆放 NPC 等等。

在很长时间里,我都倾向于制作一个大而全的编辑器 IDE 。但最最近两年,随着编程风格及开发习惯的改变,我对这种做法产生了怀疑。

一旦制作 IDE ,就涉及对 GUI 底层的选择。无论你用 MFC 还是 QT WxWidget 或是 .net framework ,对开发人员都有一个学习过程。以我所见的大多数程序员的喜好,只要开始制作 IDE ,一上来第一见时间必定是设计一个所谓自己的 framework ,制定所谓插件规范,以用来解决上面提出的各种不断会面临的功能需求增加。

以我 10 年游戏开发的成功和不成功的经验来看,设计所谓框架是最最最不靠谱的事情。设计和实现的结果,最终一定会导致框架的分量比实际功能更大,生命期也更短。(欢迎大家驳斥和批评我的这个观点,我不会跟你争论的 :) )

和写程序不同,程序员可以眼前代码千行、胸中蓝图万卷;美术人员、策划人员都需要有直观的视觉反馈,所以 Tex 那种对书籍论文排版的方式往往是行不通的。

所以,我不反对 GUI 界面的选择,单纯是考虑 IDE 的必要性和替代方案而已。

从我有限的视角去看。其实制作人员最喜爱的工具往往是最熟悉的东西,专门性强的工具;所以对 2d 图片的处理总是首选 Photo shop ,对 3d 模型则爱 3dmax 或 maya 。如果情况所迫要用开发人员提供的编辑器、那么,往往生命期越长的工具就活的越长。活的最长的工具总是那些功能单一,又能解决问题的东西;甚至于到了最后,连源代码都不见了,或是有了源代码却构建不回来(通常是由于动态链接库版本问题,或编译器版本造成一些 bug ),但留下二进制执行文件而一直用下去。

编辑器的作用到底是什么?它产生的是数据、以一种更直观的方式得到需要的数据。

早年,我们为了简化开发流程,使用标准编辑器(Photoshop)制作地图。然后编写命令行工具提取出数据,转换为最终的数据格式;随着项目的繁衍,也开始制作一些专门的 GUI 小工具辅助开发。

后来,我们开始为新项目新引擎制作专门的编辑工具。这通常需要至少一个全职程序员十个甚至二十个月的持续跟进。直到工具庞大到难以维护。

我想过好多次,能不能找到另一条思路。

目前的构想(并已经实现)是这样的:

把编辑器做成 C/S 结构。并不规定具体的实现方案,只指定数据通讯和持久化协议。这个 S(erver) 其实是一个实时版的 SVN 。它不理会数据的具体含义,只是忠实的记录编辑器的 Client 提交上来的数据,为每个原子数据产生唯一版本号。所谓实时,指 Server 会在收到提交后,才很短的时间内把数据推给其它 Client 。

首先,这样做可以使得多个编辑器 Client 同时编辑同一个对象(一张地图)变为可能。我们也不必提供锁机制,用操作链表的融合保证并发编辑的有序。Server 同时也保存了整个编辑过程的历史,可以无限制的回退。

举例:

如果有 A B 两个 Client 同时编辑一张地图。A 原子提交了 1 2 两个对象(可能是连在一起的两个地图块高度信息),而 B 在差不多的时间提交了 2 3 两个对象。

在没有得到 Server 的成功反馈之前,谁也不能把实际效果作用在 Client 的界面上。而是把未确认的操作保存在一个链表中。Server 收到 A 或 B 的提交后,核对版本号,给予最早提交的一方,比如 A 一个成功信号。这时 A 就把操作链表真正作用于地图。

而 B 的提交一旦晚于 A 的达到,由于发生版本冲突,会得到 Server 的失败反馈。B 就需要把 Server 推给它的 A 的修改先更新后,再把操作链表中的操作重新做一次,继续提交。

关于回退(Undo) 操作,和传统的 svn 代码管理不同,我们不能每次简单的回退一个版本。因为涉及多人协作,这样做和干扰他人的工作。

恰当的方式是,先向 Server 查询属于自己的最后一次操作,并递归回退相关影响的对象。

另外可以提供查询 History 的功能,可以查看整个地图的制作演变过程。


其实,多人协作这个功能只是一个结果,不是这个方案的主要目的。

我实际想做到的是,可以以 Server 作为一个数据同步中心,可以把地图编辑的多种功能完全隔离开发。每个工具只专心做好一件事。它们可以忽略掉自己不认识的数据,仅仅显示自己可能关心的数据(只读),修改自己份内的数据。

比如,拉地形高度图的工具往精里做地形编辑;摆放物品的工具调好操作手感。(这两种工具需要的摄象机操作方式可能不同)甚至可以有个专门的观察器,只用于多角度查看编辑效果:顶视、第一人称漫游、特定角度等等。

一旦工具内容专一,我们可以取消繁杂的界面,不把精力放在这个方面。也可以不必苛求渲染引擎的一致。甚至有些工具可以简单的用 2d GDI 方式实现。比如,圈定战斗区域,规划路点等等。

而美术、策划人员使用之时,完全可以多配备几台显示器,用多进程的方式启动多个不同或相同的工具(相同的工具是为了从不同视角观察地图)。最多我们做一个 Chrome 那样的专门进程管理器来管理相关进程而已。

这就有点像 Unix 哲学,用小工具(特定编辑工具)和管道(数据同步中心)组合出强大的功能来一样。每个工具都能有持久的生命期,并可以专注于特定目的做的更好。

February 22, 2009

冰与火之歌果然是个好游戏

周末跟几个同事开了一局(A Game of Thrones)冰与火之歌。讲规则之前,我特意强调大家一定要有胜负心,并且足够理性的玩这个游戏,以完成自己的最终胜利为唯一目标。事实证明,如果大家都投入进去,这个游戏相当精彩。

我作为主持人,旁观大家玩到了第 7 回合,并且一直在讲解分析。接下来替掉中间一个想去睡觉的同学玩了最后三回合。

参加的人都是爱游戏之人,比如游戏部的 dingdang ,youdao 的周枫同学,梦幻的项目经理丁丁,邮件组的熊同学。全部极具逻辑思维。(嘿嘿,居然网易的老大们可以聚在一起玩 7 个小时的桌面游戏)加上都是第一次玩这个,几乎每个回合前,五个人都在反复讨论局势的发展,并在此基础上展开外交。

也正是如此,局势发展到最后,僵持了三个回合。大家把形势和各种可能的变化分析完后,居然最优策略是按兵不动。颇有大国打仗,前线对峙,剑拔弩张的感觉。这不愧是一个强调外交的游戏,乐趣正在于不战而屈人之兵。

最后一个回合进入大混战。局势居然混乱到每个人都有机会获得最终的胜利。然后我们几个人放行动指令之前反复研究了一个小时,放下行动指令后,又执行了一个小时。把每种可能性都演练了一遍。

最终是我以微弱优势胜利。胜利的关键除了在于大家必须相互牵制以外(不然就会有人轻忪获胜)。居然是源于第一场故意打输一场战役。

事后我们总结时又发现,如果结果可能改变的话,就需要每个人都把以上过程全部考虑到,了解这些变化。然后假设某同学在远离中央火药桶的地方先行打一场看似无关紧要小战斗,结果就会大有不同。

这个游戏的最后阶段,很有象棋残局的感觉。不过涉及五人博弈,中间关节复杂了许多,按周枫同学的说法,因为变化因素太多,而且受太多人的心理决策的影响,其实最后的结果呈现出很大的随机性。


ps. 感谢周枫同学从美国帮我背回了 A Game of Thrones 的两个扩展包。目前正在研究规则书中,这周看能不能找到人开一局。:D

February 13, 2009

ExtractAssociatedIcon 的一点问题

今天 卡牌对决 升级,没在 vista 下测试。晚上就有人报告 vista 下运行不了了。

netbug 同学在家里取了一份代码查看。据说错误是出在 ExtractAssociatedIcon 这个 api 的调用内部。是下面这样一行 api 调用:

hIncon = ExtractAssociatedIcon( inst, "loader.exe", &wIndex );

但是 msdn 上看不出所以然来。

之前,vista 下都是运行正常的。netbug 同学说,唯一的区别,以前是 vc6 编译的,而现在换成了 vc9 。

一般情况下,换编译器不会造成 api 调用失败呀?这是为什么呢?

我上 google 搜到了 msdn 里关于 ExtractAssociatedIcon 的文档 ,( google ExtractAssociatedIcon site:msdnmicrosoft.com)。

HICON ExtractAssociatedIcon(
HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon );

我注意到,这第二个参数类型是 LPTSTR 而不是 LPCTSTR 。

建议 netbug 同学改成:

char filename[]="loader.exe";

hIncon = ExtractAssociatedIcon( inst, filename, &wIndex );

居然就对了。-_-

之所以换了编译器就出问题,可能是因为不同的 linker 的策略不一样。或许 vc9 把 "loader.exe" 放到了一个只读段里去了,因为 vista 的 api 实现不太一样,导致去写一个只读页。(也有可能是 vista 的 PE Loader 的区别,不想深究了)


之所以这次我能在半分钟内反应过来,是因为以前碰到过类似的 Windows 版本之间平台差异问题。

GetGlyphOutline 就有这个问题。如果说 ExtractAssociatedIcon 的 msdn 文档还隐晦了指出了问题,GetGlyphOutline 就能肯定是 bug 了。

GetGlyphOutline 的最后一个参数类型是 const MAT2 *lpmat2 ,写明了是 const 。但是如果你定义一个 static const MAT2 ,然后把指针传进去的话,某个平台的 windows 下,进程会崩溃在这个 api 调用里。(可能是 Windows 98 ,因为这是很多年前开发大话 client 时遇到的了)


btw, netbug 同学在家里想 checkout 办公室内部的 svn ,而我们并没有提供外部 vpn 登陆的途径。而我还在办公室。有什么简单的办法呢?我发现 ssh 的 tunnel 功能可以安全的解决这个问题。

我们找了台外部大家都可以 ssh 登陆的机器,然后我先 ssh 上去,做一个 remote tunnel ,把我可以看见的办公室内部的 svn tunnel 到那台机器的本地。然后 netbug 同学再 ssh 过去,做一个 local tunnel 把管道对接回他家里的 PC 就 OK 了。 :D

这个方法值得推广。


2009 年 2 月 14 日补充:

今天 netbug 同学重新读了 msdn 文档,发现文档中提到了,第二个参数是有可能被改写的。不过文档中没有正确标明类型是 [in,out] ,而是标注成 [in] 。

不过奇怪的是,既然这个指针有可能接收返回串,但却并没有指定最大长度,是否会有栈溢出的安全隐患?

谨慎起见,需要把 filename 定义成:

char filename[MAXPATH]="xxxx";

(严格说,应该是用 TCHAR)

February 07, 2009

再谈"平等"

在 google reader 上看到朋友 share 的一篇 "平等?" ,恰逢周末,可以接下来闲扯几句。

对于所谓民主、自由、平等这些话题,我从来都不愤青。所以在我的 blog 上也看不见此类文章,不是我不敢写、不愿写,而是我觉得那些问题过于复杂,尤其是在读了些许历史之后。上篇 blog 用了 ”平等“ 这个题目,其实不完全是想谈 "平等" 这个概念,是因为我不知道该用什么样的题目表达我的意思。

yeka 写了一篇"通向自由的必经之路——自律——平等" 引述了蒋纬国的一段话,”不论是谁,稍稍有权威后就开始耀武扬威了“ 。其实,未必是"耀武扬威"那么霸道而另人生厌。稍有涵养的人也不会如此。只是有些人表面上和颜悦色、骨子里的独断和自负却是不经意间流露的。这是我想说的:无论人站到了多高,都需要时刻自省,并理性的倾听。

把 "平等" 看成 "自尊" 的需要,稍显浅薄(不好意思,用了个贬义词,希望不要因此引发争议)。让低位者感到 "自尊" 受到侵犯,或者 "自尊" 得到保护,其实存在一样的问题。在对问题的讨论中,自然而然的忽视所谓 "自尊" ,才能回归理性。这也是我上次说的,避免发言者抬杠和钻牛角尖。

人不可能生来平等。但物以类聚、人以群分。能在一起共事(通过客观和相对公正的招聘流程),同事之间其实没有太大的差距。做对事情远没有做错事情容易,所以发现错误远比找到正确的方法需要的经验和知识少的多。具体的事情上,决策者通常只能有一个。决策者应该具有比其他参与者更大的能力是无庸置疑的(虽然实际上并不能完全保证这一点,尤其是在定义 ”能力" 本身就是件很困难的事情),决策者就更不应该以自己要承担更大的责任,考虑更多的方面,来推委、拒绝仔细考虑负面的声音(我指真正认真的思考,而不是表面上的)。

具体在技术问题上,一个有 20 年编程经验的人很难不在一个仅有 5 年编程经验的人面前产生优越感。而正是这种优越感,往往错失纠正错误的机会。即使一个新手提出一个多么可笑的建议,只要经过认真思考、总有内在的逻辑。哪怕亲身证实过是错误的东西,都有可能在重新审视后发现其实是对的。一个人的能力和精力是有限的,事情做的多了,就会转化为一些浅意识的条件反射,而不再去动用逻辑分析。外界的变化却是偷偷进行的,有更多的人帮助思考,是团体进步的源泉。

另一方面,在团体中去权威化,可以帮助团体树立更多的有价值的 "权威" 。面对问题,可以获得多角度的信息。让更多人站的更高,却不同质化,所谓 "君子和而不同" ,这对 "平等" 也是一个正反馈。

"一件事情任何人都可能提出想法,可永远没有人真正为此负责" 不是 "追求平等和民主必须付出的代价" 。恰恰相反,这是只做 "平等" 表面工夫的副产品。表面上的 "平等" 背后,实质上是严重的不平等。"平等" 绝不是指提供一个平台让大家常做做头脑风暴,发牢骚。拍脑门得到的不负责的想法真的会是认真思考过的吗?"平等" 在于对待问题的态度上也是平等的,尽可能的考虑自己能考虑的一切。而不是只有决策者最尽力去考虑。

当一个讨论,真正允许发出各种声音。常常不会给人带来愉悦感。更多的是自己的想法不能完全贯彻的烦闷(不能贯彻的部分,可能无法再被证明是对是错)。居上位者从情感上去迎合对方的 “自尊" ,本身就是极度的不平等了。好比当年刘少奇主席对时传祥说,我是国家主席,你是掏粪工人,这只是分工不同,我们都是人民的勤务员。这反应的是一种平等还是不平等?稍具理性的人一眼就能分辨。

一旦真的把平等写到心里,抛开自己的位置,谁在感情上又能接受自己觉得正确的东西被人反对?这和人的位置无关。可是,把事情做对,少犯错误,提高团体的水平,需要所有人都来承担这个感情上的损失,而不是让部分人得到精神按摩。

February 05, 2009

今天许了个愿

晚上想起来去买蛋糕。开车过去,带上了两年来公司发的蛋糕卷累计共 RMB 200 圆。路边不方便停车,所以到蛋糕店了胡乱快速点了一圈,打好两大包一算,刚好 200 块,一分不多一分不少。貌似已经是第 2 次发生这种事情了。难道我潜意识里对数字特敏感?

晚上办公室人比较多,加上新年第一趟抱石的,消灭一个 9 寸的蛋糕那是相当容易。

许了个愿,希望在今年内可以实现。

今天共计收到 4 条短信,3 条 IM 留言,一封 email 。

一并感谢。

February 04, 2009

平等

过年在武汉时,和博文 的朋友一起吃饭。周老师 问,你在网易那么多年,说说网易的文化吧。

一时间,我不知道从何说起。网易从来没有一本如职培训教材上条条款款写明所谓公司文化的。也没有什么人认真总结过。我想,每个网易人心中都有一份网易文化的定义。

如果让我说,第一反应是,网易重视技术人员。通常在 IT 的创业小公司中,这种现象比较常见。网易已经不算是小公司了,坚持这样比较难得。这倒不是因为丁磊有技术背景,我想更多的是,网易在几个关键时期,都是技术人员起了重要的作用。公司善待技术人员,算是投桃报李了。这是公司的一种发展偏好吧。

网易在做重要决策时,往往显得谨慎小心。不够大气。往往比别人慢一拍,且少有破釜沉舟的投入。这是几个公司高层性格的体现,物以类聚,人以群分,所以这也影响了许多员工。这似乎成了公司的性格,因此,也有性格不合的人离开。

能称之为文化的是什么呢?我拿不太准。或许,追求“平等”,勉强算的上吧。


有些“平等”,是很容易做出来的。许多公司都一样。

没有特别多的层级、所谓扁平化管理。我听过许多抱怨,说网易的管理太有问题,全是干活的人,没几个管事的。一个头管了无数人,自己还要亲力亲为,怎么可能管的好。好几年前,公司也请了所谓管理咨询公司,不断的培养所谓“中层管理人员”。成效怎样?不敢妄断。可以肯定是的,一些期望公司变好,更像一个大公司的努力,和公司原有文化是发生了一定冲击的。

公司的 CXO 们,和新进来的普通员工在街边吃烧烤,似乎不是什么稀罕事。下了班,就不再分上下级,一律是同事。该玩还是一起玩儿。该聊天还是敞开了聊。从丁磊开始,他这些年就没改过习惯,兴致来了就打电话叫同事一起喝酒。遇见朋友,一律介绍,这是我的同事 XXX 。不过,现在和以前不同,和不熟的同事在一起时,他都抢着买单了。不过我倒是觉得,抢着买单倒是见外了。要说平等,即使不 AA ,随便谁买都一样。老板也不应该有买单的义务,再说,下了班就不是老板了。

网易主张敞开式的大开间办公。在很长一段时间里,没有人有独立的小办公室。高职位者也不过一张同样的桌子,坐在大家的中间,甚至不是更好的位置。

其实这些刻意去做都不难,难的是把“平等”二字写在心里。

01 年我刚进网易的时候,游戏部门刚刚成立,所有人都是临时拼凑起来的。我听闻了一则故事。有美术部门的同事之间争吵起来,大概是工作上的吧。最后谁也说不过谁,只好比起员工级别来了。网易的员工级别有 9 级,其实落到大部分员工上的级别很少。开发人员最低是 8 级,如果到 5 级,基本属于高级管理人员了,人数非常稀少。所以大部分人不是 7 级就是 8 级( 6 级属于中层管理人员,人数也不太多)。刚好吵架的人一个是 7 级,另一个是 8 级。这级别高的就用级别压人。

给我讲故事的这位老兄一脸的不屑。我们这又不是军队,没什么上下级的。他的想法代表了大部分网易老员工的观念:工作中具体东西的争议,不是靠级别高就可以说了算的。所谓特权的思想,在整个网易的文化中是受排斥的。

05 年,游戏部门中层管理人员开了次比较大的会议。讨论许多管理中出现的问题。其中有个议题争论的非常厉害。那就是中高层人员,有没有权利比普通员工晚来上班。这个议题的前提还是,几乎所有的中高层人员工作时间都长于普通员工,只是晚来晚走而已。但是,即使这样,要求别人 9 点上班打卡,而自己可以推迟到中午报道,已经让大多数人感觉到严重的不平等了。而开始的所有人还都是在享受这个特权的,并没有普通员工参加。

04 年,我和我的上司 dingdang 有过一次激烈的争吵。那是唯一的一次。谁都说服不了谁。最后 dingdang 逼急了,说,这次一定要听我的,我要为整个团队负责。一句话噎的我在旁边闷声不响。五分钟以后,dingdang 就跑过来向我道歉。或许,有人不会理解,为什么应该道歉?因为,无论你看的多远,想的更多,在讨论具体问题时,不能以自己的位置来压人。其实,这个位置不单单是指职位的高低,也包含有你的经验,你在行业内的权威,等等。

说起来容易,做起来其实很难。

在我们的办公室里,经常为一些不知为谓的问题,吵的面红耳赤。因为每个人随时都可以对别人在做的东西发表自己的意见。不论怎么吵,都不能搬出:我做这个已经很久了,我的“感觉”这样就是好的,这种理由来说事。做技术的人往往有这种感觉,有些东西凭自己的经验这么做就是对的,讲出道理来却很难。有些还是一些个人喜好甚至“信仰”的缘故。但是这种东西,在争论时,大家都有一种默契,不拿自己的“感觉”说事。因为涉及到“感觉”,就牵扯到每个人在各自领域的所谓“权威”。而“权威”最容易造成不平等的争论。

去“权威”化,是“平等”文化的一部分。即使在单纯的技术领域也是一样。讨论问题时,不应该有一个人站的更高。这样,人才能够放开心胸把自己的想法说出来,不至于每每到最后去“抬杠”,“钻牛角尖”。

都说,技术问题的争论是单纯的,只要对事不对人,没什么大不了。实际上,根本不是这样。大多数技术问题,都有截然不同的几个面。根本无法决定那种方案更好。单凭道理,很难说服“政见”不同的对方的。由于本不存在对错,所以争论的结果造成不欢而散的结果其实非常多见。单方面的让步,其实只是隐藏的问题,而并没有解决。许多人会觉得,管他谁对谁错,只管去做就是了。让事实说话?事实不是一个因对一个果的。

所以,把“平等”放在心中就变的重要起来。一切争论都需要有个结果。而这个结果是在平等的基础上,双方妥协让步的结果。虽然每个人都不爽,但是每个人都不得不接受。没有人允许说,“这次我说了算,我会考虑你的意见”。

为什么需要这样?的确,很多成功来至于独断专行。因为这样有最高的效率。但是,失败的概率比成功更高。只是因为样本空间足够大,让人们看见了那些偶然的成功者而已。而发挥每个人的智慧,即使引起了冲突,我们不得不妥协放弃更好的方案,但我们很少犯错。


每个人总有些权利,即使工作多年一事无成,也有权利向刚工作的新人倚老卖老。有多少人肯放弃这种权利呢?

追求平等,就要懂得放弃自己已有的东西。真正的平等是居高位者放弃自己的权利换来的。在没有权利时,抱怨不平等,又有什么意义呢?