【mackler】电脑mod完全教程

回过头来看这句
操作系统可以看做一个主程序,上面执行了一些子程序,这些子程序就以协程的方式受到操作系统的统一管理。
当其中一个协程执行了os.pullEventRaw之后,就执行了这边的yield,同时传递了一个sFilter。
于是这个协程挂起,控制权回到操作系统那边的resume上,resume收到了sFilter。
而有些协程或者设备通过os.queueEvent像系统发送消息,系统把这些消息在下一轮循环的时候,再通过resume的参数发送给协程。协程会从yield这里收到消息,也就是os.pullEvent返回的值。
后面我们会详细解释。这里大家先做一个了解。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:20:00 +0800 CST  
至于这个os.pullEvent
只是处理了一些terminate这个事件,收到这个事件直接退出程序(注:我们把通过上述方式在系统的不同程序、设备间传递的数据叫做事件,各个协程或者设备都可以发送事件,并且这个事件会被正在执行os.pullEvent的其他协程接受到。)

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:23:00 +0800 CST  
接下来bios.lua又定义了write(sText),用于在屏幕上输出给定的字符。用的是term API,这个API可以获取屏幕的大小、设置光标的位置,在当前光标的位置输出一个字符等操作。
write函数就以此来输出一个字符串

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:25:00 +0800 CST  
再接下来,定义了print函数
是用刚刚定义的write函数来实现的。
代码很好理解
print可以传递多个参数,用"..."表示
for循环中,将...用{}括起来,例如...是a,b,c
那么图中的for语句相当于
for n,v in ipairs({a,b,c}) do
这把传入的参数放到一个table里,然后用for语句遍历
并且对每个参数,都先调用tostring来转换为string类型,接着用刚刚定义的write输出到屏幕上。
而tostring函数的转换方式,则是由默认方式,或者metatable里定义的方法来决定的。这个在前面讲metatable的时候提到过

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:31:00 +0800 CST  
接着又定义了printError
只是在print之前将颜色设置为了红色,print完了再切换回白色
这里的term、colours都是电脑mod内建的库,我们调用这些函数的时候,lua的解释器会把这些参数传递给mod的java代码来执行,都封装好了。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:33:00 +0800 CST  
接下来的read是定义了一系列可以在有限的屏幕上操作较长文本的操作。代码很好读,大家可以自己看看写写。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:35:00 +0800 CST  
在然后定义了loadfile和dofile
lua中有一种动态加载语句的方法loadstring
就是说你可以在程序运行过程中生成一段lua代码,然后用loadstring调用这段代码以执行这段代码
loadfile则是把文件打开,读出里面的字符串,接着用loadstring载入
最后返回的就是这段代码对应的函数。
而dofile则是通过loadfile加载函数之后,给其通过setfenv设置环境,然后运行并返回运行结果。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:40:00 +0800 CST  
最后定义了一个os.run函数
传递的参数是环境和lua代码文件以及函数参数
将lua代码文件载入,并为加载的函数设置环境变量,最后把参数传递进来执行这个函数。
代码可读性很强,有前面的基础,理解不是问题

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:42:00 +0800 CST  
接下来的一段又是重新定义了一下getfenv和getmetatable
主要是为了保护string的metatable,代码不难明白~

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:45:00 +0800 CST  
下面一个函数os.loadAPI(_sPath)
还有一个局部变量tAPIsLoading,是table类型,存放已经加载的API
所谓API,其实就是一个table,里面存放了一系列方法。所谓API被加载,也就是这个table被放到了环境变量里。
大家看这个是怎么载入的,这里用到了一个技巧
在代码的第二段
local tEnv={}定义了一个空的局部table
接下来
setmetatable(tEnv,{__index=_G})
给这个空的table设置了metatable的__index域指向_G,此时访问tEnv失败就会去访问
接着
local fnAPI,err=loadfile(_sPath)
用loadfile载入了文件,接着用setfenv将tEnv作为环境设置给了fnAPI,于是tEnv中就有了fnAPI
最后for k,v in pairs(tEnv) do tAPI[k]=v
将tEnv中所有元素都导入到tAPI中,也就是载入的哪些file
最后_G[sName]=tAPI
此时访问_G相当于在访问tEnv._G,由于tEnv的metatable,又相当于_G._G,相当于_G
现在_G[sName]=tAPI,也就是把tAPI这个table中的内容都放到了sName这个域中
看代码的第4行,sName=fs.getName(_sPath),所以文件名就是API的名称,里面定义的全局函数就会成为API的方法。
电脑mod的rom目录下有个apis目录,里面是封装好的各种API,这些API的功能以后再说,我们现在只要知道API是怎么被载入的。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:56:00 +0800 CST  
当然,有load也有unload,lua中的unload很简单,就是设置为nil

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:57:00 +0800 CST  
http的部分跳过了
下面就是载入API了,上面大多数是定义函数,实际上并没被执行,这一段是真正执行的了。
载入API,就是遍历rom/apis目录,加载其中所有文件为API
如果是turtle,还要遍历rom/apis/turtle目录,手机要遍历rom/apis/pocket目录

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 00:59:00 +0800 CST  
接下来就是运行shell了
这里用到了pcall,不用理会这是什么,总之它能返回运行结果给左边的ok和err
pcall的参数是一个function,这个function包括了一个语句
parallel.waitForAny()
这个语句有2个参数,这两个参数都是函数,第一个是运行shell程序的函数,第二个是rednet.run()
其中的parallel和rednet都是上一步中载入的电脑mod API,功能下面再讲

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:03:00 +0800 CST  
最后一段是上面的shell退出之后,进行的一些操作,最后关机。
总结一下,其实bios.lua其实就是封装了一些最最基础的操作,实际核心的单元就是parallel.waitForAny和其中的2个函数,同时启动了rednet.run和shell
parallel.waitForAny可以简单理解为用协程实现的任务调度,在rednet.run和shell.run之间切换。当然了因为是协程,自然是程序主动挂起的。

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:07:00 +0800 CST  
既然bios.lua的核心是启动了shell,那我们来看看shell都做了什么吧,前面仍然是一堆shell相关函数的定义
真正主体在这里
else下面这一段是输出开头的CraftOS 1.6
接着可以看到shell.run("/rom/startup")
在然后才是一个while循环,等待我们输入命令并执行
那么这个/rom/startup相当于在shell开始循环等待输入命令前执行的一个程序

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:12:00 +0800 CST  
我们再跳转到/rom/startup里面,看看都做了什么
这一段开始是比较实际的代码
可以看到这边建立了一堆映射,把ls映射到list、dir映射到list
这就是我们最开头为什么输入ls一样可以找到list的原因。因为在shell的循环之前启动的startup为我们设置好了

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:15:00 +0800 CST  
此外还设置了一系列默认路径,例如shell输入ls转化成list之后到什么目录去找,也都在这里做了详细的定义和规定

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:16:00 +0800 CST  
startup最后两部分就是运行启动项了
第一部分是逐个运行/rom/autorun目录下的所有代码,或者/rom/autorun文件
就是说在shell启动之后,进入等待输入命令之前,会先执行/rom/autorun目录下的所有程序,当然这个目录下只有一个.ignoreme,里面没有一个代码,全是注释,并且这个/rom目录下的东西我们在游戏里是没法更改的。
第二部分是运行/autorun,这个是用户可以自己编辑的,这就提供给用户自己定制开机启动项的可能。例如我们开发了一个新的系统,我们设置到/autorun里面启动,就可以在开机后立刻进入我们的新系统了,不会进入命令行界面了
第二部分接下来是寻找电脑周围的磁盘驱动器,然后读取磁盘目录下的startup文件,一般为/disk/startup,执行这个程序。
这个就更有用了,例如我们开发了一个全新的机器人操作系统,我们要安装到1000个机器人上,如果逐个设置每个机器人,实在是相当累,我们可以写一个安装程序放到软盘的根目录,命名为startup,接着可以用机器人把要配置的机器放到磁盘驱动器旁边,然后打开机器,机器会自动运行这个startup执行安装过程。
整个电脑mod开机启动就大致介绍完了

——来自 MCLive


楼主 maple_in_thu  发布于 2014-10-22 01:26:00 +0800 CST  

楼主:maple_in_thu

字数:24301

发表时间:2014-10-12 21:33:00 +0800 CST

更新时间:2016-03-15 11:34:57 +0800 CST

评论数:395条评论

帖子来源:百度贴吧  访问原帖

 

热门帖子

随机列表

大家在看