眨眼间2015年已经过去了, 也许是我最近记忆力变差了, 总感觉好像昨天才辞职的样子。
在2015年年初辞职时, 其实我的内心非常的纠结,一方面是安逸,一方面是未知, 很难下定决定到底何去何从。
终于还是求知欲战胜了懒惰。因为我发现如果再干着同样的工作,我的技术不太可能提高太多。所以最终我还是选择了辞职,由于上一份工作的原因,相比前端程序来讲,我对于后端的兴趣更大。因此在找工作方面,我更着重于找服务器编程方面的工作。因此后来就找了一份游戏服务器工作.
现在想想刚入职时闹的一个笑话都还脸红。才入职时,基于对新人的保守使用,都是先编写UI逻辑。而客户端的UI逻辑是采用lua+异步的方式来实现的。而我当时并不知道什么是异步,甚至还想在lua中使用sleep来保证代码的时序逻辑。直到后来我在silly中集成luaVM时,我才终于知道客户端lua+CPP中异步到底是如何工作的。
虽然当时我很想直接去写服务器代码,但是即然写了客户端,也就花了大约2周时间去学了一下《3D数学基础》。再说依我的性格虽然准备写服务器, 但一点都不了解客户端,那也不是我的性格 :), 不过在学习过程中,我发现游戏客户端其实就是在用各种自然学科的知识去模拟整个世界,也就是在这时候,我却突然对客户端代码也产生了兴趣。
这时分给我的UI工作刚好做完, 手头上暂时没什么事, 就硬着头皮研究了一下客户端的引擎代码部分。物理部分和声音部分都是不开源的,因此能研究的也就只有动画部分了。在研究了几W行动画相关代码之后,终于大致知道了一些动画渲染的原理。比如骨骼动画,动画融合等。
粗略研究了一下动画原理之后, 就顺便研究了一下客户端多国语言的实现。上一份工作中,我对于自己多国语言的设计非常不满意。看完这个多国语言的实现之后,我才明白原来当是自己是过度设计了,在简化了设计之后,我只花了几十行就重新实现了一个多国语言模块。
下一阶段的开发任务来了,我终于能够编写服务器代码了(虽然只是服务器中很简单的逻辑部分), 不过却见到了一些我从没想过的C++的用法, 由此又顺便学习了一下C++的一些高级用法(比如模板推导等)。与此同时我的个人服务器框架也正基本上正式开始编写了。
在接触到服务器编程之后, 由于是TPS游戏都是开房间的,因此我一直都是思考如何才能让所有玩家都可以在同一张地图上进行游戏。在此之前一直都想不通要怎么做。在网上搜了很多文章也都没有找到什么好的办法,我只好暂时暂停了此问题的思考,转而去研究了《redis的设计与实现》来换换脑筋。在《redis的设计与实现》的最后部分,作者讲了一下redis对于集群的设计,一下令我慌然大悟。
在下一个开发阶段,由于业务需求,我终于要单独写一个服务器,想想都令人激动。在摆脱了以往框架限制的同时,我也需要从头来实现一些机制。 正是在实现这些机制的同时却让我对TCP协议有了更深的了解,比如tcp的端口绑定, TIME_WAIT等。就这样基本上都是上班写代码,然后发现自己有什么理解错误就下班回来改silly.
终于开发任务完成了, 又有一段时间可以搞自己的东西了.由于很多UI上的bug都不是100%必现的,而lua的调试手段一般就是加print来打印一些变量的值。当出现bug时我们需要打印一下当时一些变量的值就非常的不方便,于是就琢磨着写了一个简单的lua调试器.这样在出现bug时就可以拿lua调试器直接attach上去来打印当时的call stack以及以些变量的值等需要的调试信息,可以大大减少了bug重现的需要。
在很早以前就知道google protobuffer这个东西,而且也对编译原理有所眼馋。在silly中上层逻辑都是使用lua来编写,在socket传输序列化时很不方便,因此老早就想实现一个类似google protobuffer的东西了。趁还有时间就花了几周看了一下编译原理的词法和语法部分,然后实现了zproto, 用作silly的配套lua序列化库。这个库直到上周才终于完成了。
总得来说,如果2014年我得到的是新的技能的话,那么2015年我得到的其实就是经验。而获取经验的最大途径并不是来自于工作,而是对于silly的一次次的重构甚至重写。
所谓的经验其实就是各种取舍,在编码的过程中, 总会遇到各种情况,在这时就需要靠经验来进行取舍。
比如linux中的seqlock就是估算了index的递增速度以及linux调度时间来大大降低了实现的复杂度。
在silly中关于连接号的管理也同样借鉴了类似的方式大大降低了实现的复杂度。
因此在编码过程中,我们需要会的不仅仅是技能,还有对于问题的取舍,怎样做到功能和复杂度的平横,才是一个程序员迫切需要解决的问题。
在2016年,我打算阅读完luaVM的源码,一个脚本语言的设计,一个栈式虚拟机的实现,仅此而已。