传奇广告查询第一站 同步54.com

Qt写游戏脚本/辅助(仅供参考)
原创 于2026-01-05 18:07:00发布
26 阅读
0
0

写游戏脚本/辅助的背景

去年找了一款传奇游戏玩,后续发现现在的传奇游戏都是氪金为主,除了活动时间以外大家都是挂机刷混沌神石,然后再通过混沌神石换灵符,灵符又是零氪党快速提升实力的唯一绝经,后面就萌生了用脚本来刷混沌神石的想法。然后就通过“按键精灵”写了一个自动挂机(切图)刷混沌神石的脚本。随着时间的推移,后面又陆陆续续增加了功能,比如固定时间的活动(魔龙宝藏,世界BOSS,行会试炼等)。也用了很长一段时间,中途还在游戏里面跟别人吵架了,被别人开着榜一的号连续24小时追杀了好长一段时间,因为挂机的时候被杀的话就一直躺着,如果是晚上睡觉之后被别人杀了就很伤...然后就继续优化脚本,增加角色死亡检测和死亡自动复活等功能。总之在游戏里面通过脚本跟别人各种斗智斗勇,但是随着时间的推移,游戏里面增加的地图也越来越多,需要用到脚本做的事情也越来越多。最主要是把脚本给别人用,同时还要控制辅助的使用时间(过期不给用)。。。越到后面越发觉得用“按键精灵”写的脚本性能和UI界面(UI界面固定大小,放不下太多东西)不够用,然后今年就用Qt重构了脚本,把脚本的功能都通过Qt来实现。

一、用Qt写游戏脚本/辅助的前提准备工作

1. 通过Qt界面来配置游戏参数

毕竟辅助是给别人(小白)使用的,所以界面是必须要有的,用Qt写界面这是基本操作

2. 对游戏窗口实现鼠标点击操作

对游戏窗口实现鼠标点击操作最简单的是在屏幕对应的坐标点击鼠标左键/右键。但是大部分玩家都是游戏双开甚至多开,所以就不能直接点击屏幕,而是要实现后台操作(毕竟不可能每个窗口要操作的时候都临时切换到顶层来点击屏幕)。后台操作游戏窗口就离不开窗口句柄,游戏多开的情况下需要精准找到各个游戏的窗口句柄(精准区分大小号),再通过游戏窗口句柄实现相对坐标系统的鼠标点击。

3. 对游戏窗口实现按键(键盘)操作

找到窗口句柄后,再通过游戏窗口句柄实现对窗口的按键操作

4. 对游戏窗口进行监测

对游戏窗口的数据进行检测和分析,比如人物死亡检测,通常是检测人物血条,也就是对某一坐标的颜色进行抓取和判断。还有就是活动期间的检测,比如某一时间段到活动了,简单一点来就是获取电脑本地时间。

5. 对辅助的时间控制

辅助毕竟是给别人用的,如何实现对辅助的时间控制,比如过期后就用不了。最简单的就是设置一个日期,每次运行辅助的时候检测本地时间,到期后就不能用。但是这个有一弊端,电脑本地时间是可以调准的。那就得获取网络时间,并且还要能动态控制时间,比如上服务器动态给辅助设置有效期。还有就是如何精准知道是哪一个用户等。。。

二、用Qt写游戏辅助的实现

1. 辅助UI界面的实现

2. 找到游戏的所有窗口句柄

找到所有窗口句柄

 // 枚举所有顶层窗口 EnumWindows(EnumWindowsProc, 0);

筛选需要的游戏窗口句柄,并且放到list中

 // 枚举顶层窗口的回调函数 BOOL CALLBACK Widget::EnumWindowsProc(HWND hwnd, LPARAM lParam) { // 获取窗口标题 int length = GetWindowTextLength(hwnd); if (length > 0) { TCHAR *buffer = new TCHAR[length + 1]; GetWindowText(hwnd, buffer, length + 1); QString windowTitle = QString::fromWCharArray(buffer); delete[] buffer; if (windowTitle.startsWith("霸者xx")) { qDebug() << "hwnd:" << hwnd << ", title:" << windowTitle; // 将匹配到的窗口句柄放到列表中 hwndList.append(hwnd); // 根据窗口句柄截取一片区域(游戏等级)放入列表中,便于用户区分大小号(用户选中某一窗口句柄时显示对应游戏等级) hwndNameList.append(captureHiddenWindow(hwnd)); } } return TRUE; } 

截取游戏窗口一片区域(游戏等级区域),和窗口句柄绑定,给用户区分大小号用。

 QPixmap Widget::captureHiddenWindow(HWND hwnd) { if (!hwnd) { qDebug() << "找不到窗口!"; return QPixmap(); } RECT rect; if (!GetWindowRect(hwnd, &rect)) { qDebug() << "获取窗口矩形失败!"; return QPixmap(); } int width = rect.right - rect.left; int height = rect.bottom - rect.top; HDC hdcScreen = GetDC(hwnd); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height); SelectObject(hdcMem, hBitmap); // 使用 PrintWindow 输出被遮挡部分 if (!PrintWindow(hwnd, hdcMem, PW_RENDERFULLCONTENT)) { qDebug() << "PrintWindow 失败!"; DeleteObject(hBitmap); DeleteDC(hdcMem); ReleaseDC(hwnd, hdcScreen); return QPixmap(); } // 将 HBITMAP 转换为 QImage BITMAP bmp; GetObject(hBitmap, sizeof(BITMAP), &bmp); QImage img(width, height, QImage::Format_RGB32); BITMAPINFOHEADER bi; ZeroMemory(&bi, sizeof(BITMAPINFOHEADER)); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = width; bi.biHeight = -height; // 负数表示从顶向下存储 bi.biPlanes = 1; bi.biBitCount = 32; bi.biCompression = BI_RGB; GetDIBits(hdcMem, hBitmap, 0, height, img.bits(), (BITMAPINFO*)&bi, DIB_RGB_COLORS); QPixmap pixmap = QPixmap::fromImage(img); //pixmap.save("screenshot.png"); //qDebug() << "截图完成,保存为 screenshot.png"; DeleteObject(hBitmap); DeleteDC(hdcMem); ReleaseDC(hwnd, hdcScreen); // 定义要截取的区域,win10和win11窗口有细微区别 int y; if (QSysInfo::productVersion().toInt() < 11) { //win 10及以下 y = 935; } else { //win 11 y = 928; } QRect qrect(1390, y, 100, 25); return pixmap.copy(qrect); }

3. 通过窗口句柄实现后台鼠标点击

 //后台点击 void Worker::backgroundClick(MyPoint point) { if (!IsWindow(hwnd)) { qDebug() << "backgroundClick: 窗口不存在"; return; } LPARAM lParam = MAKELPARAM(point.getX(), point.getY()); PostMessage(hwnd, WM_MOUSEMOVE, 0, lParam); PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, lParam); PostMessage(hwnd, WM_LBUTTONUP, 0, lParam); }

4. 通过窗口句柄实现后台按键操作

 //后台按键 void Worker::backgroundKeyPress(int keyCode) { if (!IsWindow(hwnd)) { qDebug() << "backgroundKeyPress: 窗口不存在"; return; } DWORD dwVKFkeydata; //lParam 参数值 WORD dwScanCode = MapVirtualKey(keyCode, MAPVK_VK_TO_VSC); dwVKFkeydata = 1; dwVKFkeydata |= dwScanCode << 16; dwVKFkeydata |= 0 << 24; dwVKFkeydata |= 1 << 29; PostMessage(hwnd, WM_KEYDOWN, keyCode, dwVKFkeydata); dwVKFkeydata = 1; dwVKFkeydata |= dwScanCode << 16; dwVKFkeydata |= 0 << 24; dwVKFkeydata |= 1 << 29; dwVKFkeydata |= 3 << 30; PostMessage(hwnd, WM_KEYUP, keyCode, dwVKFkeydata); }

5. 通过窗口句柄检测目标坐标点的颜色

 /** * @brief checkPixelColor 根据窗口句柄检查某一坐标是否是某颜色 * @param hwnd 窗口句柄 * @param point 检查的坐标 * @param color 目标颜色 * @return */ bool Widget::checkPixelColor(HWND hwnd, QPoint point, QColor color) { if (!IsWindow(hwnd)) { qDebug() << "窗口不存在"; return false; } //获取窗口上下文 HDC hdc = GetDC(hwnd); if (hdc == NULL) { qDebug() << "hdc获取失败"; return false; } COLORREF colorREF = GetPixel(hdc, point.x(), point.y()); //释放窗口上下文 ReleaseDC(hwnd, hdc); unsigned char red = GetRValue(colorREF); unsigned char geen = GetGValue(colorREF); unsigned char blue = GetBValue(colorREF); qDebug() << "R:" << red << ", G:" << geen << ", B:" << blue; if ((red > color.red() - 5 && red < color.red() + 5) && (geen > color.green() - 5 && geen < color.green() + 5) && (blue > color.blue() - 5 && blue < color.blue() + 5)) { return true; } return false; }

三、后话

自己写的辅助给别人用的话,如果还需要控制辅助使用时间,最好是能有一个服务器。没有服务器也能实现,比如自己在某个网页写了一篇文章,在这篇文章里面按一定的格式写上时间,然后辅助启动的时候去访问这个文章的链接,并且获取到所有内容,并且提取出对应格式的内容,然后进行对比时间是否过期...要更新辅助的使用时间那就更新一下文章(修改一下里面的时间)。。。

管理员
0
0
0
分享
上一篇: 为gee引擎开发一个任务脚本,思路整理设计
下一篇: 挂机脚本_【脚本】假人自动挂机脚本GOM引擎传奇版本
评论
历史记录
回顶部
浏览时间 游戏名称 游戏IP 开区网址
注册GM1论坛账号
  • 上传头像
注册

已有账号,

微信扫码登录
重置密码
重置密码

注册

绑定关联手机号
关联手机号