年中的评价会上提了不成熟的方案,一个同事驳斥了我,因为没有仔细的看过mudos的源代码也就停了讨论。
正是周末把mudos的源代码下载下来,用调试的跳着看了下流程。
mudos 的代码还是很干净整洁的,有部分是调整过,但看得出来并没有影响整体的构思。流向和代码的分界还是很清醒的。工程使用的单线程结构,避免了不必要的数据冲突和高复杂度并带来了很好的移植性,但不可避免的降低的服务器性能。
mudos 是linux上的工程的入口是main函数,在移植到win32上使用了服务器模式,加了一个winmain的包装,核心的驱动并不是消息循环方式,而是heartbeet的方式,简单的说就是在main的尽头有一个while(1)的循环在设定的heartbeet的时间间隔下循环。这个时间是设置在select() socket函数上,这样可以不占用系统资源。
接下来的东西有点枯燥的,我建议配置好环境把断点设置到compile_file函数上,port p1 p2是宏为了兼容其他编译器的,vc7似乎也支持这样的写法。
第一个断下来的是
+ name 0x00e2d540 "adm/single/simul_efun.c" char *
可以看得出来是
void init_simul_efun P1(char *, file)
调用了他,见名思意知道是初始化efun函数
loadobject似乎给人一些误解但如果你编写过lpc程式应该了解他以文件为类的组织形似。接下来会有很长的一大段时间是初始化装载个种各样的类和函数文件,无论这些函数是什么样地他都应该属于某个类吧。让我们禁用断点跳过这一段。当可以用客户端连接到mudos的时候打开断点会看见这时候已经在backend()的领空了。在这里我们能看见前面说的while(1)和select.这时候在compile_file断下来的是
+ name 0x00e2ca4c "clone/quest/capture.c" char *
服务器开始装载游戏的道具,npc或者房间,我不清楚这个缓冲区有多大和每次心跳回缓存几个。有的时候会在调用栈看见很多的loadobject显然是在根据文件某个文件递归的载入。这个时候似乎可以告一段落了我们知道loadobjct是在不断地被调用载入文件到缓冲区,也许这个缓冲区会根据用户输入的指令调整载入的顺序但看的出来他们的运作是异步的。这也许不是很直观那么我们来看这个异步的过程是怎么运作的。在process_user_command下断点,放开其他的断点。会看见你输入的指令都停留在这里进行处理。如果单步下来你会跟着某个命令进入process_input或escape_command或call_function_interactive等几个处理函数,最多的时候我们是进入了process_input,我们看到他只是简单的调用了apply开始我以为他是把函数放到了某个命令栈当中,但不是从apply开始进入了interpret.c文件的领空。这也许是个可以优化的地方。命令被解析成了函数调用call_program()他有两个参数文件名和函数地址。这个地址应该不是二进制的地址,稍后马上会提到他。
interpret是个让人不能一眼看出用意的名字,他就是mudos核心的虚拟机了。这里是脚本运行的解释器,所有被编译的过的脚本被放在这里以函数作为最小运行单位被调用。函数在compile_file领空下被编译成了一种类似汇编语言的东西,编译的过程是用gun的两个工具Yacc 与 Lex 和相应的编译脚本。call_program就是简单的调用eval_instruction这又是个以while(1)循环的大列表,罗列了各种可能,调用了各种函数当然这是根据函数的每个命令做的。函数在被编译好之后是放在一个大的树列表下,可能是二叉树无论是什么这是一个好方法。(正确的叫法是语法树)上面提到函数地址指向了这个树,详细地内容也许有人可以去找找看。其他的文件多半是扩展的函数包括lpc的print,socket,等等,下个周末也许会把lpc编译好的代码找出来看看。
下午回来又看了下编译好的代码,是一种类似汇编的二进制代码完全没有文字的那种和c#的中间代码完全不同和汇编更接近。要是这样跟tiny c倒是很接近了。
在泥巴创世纪 bbs.mudbuilder.com/
可以找到相关的代码