饥荒联机版mod大全 订阅完了 下载完了 开启mod的时候mod 自己被禁用了 怎么 整啊

来自饥荒_饥荒中文wiki_饥荒攻略_MOD下载_着迷joyme
  目前TGP饥荒不管是单机版还是联机版,MOD数量都偏少,因此建议大家可以自己去Steam里面找一些自己喜欢的MOD,自己移植到TGP里面使用,本篇教程对于萌新来说非常有价值,可以让你有更多的MOD选择余地。
  注意,一般来说,Steam版的MOD和TGP是兼容的,但是某些过老的MOD可能会出现问题。另外STeam单机版MOD对应TGP饥荒单机,同样的联机版也对应联机版。
  也就是Steam Don't Starve对应TGP饥荒单机版,Steam Don't Starve Together对应TGP饥荒联机版。
  下载Steam MOD的方法有两种。
  1、先去Steam饥荒的创意工坊里面,找到自己喜欢的MOD并且订阅;
  2、接着打开游戏安装目录下面的MODS文件夹,可以直接在Steam里面找到游戏,鼠标右键点击“属性”,然后依次点击“本地文件"-"浏览本地文件”即可找到mods文件夹。
  3、之后运行Steam饥荒游戏,等你刚才订阅的MOD自动下载完毕,然后返回mods文件夹,将刚才下载的MOD复制出来并更名,名字建议是英文或者数字即可,但是不能是“workshop"开头的,也不能是汉字;
  如果你没有正版的Steam饥荒游戏也没关系,可以利用第三方网站来直接下载MOD。
  首先去Steam创意工坊找自己喜欢的MOD。
  Steam单机版创意工坊:
  Steam联机版创意工坊:
  1、先找到自己喜欢的MOD,然后记住浏览器地址栏最后的ID数字,比如下图这个,ID就是;
  2、接着复制这串ID数字,然后进入VVWALL网站(),将ID复制到下图这个位置,并且点击搜索;
  3、之后点击最下面的”下载“即可;
  4、新建一个文件夹,将下载好的MOD解压到这个文件夹里面,并且重命名,名字随便取,只要是数字或者字母即可。
  4、然后我们运行TGP,如下图所示打开TGP饥荒的游戏安装目录;
  5、将刚才从Stteam里面提取或者下载的MOD复制到TGP饥荒目录的mods文件夹下面即可;
  6、运行TGP版饥荒,在游戏的模组里面就可以看到刚才复制进去的MOD了,点击启用即可。
  注意:不是从TGP”创客空间“下载的MOD会有”警告提示“,无视即可,如果想删除MOD,就直接进入mods文件夹下面删除想删除的MOD即可。
如果你也喜欢《饥荒》,想要写一些攻略心得;或者是同人;又或者想要来着迷联机大厅找朋友一起玩,欢迎加入着迷《饥荒》WIKI攻略组,和热爱《饥荒》的我们一起,打造一个高质量的《饥荒》中文WIKI。当前位置:
→ 饥荒联机mod怎么用:房主与非房主mod开启心得
饥荒联机mod怎么用:房主与非房主mod开启心得
饥荒联机版是支持mod的,这一点相信大家都知道,那么大家知道当饥荒联机时,作为房主与非房主,是否需要开启一致mod呢?又有哪些mod是不需要大家一起开启的吗?
联机版是支持mod的,这一点相信大家都知道,那么大家知道当饥荒联机时,作为房主与非房主,是否需要开启一致mod呢?又有哪些mod是不需要大家一起开启的吗? 饥荒联机mod怎么用:房主与非房主mod开启心得1、部分,如人物mod必须一起开。2、部分,如EzInput、建筑几何,不需要一起开。3、部分只能主机开,副机开无效,而且是只要主机开了都有效,记得是自动刷新地图资源。4、部分不能用的mod先不要用,等更新看完上面的内容之后,相信大家对于作为房主与非房主时mod的使用也有了一定了解,不管怎么说呢,记得多和小伙伴多多沟通。
类别: 动作冒险 &&&大小:1.4 GB
&&&语言: 中文
读完这篇文章后,您心情如何?
江苏联通 网友 客人 发表于:
游戏攻略推荐
游戏攻略排行榜
单机游戏排行榜
1 7.4类型: 射击游戏语言: 中文大小: 2.7 GB
2 5.5类型: 动作冒险语言: 中文大小: 7.6 MB
3 7.2类型: 模拟经营语言: 中文大小: 34.3 MB
4 7.8类型: 角色扮演语言: 中文大小: 240.3 MB
5 7.2类型: 射击游戏语言: 中文大小: 414.2 MB
6 7.0类型: 模拟经营语言: 英文大小: 12.1 MB
7 8.3类型: 动作冒险语言: 中文大小: 101.6 MB
8 6.7类型: 休闲益智语言: 中文大小: 233.0 MB
9 8.5类型: 角色扮演语言: 中文大小: 76.2 MB
10 4.8类型: 动作冒险语言: 中文大小: 1.6 GB
1 7.5类型: 赛车游戏语言: 中文大小: 439.6 MB
2 7.2类型: 模拟经营语言: 中文大小: 34.3 MB
3 7.4类型: 射击游戏语言: 中文大小: 2.7 GB
4 6.7类型: 休闲益智语言: 中文大小: 233.0 MB
5 7.6类型: 角色扮演语言: 中文大小: 2.0 MB
6 7.8类型: 角色扮演语言: 中文大小: 297.8 MB
7 7.2类型: 射击游戏语言: 中文大小: 414.2 MB
8 6.1类型: 策略游戏语言: 中文大小: 18.0 MB
9 8.5类型: 角色扮演语言: 中文大小: 76.2 MB
10 6.5类型: 模拟经营语言: 中文大小: 213.8 MB
1 7.4类型: 射击游戏语言: 中文大小: 2.7 GB
2 7.2类型: 模拟经营语言: 中文大小: 34.3 MB
3 7.2类型: 休闲益智语言: 中文大小: 83.5 MB
4 6.7类型: 休闲益智语言: 中文大小: 233.0 MB
5 7.5类型: 赛车游戏语言: 中文大小: 439.6 MB
6 8.0类型: 即时战略语言: 中文大小: 1.1 GB
7 6.7类型: 动作冒险语言: 中文大小: 1.2 GB
8 7.5类型: 动作冒险语言: 中文大小: 1.4 GB
9 7.2类型: 射击游戏语言: 中文大小: 414.2 MB
10 5.5类型: 动作冒险语言: 中文大小: 7.6 MB
超多下载基地 当游网(3h3.com)
越当越快乐
www.3h3.com 版权所有 浙ICP备号本地高速下载器地址
常用软件推荐
原创软件推荐
饥荒联机版MOD整合包,这是为大家准备的最好的联机版MOD整合包,联机版以后也有MOD了,大家不用愁了,赶紧试试吧。饥荒联机版MOD使用方法:1.解压缩2.将文件夹放入游戏的MODS文件夹3.进入游戏,启用即可饥荒联机版MOD包含文件:1.全人物解锁2.传送戒指3.小地图4.G键发表情5.帐篷6.玛德琳7.显示血量8.指示玩家位置9.狐人10.胆小狗11.猫妹子12.武器属性13.地图显示牛14.鱼农场16.兔娘17.中文输入18.五格装备栏19.鼠疫医生21.智能锅22.古惑狼23.地图显示玩家24.路飞25.艾斯26.不知道是什么a7.咖啡女孩a8.九尾狐a13.悟空a15.月亮女神a17.佐罗b1.地下洞穴扩展b2.国产冰柜b3.虫洞标记b4.地窖b5.地形全开b6.堆叠99b7.建筑几何学b8.快速采集b10.全物品属性显示b13.箱子图标b14.营火不灭b15.树桩生长b16.进口冰柜b17.五项状态显示b18.芦苇可移植b19.太阳蓬b21.可再生能源世界b23.威尔逊的家b24.围墙大门
《饥荒》是由Klei制作发行的一款动作冒险类求生游戏,《饥荒》的故事讲述的是关于一名科学家被恶魔传送到了异世界荒野,他必须用自己的智慧在严酷的野外环境中求生,下面是小凡整理的饥荒联机mod大全专题,含有161以后的mod版本,158及之前的版本会报错,需要的可以来看下哦。
饥荒联机版星巴克热咖啡MOD,作为一个玩饥荒的小...
饥荒联机版炎魔李小狼人物MOD,只要有童年的人一...
饥荒联机版瓢虫少女玛里内特人物MOD,你没有看错...
饥荒联机版末日男孩人物MOD,他来自一个环境极度...
高速下载器地址
适合机型:三星N9200,三星N9200刷机包
Android版本:6.0.1
ROM大小:1990 MB
本站提供的软件会测试再上传,但无法保证所有软件都没有问题,如果您发现链接错误或其它问题,请在评论里告诉我们!
下载点支持点击下载(IE图标)或(迅雷图标),若直接点击下载速度太慢,请尝试点击其他的下载点,若文件太大请使用高速下载器。为确保下载的文件能正常使用,请使用最新版本解压本站软件。
建议大家谨慎对待所下载的文件,大家在安装的时候务必留意每一步!关于或的有关提示,请自行注意选择操作。
本站所有资源均是软件作者、开发商投稿、网上搜集,任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担!将不对任何资源负法律责任。所有资源请在下载后24小时内删除。
本站下载资源全部由软件作者或软件厂商提供,游戏相关下载转自各大游戏论坛及游戏下载站,并全部为免费分享。如侵犯了您的版权,请立刻联系我们并附带版权证明,本站将尽快处理删除(举报联系QQ:3909136),或。
若您下载的资源有问题或无法下载,请与本站客服人员联系(QQ:9190104)。&figure&&img src=&https://pic3.zhimg.com/1655feb05cd5d744ab663bd_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic3.zhimg.com/1655feb05cd5d744ab663bd_r.jpg&&&/figure&新写一篇文章,以纪念在制作和调试饥荒游戏LuaJIT桥接PATCH中探过的雷区。&p&本文大体已经更新完结,如有新的内容会及时补充。&br&&/p&&p&关于饥荒游戏的介绍,直接看这个答案好了:&a href=&https://www.zhihu.com/question/& class=&internal&&&span class=&invisible&&https://www.&/span&&span class=&visible&&zhihu.com/question/2128&/span&&span class=&invisible&&2202&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&关于本插件的详细介绍,下载及源码请点击:&a href=&http://link.zhihu.com/?target=https%3A//paintdream.github.io/DontStarveLuaJIT/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&paintdream.github.io/Do&/span&&span class=&invisible&&ntStarveLuaJIT/&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&本文所用到的软件:OllyDBG 2.01、Microsoft Visual C++ 2008&/p&&br&&p&-----------------------------------------我是分割线------------------------------------------------&/p&&p&&b&0x00 神船搁浅&/b&&/p&&p&我要给饥荒写PATCH,并不是一个刚开始就计划好的事情。饥荒发布于Steam平台并且添加了创意工坊,里面有很多好的、差的、能用的、不能用的、原创的以及抄的Mods,大部分都维护得很好,开游戏时连存档带MOD设置都会被云同步更新,几乎可以是完美了。&/p&&p&然而唯一的美中不足似乎是:这游戏居然很吃配置。N年前买的神船竟然会在玩久了之后就会时不时顿卡,以至于到后来居然越来越卡了。虽然i7-3610QM+GT650M在现在看来也比较渣,但是至少跑跑dota2中配都还很流畅,也不至于在饥荒上惨成这样。&/p&&p&打开任务管理器瞄一眼,发现情况还是很有意思的。在卡顿的时候,CPU只有两个核心满载运行,其余都在打酱油——通过暂停-恢复的办法观察CPU占用率,可以得出结论,CPU0是负责渲染的线程,CPU6是负责脚本逻辑的线程。&/p&&p&&figure&&img src=&https://pic2.zhimg.com/e61b23a34abda57c9dfb88c_b.jpg& data-rawheight=&519& data-rawwidth=&345& class=&content_image& width=&345&&&/figure&卡顿是来自于两方面的,一方面如果绘制的对象较多,机器就会明显开始变卡。这时CPU0的使用率会明显下降,说明有大量绘制指令阻塞了渲染管线,导致绘制线程长期处于等待渲染完成的阻塞状态。同时用户的输入反馈也会被明显阻滞,推测读取用户输入的相关代码也是在这个线程中执行的(饥荒使用了DirectInput来读取键盘操作)。饥荒本身这种哥特式的画风,使用一些预制的纹理搞搞Billboard贴图就可以做出伪2D的画面效果了,渲染本身压力应该不算大。但是考虑到ES版本低的限制用不了Instanced Draw,很可能是每个对象都对应一个draw call,并且每个对象绘制时都重复提交了大量数据,导致带宽用尽。不过这方面我现在还没有做仔细的研究,仅仅是猜测而已。&/p&&p&另一方面如果脚本的逻辑过于复杂,也会明显变卡。这时CPU6将会被占满,而由于逻辑帧与渲染帧同步的关系,CPU0的占用率会变低。这方面的问题相对来说比较严重,因为为了好玩大家都会加载很多MODs,Shipwrecked DLC新增加的游戏特性也非常吃CPU,导致大家在玩这个DLC时感受到的卡顿远远比原版或者Reign of Giants DLC时要明显得多。因此在很多论坛上大家解决这个卡顿的办法只有——别开那么多MOD,换个好点的电脑。&/p&&p&本文尝试解决的是脚本逻辑引起的卡顿。&/p&&p&&b&0x01 积重难返&/b&&br&&/p&&p&好消息是饥荒使用了我比较熟悉的lua 5.1.4作为脚本引擎(但是实际上我更希望看到的是lua 5.3),并且随游戏附送了所有的lua脚本(大约18万行,不算DLC),所有的逻辑都是在脚本中实现的。&/p&&p&研究了几个小时后发现,作者似乎仅仅是把它当作一个工具来用,没有专门在lua特性上下功夫。为了写起来更方便和熟悉,当需要异步操作时,大部分的需求都是通过C层面支持的时钟回调(往往配合全局任务队列)来完成的。这个设计也给我造成了麻烦,因为它会使原本完整的逻辑从中断开,调试时打印调用堆栈就只能看到当前事件触发后的逻辑。&/p&&p&那么,为什么不用coroutine呢?我搜了下源码,有三个地方对coroutine进行了封装,其中两个是有关网络的第三方库,主要负责发邮件之类的工作 ,和游戏逻辑没什么关系。唯一用到的就是调度器添加任务的时候,为每一个新任务创建一个coroutine,然后调度的时候枚举所有任务一个个执行。&/p&&p&然而,这个coroutine似乎仅仅是由来保存一个独立执行栈的——调度器对它的操作仅仅是从队列中取出然后执行完删掉。全部代码中只有9个很少执行到的地方用到了Yield()。个人觉得这个coroutine的用法值得商榷——毕竟coroutine本身还是有一点点开销的,而且绝大多数异步需求还是用回调来完成的。&/p&&p&从lua代码架构上看,这套脚本自己实现了一个简单的类似C++的面向对象框架,模块的封装比较任性,耦合度也有点高,经常会出现在底层框架代码中去加一些代码来控制上层实现逻辑的代码。而它发布的两个DLC并不是在原有代码框架上开发的扩展包,而是直接把代码复制出来进行修改的,估计最初写的时候也没想要有个DLC……&/p&&p&可以看出,游戏本身应该是直接从一个简单的原型一步步迭代上来的,虽然在开发的过程中有过抽象和封装,但是积重难返,大体的结构已经固定,没有什么简单的优化空间了。脚本负责了太重的任务,并行方面做的工作也不多,试图直接优化现有代码对于我来说已经成了死局。&/p&&p&因此把lua引擎替换为LuaJIT已经成了为数不多的可以让程序运行起来不那么卡的选择了。虽然从道理上讲,这也只能算是治标不治本,但是好歹能有的玩啊。&/p&&p&&b&0x02 横生枝节&/b&&/p&&p&但是事情远远没有想的那么简单。我最初以为直接把饥荒可能用到的lua51.dll换成luajit.dll就万事大吉了,然而翻遍了安装目录也没看到lua51.dll库的影子。那么次一点的结果就是LUA被封装在了别的DLL里,由dontstarve_steam.exe启动时加载。然而最终发现lua引擎是直接作为静态库或者源码编译进主程序的,这是最糟糕的结果。&/p&&p&这个麻烦在于,我们知道exe通常不需要导出函数(仔细看了下dontstarve_steam.exe确实没导出),那么如何定位lua api在exe中的位置就成了首要解决的问题。&/p&&p&EXE中lua api的布局和DLL中是完全不一样的:编译器可以剪掉那些没被引用到的函数与常量,也可以重排函数的顺序。想要通过公开的或者凑巧的办法定位到这些函数是不可能的。那么就剩下了三条路:直接改EXE,硬编码与特征码搜索。&/p&&p&直接改EXE或者硬编码相应函数的RVA看起来简单粗暴,但是万一饥荒EXE更新了就得新发布个版本,而且为了得到地址还得手工用特征码先搜索并较正一遍。想了想还是用特征码吧,而且还要尽量做成非侵入式的,这样就可以有效地兼容饥荒自己的更新。&/p&&p&&b&0x03 探针计划&/b&&/p&特征码搜索需要先找到每个函数对应的特征码。为此我的思路是,先编译一份原汁原味的lua 5.1.4的DLL,把LUA API设置为导出,这样就能得到每个API的地址,进而用函数开头的二进制指令作为特征码在EXE中进行搜索。接下来,只需要把搜索到的源地址和名字一一对应起来,然后加载luajit.dll就可以再通过kernel32.dll!GetProcAddress拿到目标地址,通过inline hook将源地址处的执行流导向目标地址。由于这些hooks不需要执行原函数,计算跳板所保留的原函数头部字节数也就没有必要了。&p&不同的编译器生成目标代码时的算法都是很不一样的,甚至就算是同一系列的编译器,随着版本更新也会有不同。那么应该用什么来编译原版lua DLL呢?当然是与饥荒主程序保持一致。OllyDBG告诉我们答案:MSVC9,即Microsoft Visual C++ 2008。&/p&&figure&&img src=&https://pic4.zhimg.com/04da3c510db72fc7afa61b_b.jpg& data-rawheight=&409& data-rawwidth=&601& class=&origin_image zh-lightbox-thumb& width=&601& data-original=&https://pic4.zhimg.com/04da3c510db72fc7afa61b_r.jpg&&&/figure&&br&&p&然而在开始编码之前,先要解决的问题是:怎么让我的代码得到执行?&/p&&p&很明显如果想要做非侵入式的Patch,要么额外写一个启动器,要么通过某种技巧让我们的代码在游戏启动时得到执行。官方的MOD机制允许自定义mod在游戏初始化的时候执行lua代码,然而这时候lua引擎已经建立,再替换就晚了,肯定不行。&/p&&p&于是我的目光移动到exe依赖的那些DLL上,看看有什么偷梁换柱的策略。所谓的偷梁换柱就是指,针对目标EXE所依赖的DLL,写一个傀儡DLL,名字和导出函数都和目标DLL一样,然后放在EXE目录中就可以在EXE启动时被加载。加载后再手动用kernel32.dllLoadLibraryA/W加载目标DLL,并把导出的函数都转接到目标DLL中对应的函数里去。早些年一些病毒为了禁用杀毒软件,就在杀毒软件安装目录下放一个假的ws2_32.dll,这样杀毒软件启动时就会崩溃或者被劫持。注意一些系统核心的DLL是不受这个影响的,如kernel32.dll, ntdll.dll等)&/p&&p&饥荒主程序目录下那些DLL大多都是C++写的,导出函数的名字都是经过name decoration的,处理起来会比较麻烦。加之导出函数的数量也很多,有点不划算。&/p&&p&找了半天,最佳的选择是DINPUT8.DLL,这个DLL是DirectInput所需要的。选择它的原因是dontstarve_steam.exe只从其中导入了一个函数DirectInput8Create,用来创建DirectInput的设备对象,由于这个对象是用COM封装的,所以DLL不再需要导出其成员函数,导入表项因此就简洁了很多。还有一个好处,由于它是处于系统目录中的DLL,替换它不需要替换原有的DLL,只需要在EXE目录中放置即可被加载,是完美的非侵入式PATCH的选择。&br&&/p&&figure&&img src=&https://pic3.zhimg.com/3f6fe4799_b.jpg& data-rawheight=&253& data-rawwidth=&422& class=&origin_image zh-lightbox-thumb& width=&422& data-original=&https://pic3.zhimg.com/3f6fe4799_r.jpg&&&/figure&&p&如前文所述,你接管了DINPUT8.DLL,那么也就得实现DirectInput8Create这个函数,否则游戏启动时会找不到入口。这个很容易:&br&&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&typedef&/span& &span class=&nf&&HRESULT&/span&&span class=&p&&(&/span&&span class=&n&&WINAPI&/span& &span class=&o&&*&/span&&span class=&n&&PFNDirectInput8Create&/span&&span class=&p&&)(&/span&&span class=&n&&HINSTANCE&/span& &span class=&n&&hinst&/span&&span class=&p&&,&/span& &span class=&n&&DWORD&/span& &span class=&n&&dwVersion&/span&&span class=&p&&,&/span& &span class=&n&&REFIID&/span& &span class=&n&&riidltf&/span&&span class=&p&&,&/span& &span class=&n&&LPVOID&/span& &span class=&o&&*&/span&&span class=&n&&ppvOut&/span&&span class=&p&&,&/span& &span class=&n&&LPUNKNOWN&/span& &span class=&n&&punkOuter&/span&&span class=&p&&);&/span&
&span class=&k&&static&/span& &span class=&n&&PFNDirectInput8Create&/span& &span class=&n&&pfnDirectInput8Create&/span& &span class=&o&&=&/span& &span class=&nb&&NULL&/span&&span class=&p&&;&/span&
&span class=&n&&HRESULT&/span& &span class=&n&&WINAPI&/span& &span class=&nf&&DirectInput8Create&/span&&span class=&p&&(&/span&&span class=&n&&HINSTANCE&/span& &span class=&n&&hinst&/span&&span class=&p&&,&/span& &span class=&n&&DWORD&/span& &span class=&n&&dwVersion&/span&&span class=&p&&,&/span& &span class=&n&&REFIID&/span& &span class=&n&&riidltf&/span&&span class=&p&&,&/span& &span class=&n&&LPVOID&/span& &span class=&o&&*&/span&&span class=&n&&ppvOut&/span&&span class=&p&&,&/span& &span class=&n&&LPUNKNOWN&/span& &span class=&n&&punkOuter&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&pfnDirectInput8Create&/span&&span class=&p&&(&/span&&span class=&n&&hinst&/span&&span class=&p&&,&/span& &span class=&n&&dwVersion&/span&&span class=&p&&,&/span& &span class=&n&&riidltf&/span&&span class=&p&&,&/span& &span class=&n&&ppvOut&/span&&span class=&p&&,&/span& &span class=&n&&punkOuter&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&nl&&DllMain&/span&&span class=&p&&:&/span&
&span class=&n&&TCHAR&/span& &span class=&n&&systemPath&/span&&span class=&p&&[&/span&&span class=&n&&MAX_PATH&/span&&span class=&p&&];&/span&
&span class=&o&&::&/span&&span class=&n&&GetSystemDirectory&/span&&span class=&p&&(&/span&&span class=&n&&systemPath&/span&&span class=&p&&,&/span& &span class=&n&&MAX_PATH&/span&&span class=&p&&);&/span&
&span class=&n&&HMODULE&/span& &span class=&n&&hInput&/span& &span class=&o&&=&/span& &span class=&o&&::&/span&&span class=&n&&LoadLibrary&/span&&span class=&p&&(&/span&&span class=&n&&CString&/span&&span class=&p&&(&/span&&span class=&n&&systemPath&/span&&span class=&p&&)&/span& &span class=&o&&+&/span& &span class=&n&&_T&/span&&span class=&p&&(&/span&&span class=&s&&&&/span&&span class=&se&&\\&/span&&span class=&s&&DINPUT8.DLL&&/span&&span class=&p&&));&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&hInput&/span& &span class=&o&&!=&/span& &span class=&nb&&NULL&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&pfnDirectInput8Create&/span& &span class=&o&&=&/span& &span class=&p&&(&/span&&span class=&n&&PFNDirectInput8Create&/span&&span class=&p&&)&/span&&span class=&o&&::&/span&&span class=&n&&GetProcAddress&/span&&span class=&p&&(&/span&&span class=&n&&hInput&/span&&span class=&p&&,&/span& &span class=&s&&&DirectInput8Create&&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&在上面的代码里,DllMain里需要加载真正的DINPUT8.DLL,然后获取到DirectInput8Create的地址,然后才能在中继代码中CALL。需要注意的是,我们最好不要包含任何有关DirectX SDK的头文件,这些头文件往往会指定API为导入,而我们需要将同名的中继函数导出。&/p&&p&如果遇到了类型没定义的错误也不用急,按照其长度写一个等价的就行了。后文我会介绍一个更简单的制作中继函数跳板的办法。&/p&&p&那么,接下来是怎么搜的问题。我们先来编译原版lua51.dll,编译设置选择Release版本。&/p&&figure&&img src=&https://pic1.zhimg.com/a5b0dab4785b9_b.jpg& data-rawheight=&600& data-rawwidth=&800& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/a5b0dab4785b9_r.jpg&&&/figure&&br&&p&如果在用kernel32.dll!LoadLibraryA/W加载了原版的lua51.dll之后,直接拿API函数开始的二进制码去做搜索,只能搜索到一小部分函数。这是由于DLL中的代码需要根据.reloc节的信息进行重定位,需要定位的地方二进制值会变,因此纯粹的memcmp行不通。&/p&&p&在这里我直接采用了一个较简单但是相对耗时的策略:在搜索时利用反汇编引擎XDE32一条条解析指令格式,发现需要重定位的指令,就读取地址处的值代替地址本身充当特征码。&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&while&/span& &span class=&p&&(&/span&&span class=&n&&target&/span& &span class=&o&&&&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&xde_disasm&/span&&span class=&p&&((&/span&&span class=&n&&BYTE&/span&&span class=&o&&*&/span&&span class=&p&&)&/span&&span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&instr&/span&&span class=&p&&);&/span&
&span class=&kt&&int&/span& &span class=&n&&len&/span& &span class=&o&&=&/span& &span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&len&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&len&/span& &span class=&o&&==&/span& &span class=&mi&&0&/span&&span class=&p&&)&/span&
&span class=&k&&break&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&opcode&/span& &span class=&o&&==&/span& &span class=&mh&&0x68&/span& &span class=&o&&||&/span& &span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&addrsize&/span& &span class=&o&&==&/span& &span class=&mi&&4&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&// read memory data&/span&
&span class=&n&&PVOID&/span& &span class=&n&&addr&/span& &span class=&o&&=&/span& &span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&opcode&/span& &span class=&o&&==&/span& &span class=&mh&&0x68&/span& &span class=&o&&?&/span& &span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&n&&PVOID&/span&&span class=&o&&*&/span&&span class=&p&&)(&/span&&span class=&n&&c&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&p&&(&/span&&span class=&n&&PVOID&/span&&span class=&p&&)&/span&&span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&addr_l&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&];&/span&
&span class=&kt&&char&/span& &span class=&n&&buf&/span&&span class=&p&&[&/span&&span class=&mi&&16&/span&&span class=&p&&];&/span&
&span class=&n&&memset&/span&&span class=&p&&(&/span&&span class=&n&&buf&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&k&&sizeof&/span&&span class=&p&&(&/span&&span class=&n&&buf&/span&&span class=&p&&));&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&addr&/span& &span class=&o&&!=&/span& &span class=&nb&&NULL&/span& &span class=&o&&&&&/span& &span class=&o&&::&/span&&span class=&n&&ReadProcessMemory&/span&&span class=&p&&(&/span&&span class=&o&&::&/span&&span class=&n&&GetCurrentProcess&/span&&span class=&p&&(),&/span& &span class=&n&&addr&/span&&span class=&p&&,&/span& &span class=&n&&buf&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&nb&&NULL&/span&&span class=&p&&))&/span& &span class=&p&&{&/span&
&span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&stringList&/span&&span class=&p&&.&/span&&span class=&n&&push_back&/span&&span class=&p&&(&/span&&span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&make_pair&/span&&span class=&p&&(&/span&&span class=&n&&addr&/span&&span class=&p&&,&/span& &span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span&&span class=&p&&(&/span&&span class=&n&&buf&/span&&span class=&p&&)));&/span&
&span class=&p&&}&/span&
&span class=&n&&BYTE&/span& &span class=&n&&temp&/span&&span class=&p&&[&/span&&span class=&mi&&16&/span&&span class=&p&&];&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&opcode&/span& &span class=&o&&==&/span& &span class=&mh&&0x68&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&memcpy&/span&&span class=&p&&(&/span&&span class=&n&&temp&/span&&span class=&p&&,&/span& &span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&len&/span&&span class=&p&&);&/span&
&span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&n&&PVOID&/span&&span class=&o&&*&/span&&span class=&p&&)(&/span&&span class=&n&&temp&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&)&/span& &span class=&o&&=&/span& &span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&n&&PVOID&/span&&span class=&o&&*&/span&&span class=&p&&)&/span&&span class=&n&&buf&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&n&&instr&/span&&span class=&p&&.&/span&&span class=&n&&addr_l&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&kt&&long&/span&&span class=&o&&*&/span&&span class=&p&&)&/span&&span class=&n&&buf&/span&&span class=&p&&;&/span&
&span class=&n&&xde_asm&/span&&span class=&p&&(&/span&&span class=&n&&temp&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&instr&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&n&&memcpy&/span&&span class=&p&&(&/span&&span class=&n&&target&/span&&span class=&p&&,&/span& &span class=&n&&temp&/span&&span class=&p&&,&/span& &span class=&n&&len&/span& &span class=&o&&+&/span& &span class=&n&&target&/span& &span class=&o&&&&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&?&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&-&/span& &span class=&nl&&target&/span& &span class=&p&&:&/span& &span class=&n&&len&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&n&&memcpy&/span&&span class=&p&&(&/span&&span class=&n&&target&/span&&span class=&p&&,&/span& &span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&len&/span& &span class=&o&&+&/span& &span class=&n&&target&/span& &span class=&o&&&&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&?&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&-&/span& &span class=&nl&&target&/span& &span class=&p&&:&/span& &span class=&n&&len&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&n&&c&/span& &span class=&o&&+=&/span& &span class=&n&&len&/span&&span class=&p&&;&/span&
&span class=&n&&target&/span& &span class=&o&&+=&/span& &span class=&n&&len&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&edge&/span&&span class=&p&&)&/span&
&span class=&n&&validLength&/span& &span class=&o&&+=&/span& &span class=&n&&len&/span& &span class=&o&&+&/span& &span class=&n&&target&/span& &span class=&o&&&&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&?&/span& &span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&instr&/span& &span class=&o&&+&/span& &span class=&n&&INSTR_SIZE&/span& &span class=&o&&-&/span& &span class=&nl&&target&/span& &span class=&p&&:&/span& &span class=&n&&len&/span&&span class=&p&&;&/span&
&span class=&n&&entry&/span&&span class=&p&&.&/span&&span class=&n&&lengthHist&/span&&span class=&p&&[&/span&&span class=&n&&len&/span&&span class=&p&&]&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&c&/span& &span class=&o&&==&/span& &span class=&mh&&0xCC&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&edge&/span& &span class=&o&&=&/span& &span class=&nb&&true&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&具体到匹配算法,为了避免因微小长度差异而导致整体错位,我没有直接memcmp,而是用了最长公共子串的动态规划算法,时间和空间复杂度都为O(N * N)。对于不太长的特征序列,性能上的损失可以接受。&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&nf&&CommonLength&/span&&span class=&p&&(&/span&&span class=&k&&const&/span& &span class=&n&&BYTE&/span&&span class=&o&&*&/span& &span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&kt&&int&/span& &span class=&n&&xlen&/span&&span class=&p&&,&/span& &span class=&k&&const&/span& &span class=&n&&BYTE&/span&&span class=&o&&*&/span& &span class=&n&&y&/span&&span class=&p&&,&/span& &span class=&kt&&int&/span& &span class=&n&&ylen&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kt&&int&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&INSTR_SIZE&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&][&/span&&span class=&n&&INSTR_SIZE&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&];&/span&
&span class=&n&&memset&/span&&span class=&p&&(&/span&&span class=&n&&opt&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&k&&sizeof&/span&&span class=&p&&(&/span&&span class=&n&&opt&/span&&span class=&p&&));&/span&
&span class=&k&&for&/span& &span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&i&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span& &span class=&n&&i&/span& &span class=&o&&&=&/span& &span class=&n&&xlen&/span&&span class=&p&&;&/span& &span class=&n&&i&/span&&span class=&o&&++&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&for&/span& &span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&j&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span& &span class=&n&&j&/span& &span class=&o&&&=&/span& &span class=&n&&ylen&/span&&span class=&p&&;&/span& &span class=&n&&j&/span&&span class=&o&&++&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&[&/span&&span class=&n&&i&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&]&/span& &span class=&o&&==&/span& &span class=&n&&y&/span&&span class=&p&&[&/span&&span class=&n&&j&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&])&/span&
&span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span&&span class=&p&&][&/span&&span class=&n&&j&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&][&/span&&span class=&n&&j&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&]&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&k&&else&/span&
&span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span&&span class=&p&&][&/span&&span class=&n&&j&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&][&/span&&span class=&n&&j&/span&&span class=&p&&]&/span& &span class=&o&&&&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span&&span class=&p&&][&/span&&span class=&n&&j&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&]&/span& &span class=&o&&?&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&][&/span&&span class=&n&&j&/span&&span class=&p&&]&/span& &span class=&o&&:&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&i&/span&&span class=&p&&][&/span&&span class=&n&&j&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&p&&];&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&n&&opt&/span&&span class=&p&&[&/span&&span class=&n&&xlen&/span&&span class=&p&&][&/span&&span class=&n&&ylen&/span&&span class=&p&&];&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&搜索的范围只需要设置为dontstarve_steam.exe的.text节所在范围即可,其实我在试了几个版本之后,发现.text + 0x170000之后才会有对应的lua api的函数。因此为了速度快些就直接以.text + 0x170000为地点,.text的末尾为终点了。(当然其实这么做有一定风险,不过一直懒得改。。万一哪天饥荒有大更新很可能会出错)&p&搜索到目标函数之后,标记下来,并与luajit连接即可。下面是inline hook的代码:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&Hook&/span&&span class=&p&&(&/span&&span class=&n&&BYTE&/span&&span class=&o&&*&/span& &span class=&n&&from&/span&&span class=&p&&,&/span& &span class=&n&&BYTE&/span&&span class=&o&&*&/span& &span class=&n&&to&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&// prepare inline hook&/span&
&span class=&kt&&unsigned&/span& &span class=&kt&&char&/span& &span class=&n&&code&/span&&span class=&p&&[&/span&&span class=&mi&&5&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&p&&{&/span& &span class=&mh&&0xe9&/span&&span class=&p&&,&/span& &span class=&mh&&0x00&/span&&span class=&p&&,&/span& &span class=&mh&&0x00&/span&&span class=&p&&,&/span& &span class=&mh&&0x00&/span&&span class=&p&&,&/span& &span class=&mh&&0x00&/span& &span class=&p&&};&/span&
&span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&n&&DWORD&/span&&span class=&o&&*&/span&&span class=&p&&)(&/span&&span class=&n&&code&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&p&&)&/span& &span class=&o&&=&/span& &span class=&p&&(&/span&&span class=&n&&DWORD&/span&&span class=&p&&)&/span&&span class=&n&&to&/span& &span class=&o&&-&/span& &span class=&p&&(&/span&&span class=&n&&DWORD&/span&&span class=&p&&)&/span&&span class=&n&&from&/span& &span class=&o&&-&/span& &span class=&mi&&5&/span&&span class=&p&&;&/span&
&span class=&n&&DWORD&/span& &span class=&n&&oldProtect&/span&&span class=&p&&;&/span&
&span class=&o&&::&/span&&span class=&n&&VirtualProtect&/span&&span class=&p&&(&/span&&span class=&n&&from&/span&&span class=&p&&,&/span& &span class=&mi&&5&/span&&span class=&p&&,&/span& &span class=&n&&PAGE_READWRITE&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&oldProtect&/span&&span class=&p&&);&/span&
&span class=&o&&::&/span&&span class=&n&&memcpy&/span&&span class=&p&&(&/span&&span class=&n&&from&/span&&span class=&p&&,&/span& &span class=&n&&code&/span&&span class=&p&&,&/span& &span class=&mi&&5&/span&&span class=&p&&);&/span&
&span class=&o&&::&/span&&span class=&n&&VirtualProtect&/span&&span class=&p&&(&/span&&span class=&n&&from&/span&&span class=&p&&,&/span& &span class=&mi&&5&/span&&span class=&p&&,&/span& &span class=&n&&oldProtect&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&oldProtect&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&(个人比较喜欢0xE8/0xE9这种HOOK,不需要改寄存器,长度也很短。当然也可以用PUSH+RET, FF 15/25 即CALL/JMP DWORD PTR [ADDR]的,各有所需)&/p&&br&&p&&b&0x04 引火烧身&/b&&/p&&p&写完代码,编译好DLL,并将其改名为DINPUT8.DLL。同时再编译一份luajit的DLL,重命名为luajit.dll(原来的名字是lua51.dll),再加上直接用VS2008编译lua 5.1.4源码得到的lua51.dll,总共是三个文件。&/p&&p&将这三个文件复制到饥荒的bin目录,启动游戏。(见证奇迹的时候到了!!)&/p&&p&不出意外,BOOM!程序崩溃了!!&/p&&p&客位看官不好意思,前面洋洋洒洒写了一大堆,看起来有极大可能并没有什么用。&/p&&figure&&img src=&https://pic1.zhimg.com/11a027ee4f3dcccf830215_b.jpg& data-rawheight=&237& data-rawwidth=&280& class=&content_image& width=&280&&&/figure&不过仔细想想,这也不总是悲剧,至少证明了我们还是具有了利用DINPUT8傀儡来捅篓子的能力。&br&&p&但是为什么会崩溃呢?总得有个交待啊!!通过仔细的排查(其实就是打了个LOG),发现其实有部分函数就没Hook上。&/p&&p&但是为什么没Hook上呢?前面搜索花了那么大的精力,为什么结果还是不对呢?&/p&&br&&p&&b&0x05 调试器下没有秘密&/b&&/p&&p&没办法,只能用OllyDBG调试下试试了。由于饥荒的exe你直接点击是不会启动游戏的,它只会启动STEAM,然后用STEAM再启动游戏,所以我只能在DINPUT8.DLL的DllMain里,强行加一个getchar(),然后在STEAM中启动游戏,使用OllyDBG附加调试。&/p&&p&按ALT+E打开模块列表,点击dontstarve_steam.exe,启动Search for =& All inter-modular calls,就可以看到大多数函数已经被成功HOOK了。&/p&&figure&&img src=&https://pic2.zhimg.com/18ea8a0ac9d736e158a40a2ec079c6ec_b.jpg& data-rawheight=&944& data-rawwidth=&1472& class=&origin_image zh-lightbox-thumb& width=&1472& data-original=&https://pic2.zhimg.com/18ea8a0ac9d736e158a40a2ec079c6ec_r.jpg&&&/figure&&br&&p&一个个检查HOOK的函数,发现只要是搜索到了目标,基本上就没有什么大问题。问题在于很多函数就没找到,而且吊诡的是,自己手工去用OD强大的Search Command功能去搜,放宽搜索的匹配条件,也是找不到的。&/p&&figure&&img src=&https://pic3.zhimg.com/759e8bc888bd69eb849a05d_b.jpg& data-rawheight=&52& data-rawwidth=&90& class=&content_image& width=&90&&&/figure&所以……&p&难道是……&/p&&p&那些函数压根就不存在……吗?&br&&/p&&figure&&img src=&https://pic1.zhimg.com/ed27b57e1f7ba4faad26aae469c024ff_b.jpg& data-rawheight=&78& data-rawwidth=&78& class=&content_image& width=&78&&&/figure&&p&好吧。这个结论竟然对了一半。&/p&&p&确实有些api在exe中是没有的,因为exe没用到它们,编译器在连接的时候把它们抹掉了。我于是在lua51.dll中删除了它们的导出项。&/p&&p&另一部分呢,确实是没搜索到。通过查找字符串引用逐步定位相关指令的办法(具体就不详述了),我发现了一件怪事:&/p&&p&这些API和lua 5.1.4 DLL中的api在二进制层面上差别非常大!&/p&&br&&br&&br&&b&0x06 飞轮与链条&/b&&p&如果饥荒的作者修改过这些函数的实现,那么情况就非常僵了——我得在luajit中做等价的修改。不过仔细比对后发现,事情没有那么糟糕。&/p&&p&不一致的地方主要来自于两种原因:&/p&&p&1. 部分API调用内部函数被inline&/p&&p&2. 饥荒作者删除了部分API中关于luaC_checkGC调用&/p&&br&&br&&p&对于1,参考下图:&/p&&figure&&img src=&https://pic4.zhimg.com/9efda57f47acf5a540e20bf_b.jpg& data-rawheight=&752& data-rawwidth=&1619& class=&origin_image zh-lightbox-thumb& width=&1619& data-original=&https://pic4.zhimg.com/9efda57f47acf5a540e20bf_r.jpg&&&/figure&&p&luaO_pushfstring是lua_pushfstring所调用的函数,在饥荒主程序里这个调用是被inline的,导致其与我编译的lua51.dll中lua_pushfstring的二进制码不一致。&/p&&br&&p&对于2,参考下图:&/p&&p&&figure&&img src=&https://pic1.zhimg.com/efacb334860a_b.jpg& data-rawheight=&752& data-rawwidth=&1573& class=&origin_image zh-lightbox-thumb& width=&1573& data-original=&https://pic1.zhimg.com/efacb334860a_r.jpg&&&/figure&饥荒作者删除了代码中的一些luaC_checkGC的调用,从而使得一些函数不再会触发垃圾收集。这种想法是为了避免某些BUG吗?(比如C层面持有的对象因没有维持引用而失效)还是试图降低卡顿?我不得而知。但是奇怪的是,联机版的饥荒(针对联机版的内容主要参见后文)改动的地点和单机版并不一致。(上图中我添加的luaC_checkGC_是一个空宏,等价于把GC调用删除掉)&/p&&p&经过如上的修改之后重新编译lua51.dll,我们重新制作的链条终于能和饥荒原程序的飞轮啮合在一起了。&/p&&p&&b&0x07 打包炸弹&/b&&/p&&p&启动时崩溃,按照OllyDBG的LOG跟踪到是luajit有部分常数的值太小(如函数串最多常量个数,参数列表最多参数个数),改成大一些的值即可,不在此详述了。(饥荒真是内存杀手)&/p&&p&折腾了半天,我们的破补丁总算能勉强跑起来了。顺利度过loading界面,主界面成功启动!久违的背景音乐响起~&/p&&figure&&img src=&https://pic3.zhimg.com/ca9634288eaf9d8913770e_b.jpg& data-rawheight=&727& data-rawwidth=&1292& class=&origin_image zh-lightbox-thumb& width=&1292& data-original=&https://pic3.zhimg.com/ca9634288eaf9d8913770e_r.jpg&&&/figure&&br&&p&先随便试试基本的功能吧,先点下MODS看看会不会挂……&/p&&p&由墨菲定律可知:如果一个地方你感觉会出错,那么它就会出错。。于是有插件崩溃了。&/p&&figure&&img src=&https://pic2.zhimg.com/9efa97cd533aaadf_b.jpg& data-rawheight=&728& data-rawwidth=&1293& class=&origin_image zh-lightbox-thumb& width=&1293& data-original=&https://pic2.zhimg.com/9efa97cd533aaadf_r.jpg&&&/figure&&p&虽然在游戏中按“`”键也可以打开内置的控制台,但是这里LOG显示的行数有限,且不能滚屏。于是直接打开OllyDBG的LOG看看倒底发生了什么:&/p&&figure&&img src=&https://pic3.zhimg.com/e70debf13bcb68c5a3268cae_b.jpg& data-rawheight=&640& data-rawwidth=&862& class=&origin_image zh-lightbox-thumb& width=&862& data-original=&https://pic3.zhimg.com/e70debf13bcb68c5a3268cae_r.jpg&&&/figure&&br&&p&(这些LOG是用OutputDebugString输出的,需要OllyDBG 2.0以上版本才支持在调试器内显示它们。)&/p&&p&从上面的文字中可以看出,在加载翼语MOD的时候,mods.lua第42行报错,提示'arg'这个变量没有被定义。&br&&/p&&p&那么就去看看喽:&/p&&div class=&highlight&&&pre&&code class=&language-lua&&&span&&/span&&span class=&kd&&local&/span& &span class=&n&&runmodfn&/span& &span class=&o&&=&/span& &span class=&k&&function&/span&&span class=&p&&(&/span&&span class=&n&&fn&/span&&span class=&p&&,&/span&&span class=&n&&mod&/span&&span class=&p&&,&/span&&span class=&n&&modtype&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&p&&(&/span&&span class=&k&&function&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&n&&fn&/span& &span class=&k&&then&/span&
&span class=&kd&&local&/span& &span class=&n&&status&/span&&span class=&p&&,&/span& &span class=&n&&r&/span& &span class=&o&&=&/span& &span class=&nb&&xpcall&/span&&span class=&p&&(&/span& &span class=&k&&function&/span&&span class=&p&&()&/span& &span class=&k&&return&/span& &span class=&n&&fn&/span&&span class=&p&&(&/span&&span class=&nb&&unpack&/span&&span class=&p&&(&/span&&span class=&n&&arg&/span&&span class=&p&&))&/span& &span class=&k&&end&/span&&span class=&p&&,&/span& &span class=&nb&&debug.traceback&/span&&span class=&p&&)&/span& &span class=&c1&&--&& 42&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&status&/span& &span class=&k&&then&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&error calling &&/span&&span class=&o&&..&/span&&span class=&n&&modtype&/span&&span class=&o&&..&/span&&span class=&s2&&&&/span&&span class=&s&& in mod &&/span&&span class=&o&&..&/span&&span class=&n&&ModInfoname&/span&&span class=&p&&(&/span&&span class=&n&&mod&/span&&span class=&p&&.&/span&&span class=&n&&modname&/span&&span class=&p&&)&/span&&span class=&o&&..&/span&&span class=&s2&&&&/span&&span class=&s&&: &/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&o&&..&/span&&span class=&n&&r&/span&&span class=&p&&)&/span&
&span class=&n&&ModManager&/span&&span class=&p&&:&/span&&span class=&n&&RemoveBadMod&/span&&span class=&p&&(&/span&&span class=&n&&mod&/span&&span class=&p&&.&/span&&span class=&n&&modname&/span&&span class=&p&&,&/span&&span class=&n&&r&/span&&span class=&p&&)&/span&
&span class=&n&&ModManager&/span&&span class=&p&&:&/span&&span class=&n&&DisplayBadMods&/span&&span class=&p&&()&/span&
&span class=&k&&else&/span&
&span class=&k&&return&/span& &span class=&n&&r&/span&
&span class=&k&&end&/span&
&span class=&k&&end&/span&
&span class=&k&&end&/span&&span class=&p&&)&/span&
&span class=&k&&end&/span&
&/code&&/pre&&/div&&p&问题很明显,饥荒作者使用了旧的表示可变参数表的语法。在5.1以前,你可以使用arg来表示{...}这个表,arg[i]即可用于提取可变参数中的第i项。但是后来这个语法就被默认弃用掉了,仅保留一个宏可以开启这个兼容。LuaJIT则完全不兼容这个写法,通过仔细查看代码,它甚至删除了实现arg兼容所占用的mask bit而将这个bit用在了其他地方。&/p&&p&当时分析到这的时候,我觉得直接要求用户修改这个文件也不是什么难事,毕竟添加如下一行就可以解决问题:&/p&&div class=&highlight&&&pre&&code class=&language-lua&&&span&&/span&&span class=&kd&&local&/span& &span class=&n&&arg&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&o&&...&/span&&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&于是我写好了详细的说明,将程序及源码发布在了Github上,并且在贴吧开了贴收集用户反馈。&br&&/p&&br&&p&&b&0x08 冒烟的补丁&/b&&/p&&p&第一波的反馈喜忧参半,可喜的是有部分用户能成功安装补丁,并且说确实有明显的效果,特别是针对Shipwrecked DLC加上大量Mods,忧的是仍然有大量不能正确启动的bug,报错也是千奇百怪,甚至有大量连游戏本身启动什么也没看到就闪退的问题。&/p&&p&对我冲击比较大的是,修改源代码文件这个要求对于普通用户来说实在是太难了。很多用户找不到文件,不知道用什么工具打开,看不懂英文因而无从下手,打了中文标点也浑然不知。而且很多第三方MOD里也用了这个旧的arg语法,要想举一反三,从我给出的修改mods.lua的方案直接得出修正第三方mod中相应语法问题的玩家非常少——毕竟贴吧以娱乐为主,不像知乎会有很多程序员。这很难办。&/p&&p&怎么办呢,只能自己把这个兼容性补丁做了。&/p&&p&在研究了一下午luajit parser之后,我放弃了按照lua源码中相同的设计添加兼容的思路。一方面如上所述,没有可用的mask bit,想要跑起来需要增加对应FLAG变量的位宽;另一方面lua源码中这个功能是在VM中解释时实现的,而luajit没有解释器,它直接跑的是原生指令。而想看明白JIT COMPILER的实现机制并且从中精准地插入这个功能并非易事。&/p&&p&不过又看了一下午parser之后,发现其实还有一个简单的办法。那就是在检测到当前编译的函数是可变参数的时候,动态插入一句local arg = {...}。这样的话有两种做法:&/p&&p&1、检测源文件文本,作一个简单的处理,定位到函数定义的地方,然后插入一行。&/p&&p&2、直接在AST生成的时候插入语法结点。&/p&&p&方法1的难度是比较低的,但是也需要稍微作一点解析工作,比如把注释,字符串跳过,检测函数定义的语句之类的。比较容易想不周全而出错。&/p&&p&要想想周全,就得搞个简单的parser。直接按方法2借用luajit自己的parser是最好的选择。为了使探索更有目的,我编写了这样的一个函数:&/p&&div class=&highlight&&&pre&&code class=&language-lua&&&span&&/span&&span class=&k&&function&/span& &span class=&nf&&test&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span& &span class=&kd&&local&/span& &span class=&n&&arg&/span& &span class=&o&&=&/span& &span class=&p&&{&/span& &span class=&o&&...&/span& &span class=&p&&}&/span& &span class=&k&&end&/span&
&/code&&/pre&&/div&&p&然后跑起luajit来看看local arg = { ... }这句话究竟都会走哪些路径来生成AST。调试了一个小时之后,终于搞出来了。&/p&&p&打开lj_parse.c,定位到:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&parse_chunk&/span&&span class=&p&&(&/span&&span class=&n&&LexState&/span& &span class=&o&&*&/span&&span class=&n&&ls&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&kt&&int&/span& &span class=&n&&islast&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&n&&synlevel_begin&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span&
&span class=&n&&add_argstmt&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span& &span class=&c1&&// HERE!!!!!&/span&
&span class=&k&&while&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&islast&/span& &span class=&o&&&&&/span& &span class=&o&&!&/span&&span class=&n&&parse_isend&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&tok&/span&&span class=&p&&))&/span& &span class=&p&&{&/span&
&span class=&n&&islast&/span& &span class=&o&&=&/span& &span class=&n&&parse_stmt&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span&
&span class=&n&&lex_opt&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&,&/span& &span class=&sc&&';'&/span&&span class=&p&&);&/span&
&span class=&n&&lua_assert&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&framesize&/span& &span class=&o&&&=&/span& &span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span& &span class=&o&&&&&/span&
&span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span& &span class=&o&&&=&/span& &span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&nactvar&/span&&span class=&p&&);&/span&
&span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span& &span class=&o&&=&/span& &span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&nactvar&/span&&span class=&p&&;&/span&
&span class=&cm&&/* Free registers after each stmt. */&/span&
&span class=&p&&}&/span&
&span class=&n&&synlevel_end&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&在标记处加一行调用add_argstmt的语句,然后编写这个函数:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&add_argstmt&/span&&span class=&p&&(&/span&&span class=&n&&LexState&/span&&span class=&o&&*&/span& &span class=&n&&ls&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&n&&ExpDesc&/span& &span class=&n&&e&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&flags&/span& &span class=&o&&&&/span& &span class=&n&&PROTO_VARARG&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&var_new_lit&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&s&&&arg&&/span&&span class=&p&&);&/span&
&span class=&c1&&// nexps = expr_list(ls, &e);&/span&
&span class=&p&&{&/span&
&span class=&n&&synlevel_begin&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span&
&span class=&c1&&// expr_unop(ls, &e);&/span&
&span class=&p&&{&/span&
&span class=&c1&&// expr_simple(ls, v);&/span&
&span class=&p&&{&/span&
&span class=&c1&&// expr_table(ls, v);&/span&
&span class=&p&&{&/span&
&span class=&n&&ExpDesc&/span& &span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&val&/span&&span class=&p&&;&/span&
&span class=&n&&FuncState&/span& &span class=&o&&*&/span&&span class=&n&&fs&/span& &span class=&o&&=&/span& &span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&fs&/span&&span class=&p&&;&/span&
&span class=&n&&BCLine&/span& &span class=&n&&line&/span& &span class=&o&&=&/span& &span class=&n&&ls&/span&&span class=&o&&-&&/span&&span class=&n&&linenumber&/span&&span class=&p&&;&/span&
&span class=&n&&BCInsLine&/span& &span class=&o&&*&/span&&span class=&n&&ilp&/span&&span class=&p&&;&/span&
&span class=&n&&BCIns&/span& &span class=&o&&*&/span&&span class=&n&&ip&/span&&span class=&p&&;&/span&
&span class=&n&&ExpDesc&/span& &span class=&n&&en&/span&&span class=&p&&;&/span&
&span class=&n&&BCReg&/span& &span class=&n&&base&/span&&span class=&p&&;&/span&
&span class=&n&&GCtab&/span& &span class=&o&&*&/span&&span class=&n&&t&/span& &span class=&o&&=&/span& &span class=&nb&&NULL&/span&&span class=&p&&;&/span&
&span class=&kt&&int&/span& &span class=&n&&vcall&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&n&&needarr&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&n&&fixt&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&kt&&uint32_t&/span& &span class=&n&&narr&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&cm&&/* First array index. */&/span&
&span class=&kt&&uint32_t&/span& &span class=&n&&nhash&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&cm&&/* Number of hash entries. */&/span&
&span class=&n&&BCReg&/span& &span class=&n&&freg&/span& &span class=&o&&=&/span& &span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span&&span class=&p&&;&/span&
&span class=&n&&BCPos&/span& &span class=&n&&pc&/span& &span class=&o&&=&/span& &span class=&n&&bcemit_AD&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&n&&BC_TNEW&/span&&span class=&p&&,&/span& &span class=&n&&freg&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&n&&expr_init&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&e&/span&&span class=&p&&,&/span& &span class=&n&&VNONRELOC&/span&&span class=&p&&,&/span& &span class=&n&&freg&/span&&span class=&p&&);&/span&
&span class=&n&&bcreg_reserve&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span&
&span class=&n&&freg&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&n&&vcall&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&n&&expr_init&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&VKNUM&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&n&&setintV&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&key&/span&&span class=&p&&.&/span&&span class=&n&&u&/span&&span class=&p&&.&/span&&span class=&n&&nval&/span&&span class=&p&&,&/span& &span class=&p&&(&/span&&span class=&kt&&int&/span&&span class=&p&&)&/span&&span class=&n&&narr&/span&&span class=&p&&);&/span&
&span class=&n&&narr&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&n&&needarr&/span& &span class=&o&&=&/span& &span class=&n&&vcall&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&c1&&// expr(ls, &val);&/span&
&span class=&p&&{&/span&
&span class=&n&&checkcond&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&,&/span& &span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&flags&/span& &span class=&o&&&&/span& &span class=&n&&PROTO_VARARG&/span&&span class=&p&&,&/span& &span class=&n&&LJ_ERR_XDOTS&/span&&span class=&p&&);&/span&
&span class=&n&&bcreg_reserve&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span&
&span class=&n&&base&/span& &span class=&o&&=&/span& &span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&n&&expr_init&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&val&/span&&span class=&p&&,&/span& &span class=&n&&VCALL&/span&&span class=&p&&,&/span& &span class=&n&&bcemit_ABC&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&n&&BC_VARG&/span&&span class=&p&&,&/span& &span class=&n&&base&/span&&span class=&p&&,&/span& &span class=&mi&&2&/span&&span class=&p&&,&/span& &span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&numparams&/span&&span class=&p&&));&/span&
&span class=&n&&val&/span&&span class=&p&&.&/span&&span class=&n&&u&/span&&span class=&p&&.&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&aux&/span& &span class=&o&&=&/span& &span class=&n&&base&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&expr_isk&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&key&/span&&span class=&p&&))&/span& &span class=&n&&expr_index&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&e&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&key&/span&&span class=&p&&);&/span&
&span class=&n&&bcemit_store&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&e&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&val&/span&&span class=&p&&);&/span&
&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&freereg&/span& &span class=&o&&=&/span& &span class=&n&&freg&/span&&span class=&p&&;&/span&
&span class=&n&&ilp&/span& &span class=&o&&=&/span& &span class=&o&&&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&bcbase&/span&&span class=&p&&[&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&pc&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&];&/span&
&span class=&n&&expr_init&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&en&/span&&span class=&p&&,&/span& &span class=&n&&VKNUM&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&n&&en&/span&&span class=&p&&.&/span&&span class=&n&&u&/span&&span class=&p&&.&/span&&span class=&n&&nval&/span&&span class=&p&&.&/span&&span class=&n&&u32&/span&&span class=&p&&.&/span&&span class=&n&&lo&/span& &span class=&o&&=&/span& &span class=&n&&narr&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&n&&en&/span&&span class=&p&&.&/span&&span class=&n&&u&/span&&span class=&p&&.&/span&&span class=&n&&nval&/span&&span class=&p&&.&/span&&span class=&n&&u32&/span&&span class=&p&&.&/span&&span class=&n&&hi&/span& &span class=&o&&=&/span& &span class=&mh&&0x&/span&&span class=&p&&;&/span&
&span class=&cm&&/* Biased integer to avoid denormals. */&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&narr&/span& &span class=&o&&&&/span& &span class=&mi&&256&/span&&span class=&p&&)&/span& &span class=&p&&{&/span& &span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&pc&/span&&span class=&o&&--&/span&&span class=&p&&;&/span& &span class=&n&&ilp&/span&&span class=&o&&--&/span&&span class=&p&&;&/span& &span class=&p&&}&/span&
&span class=&n&&ilp&/span&&span class=&o&&-&&/span&&span class=&n&&ins&/span& &span class=&o&&=&/span& &span class=&n&&BCINS_AD&/span&&span class=&p&&(&/span&&span class=&n&&BC_TSETM&/span&&span class=&p&&,&/span& &span class=&n&&freg&/span&&span class=&p&&,&/span& &span class=&n&&const_num&/span&&span class=&p&&(&/span&&span class=&n&&fs&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&en&/span&&span class=&p&&));&/span&
&span class=&n&&setbc_b&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&ilp&/span&&span class=&p&&[&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&].&/span&&span class=&n&&ins&/span&&span class=&p&&,&/span& &span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&n&&e&/span&&span class=&p&&.&/span&&span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&n&&VNONRELOC&/span&&span class=&p&&;&/span&
&span class=&cm&&/* May have been changed by expr_index. */&/span&
&span class=&n&&ip&/span& &span class=&o&&=&/span& &span class=&o&&&&/span&&span class=&n&&fs&/span&&span class=&o&&-&&/span&&span class=&n&&bcbase&/span&&span class=&p&&[&/span&&span class=&n&&pc&/span&&span class=&p&&].&/span&&span class=&n&&ins&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&needarr&/span&&span class=&p&&)&/span& &span class=&n&&narr&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&narr&/span& &span class=&o&&&&/span& &span class=&mi&&3&/span&&span class=&p&&)&/span& &span class=&n&&narr&/span& &span class=&o&&=&/span& &span class=&mi&&3&/span&&span class=&p&&;&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&narr&/span& &span class=&o&&&&/span& &span class=&mh&&0x7ff&/span&&span class=&p&&)&/span& &span class=&n&&narr&/span& &span class=&o&&=&/span& &span class=&mh&&0x7ff&/span&&span class=&p&&;&/span&
&span class=&n&&setbc_d&/span&&span class=&p&&(&/span&&span class=&n&&ip&/span&&span class=&p&&,&/span& &span class=&n&&narr&/span&&span class=&o&&|&/span&&span class=&p&&(&/span&&span class=&n&&hsize2hbits&/span&&span class=&p&&(&/span&&span class=&n&&nhash&/span&&span class=&p&&)&/span&&span class=&o&&&&&/span&&span class=&mi&&11&/span&&span class=&p&&));&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&n&&synlevel_end&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&n&&assign_adjust&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&e&/span&&span class=&p&&);&/span&
&span class=&n&&var_add&/span&&span class=&p&&(&/span&&span class=&n&&ls&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&上面的代码是按粗略的执行路径搞出来的,可能有些判断不会触发,还可以更简短些。不过影响不大就不深究了。&/p&&p&重新编译luajit,这次启动成功,MOD也能启用了。&/p&&br&&p&这里说个好玩的,其实饥荒代码中这样不经声明直接用arg的地方还真不多。大部分都是直接用了...来传递,少部分呢,其实是这样的(为了提取指定参数,很明显他不知道有select这个函数可以用):(modutil.lua)&/p&&div class=&highlight&&&pre&&code class=&language-lua&&&span&&/span&&span class=&n&&env&/span&&span class=&p&&.&/span&&span class=&n&&AddLevel&/span& &span class=&o&&=&/span& &span class=&k&&function&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&n&&arg&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&o&&...&/span&&span class=&p&&}&/span&
&span class=&n&&initprint&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&AddLevel&&/span&&span class=&p&&,&/span& &span class=&n&&arg&/span&&span class=&p&&[&/span&&span class=&mi&&1&/span&&span class=&p&&],&/span& &span class=&n&&arg&/span&&span class=&p&&[&/span&&span class=&mi&&2&/span&&span class=&p&&].&/span&&span class=&n&&id&/span&&span class=&p&&)&/span&
&span class=&nb&&require&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&map/levels&&/span&&span class=&p&&)&/span&
&span class=&n&&AddLevel&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&k&&end&/span&
&span class=&n&&env&/span&&span class=&p&&.&/span&&span class=&n&&AddTask&/span& &span class=&o&&=&/span& &span class=&k&&function&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&n&&arg&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&o&&...&/span&&span class=&p&&}&/span&
&span class=&n&&initprint&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&AddTask&&/span&&span class=&p&&,&/span& &span class=&n&&arg&/span&&span class=&p&&[&/span&&span class=&mi&&1&/span&&span class=&p&&])&/span&
&span class=&nb&&require&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&map/tasks&&/span&&span class=&p&&)&/span&
&span class=&n&&AddTask&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&k&&end&/span&
&span class=&n&&env&/span&&span class=&p&&.&/span&&span class=&n&&AddRoom&/span& &span class=&o&&=&/span& &span class=&k&&function&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&n&&arg&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&o&&...&/span&&span class=&p&&}&/span&
&span class=&n&&initprint&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&AddRoom&&/span&&span class=&p&&,&/span& &span class=&n&&arg&/span&&span class=&p&&[&/span&&span class=&mi&&1&/span&&span class=&p&&])&/span&
&span class=&nb&&require&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&s&&map/rooms&&/span&&span class=&p&&)&/span&
&span class=&n&&AddRoom&/span&&span class=&p&&(&/span&&span class=&o&&...&/span&&span class=&p&&)&/span&
&span class=&k&&end&/span&
&/code&&/pre&&/div&&p&(然后这句arg = { ... } 实际声明/修改了个全局变量arg。)&/p&&p&那为什么mods.lua中不用...来传递呢?原因很可能是,...不能穿过闭包的边界(即调用xpcall时的作为参数的匿名函数)成为upvalue,只有兼容版本的arg可以。开发者没办法只能用了arg,但是忘记声明local arg = { ... }了。&/p&&p&接下来由于兼容模式是开着的,这个小问题不会引起执行异常,所以这样的代码也就保留下来了。(我乱猜的)&/p&&br&&br&&p&&b&0x09 请写规范字&/b&&/p&&p&接下来来看玩家反馈的崩溃问题,发现很多都似乎是字符串上的乱子,有的案例会出现饥荒自带的崩溃界面,有的则直接闪退。&/p&&p&有崩溃界面长这个样子:&/p&&p&&figure&&img src=&https://pic2.zhimg.com/21f8b12a9ca5c2ea44dec_b.jpg& data-rawheight=&728& data-rawwidth=&1366& class=&origin_image zh-lightbox-thumb& width=&1366& data-original=&https://pic2.zhimg.com/21f8b12a9ca5c2ea44dec_r.jpg&&&/figure&虽然上面显示是在原版的饥荒脚本里出的错,但是实际上,引发出错的是一个旧版的汉化包。它汉化后的字符串是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&#: STRINGS.MODS.VERSIONING.OUT_OF_DATE&/span&
msgid &span class=&s2&&&Mod \&%s\& is out of date. The server needs to get the latest version from the Steam Workshop so other users can join.&&/span&
msgstr &span class=&s2&&&Mod\“% \”有更新,服务器需要从创意工坊获得最新版本,以便其他用户加入。&&/span&
&/code&&/pre&&/div&&p&虽然lua中字符串的转义符方案和C的基本一致,但是MODs以及汉化的作者往往没有C语言相关的经验,所以容易写错。上面代码中不应该转义的中文引号被加了反斜杠,同时格式占位符的%s中的s也忘记写了。&/p&&p&还有一些MOD中大量用单个反斜杠来表示反斜杠本身而并没有适当的转义。但是原版的lua 5.1.4 编译器会忽略这个错误。从lua官方的文档上来看,并没有规定如果用户提供了不合语法的

我要回帖

更多关于 饥荒联机版人物mod 的文章

 

随机推荐