最近在玩泰拉瑞亚,感觉钓鱼是一件麻烦事情,鼠标点烂还贼累。搜了半天大多都是点击脚本隔段时间自动收放,这里有个坑,我用python写过的一个自动点击脚本在这里不好使了,鼠标点击不了。在贴吧上可以看到一个老哥换成了按键实现,我没有去尝试,这么感觉用着总是很不爽,效率还低。所以就想从游戏本身出发看看能不能做到自动钓鱼,这篇文章主要是记录一下收获。因为都是自己摸索的,很多东西零零散散,也希望对入门的mod制作者有一点小小的帮助。
思路
游戏是使用的C#编写的,单机游戏没有乱七八糟的保护,可以直接反编译。工具主要是使用了vs测试代码,最新版的dnspy调试修改,注意一定要用最新版的,之前老版本总是出现各种奇怪的错误,不得不说这真是一个好东西。
初步打算是找到检测鱼上钩的代码,也就是上钩的时候会有波波的声音那种,然后调用收绳放绳相关的函数。
实践
游戏文件在Steam\steamapps\common\Terraria,打开dnspy搜索fish方法,然后就是凭借经验+下断点可以定位到FishingCheck这个函数,鱼上钩的时候会调用这个函数。
然后又是一番经验搜索,搜bait定位到ItemCheck_CheckFishingBobber_PickAndConsumeBait,鼠标点击收杆的时候会调用这里。原本是打算全部走游戏内部,但仔细想了想这个函数可能并不是顶层的调用,贸然使用可能会出现大问题。
所以我又想着简化一点吧,经过FishingCheck的时候直接调用windows的mouse_event,自动收杆后放杆。这个函数声明很简单:
VOID mouse_event(
DWORD dwFlags, // motion and click options
DWORD dx, // horizontal position or change
DWORD dy, // vertical position or change
DWORD dwData, // wheel movement
ULONG_PTR dwExtraInfo // application-defined information
);
照着文档直接使用就可以,右键FishingCheck修改方法把下面几句填进去。
[System.Runtime.InteropServices.DllImport("user32")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
mouse_event(2, 0, 0, 0, 0);//按下左键
mouse_event(4, 0, 0, 0, 0);//松开左键
这里我又遇到了之前用python写的脚本一样的问题,就是脚本在游戏里面没有反应,在外面就有效果,我思考了很久,按道理来说这个游戏是没有检测之类的,莫名其妙就失效了,因为之前mc一直用的就是这个脚本。在google上搜有国外老哥说可能是mouse_event的api失效,建议换成sendinput,然后我又鼓捣了一段时间,这段代码我就不贴了,因为也没有效果。
经过分析,我觉得问题出在游戏的输入接收上,之后尝试单句按下左键在游戏之中是有效果的,而两句连在一起就不行了,估计游戏输入必须要达到press的效果。于是我在两句中间穿插了Thread.Sleep(100),结果是成功的。
而这填进游戏里又出现了新的问题,因为sleep函数会阻塞当前线程,所以直接加进去依旧是没用,之后继续添加了一个检测线程并且完善了一下。
完善的代码
需要达成的目标:全局设置一个线程执行DoFish函数循环检测用于收杆放杆,FishingCheck检测到有鱼上钩,就调用DoFish。
右键Projectile创建1个方法,创建2个字段,勾选static,达到全局效果。
public static bool fishFlag = false; //钓鱼标志变量,每次检测到上钩置为true
public static bool createdThread = false;//线程标志,创建完线程后置为true
public void FishingCheck()
{
......
if (this.bobber && this.Name == "浮标")//避免产生错误,对当前状态进行校验
{
if (!Projectile.createdThread) //创建线程
{
Thread thread = new Thread(new ThreadStart(this.DoFish));
Projectile.createdThread = true;
thread.Start();
}
Projectile.fishFalg = true; //设置钓鱼标志位
}
}
public void DoFish()
{
for (;;)
{
if (Projectile.fishFlag)
{
//收杆
Projectile.mouse_event(2, 0, 0, 0, 0);
Thread.Sleep(100);
Projectile.mouse_event(4, 0, 0, 0, 0);
Thread.Sleep(100);
//下杆
Projectile.mouse_event(2, 0, 0, 0, 0);
Thread.Sleep(100);
Projectile.mouse_event(4, 0, 0, 0, 0);
Thread.Sleep(100);
//清除标志位
Projectile.fishFlag = false;
}
}
}
效果
将鼠标对准水坑,左键之后就可以挂机了,完美。之后也可以修改其他反人类的地方,比如物品选择栏滚轮方向问题,有的武器要左键一直点而不能够像镐子一样按着不动就行。我就没有时间继续研究了。
最后这是我的成品,想使用的可以直接放在泰拉瑞亚的文件夹下面打开即可,我的版本号是1.4.2.2,一定不要搞错了,还有,因为时间匆忙,我不保证没有什么bug,修改游戏才是我的乐趣,建议先备份一下自己的存档。
https://wwr.lanzouj.com/imvfdoexgcj
密码:7khj