首页 > 其他分享 >试着写一下MMORPG游戏游戏的自动挂机

试着写一下MMORPG游戏游戏的自动挂机

时间:2024-03-10 13:00:11浏览次数:25  
标签:processTable 游戏 index ui QString MMORPG Home 挂机 vecProcess

因为,视频里教到了植物大战僵尸的自动放置Call就结束了,所以暂且先跟着视频走。而视频就开始研究mmorpg游戏了。

所以我打算跟着视频走。而上个项目大体能够理解其实就是用CE找基址,然后通过代码注入的方式实行自动脚本之类的东东。

至于CE找基址OD找call这些设计经验的东西我会慢慢学习。先跟着视频走熟悉一下C++的语法,先了解一下mmo游戏的机制了。

我学习的视频是B站的,地址是:https://www.bilibili.com/video/BV1vy4y147s5/

总结一下吧。视频每一集大概都3个小时 建议汇编部分可以去别的UP主去看。。视频是2016年的了好像,虽然很老,但是老师讲的还是很细的。

我的汇编是在这里学习的,地址:https://www.bilibili.com/video/BV1Rs411c7HG 

这个怎么说呢,如果有编程基础的看的话,就不会那么乏味可以看得懂,但是如果一点编程基础都没有的话,我感觉会跟天书一样。

咋说呢3个小时的视频,虽然说长吧。但是贵在细致吧。。只不过乏味,属于网课系列,所有一些遇到的问题就需要自己找解答方法了。就比如我从MFC转到QT遇到的ATT汇编和Intel汇编。QString和CString ,QTimer 和Timer,和一些事件绑定都需要查百度。

但是也算是多学了知识吧。

对于没有基础来说,跳着看是看不懂的,所以快进看是错误的。。但是有些函数只是实现逻辑方法,逻辑无所谓,实现就好。这方面也就不需要看了。就比如说我这次贴出来的。如果自己可以看到最后可以实现是什么样的,那么则可以快进。

也不多说贴代码。

home.h

// home.h

#ifndef HOME_H
#define HOME_H
#include <QWidget>


QT_BEGIN_NAMESPACE
namespace Ui {
class Home;
}
QT_END_NAMESPACE

class Home : public QWidget
{
    Q_OBJECT

public:
    Home(QWidget *parent = nullptr);
    ~Home();

public: // 自己写的
    void initTableBox();    // 初始化进程表数据
    void getProcessList(QString strName ,QVector<QString>& vecProcess);   // 获取进程列表,把结果写在形参的第二个参数里
    void removeProcessTItem(QVector<QString> vecProcess);    //根据需要去除processTable中已经退出的进程
    int findProcess(QString pid );
    int findVecProcess(QString pid ,QVector<QString> vecProcess);
public:
    QTimer *tim;    //定义一个定时器
private slots:
    void realTimeMonitoringProcessTable();      // 用来做槽实时监控processTable像属性的东东

private:
    Ui::Home *ui;

};
#endif // HOME_H

home.cpp

// home.cpp

#include "home.h"
#include <windows.h>
#include <tlhelp32.h>
#include "ui_home.h"
#include <QMessageBox>
#include <QTimer>


Home::Home(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Home)
{
    ui->setupUi(this);

    initTableBox();  // 这个表格空间里写有进程列表的信息,这里设置他的默认数据。
    // 定义一个定时器 定义一个槽函数initTableBox对应他的信号timeout;其实按照js来说就是给他绑定一个事件
    // 用JS语言来理解他 就相当于定义了一个 setTimeout(() =>{ 我里面写了realTimeMonitoringProcessTable的代码。}) 唯一不同的是JS里有两个参数且只调用一次
    // 而这里time->setInterval(1000)的意思好像就和JS里setInterval差不多了结合后边的connect绑定槽和信号的关系,实现循环执行函数。大概吧,我是这么理解的
    tim = new QTimer;
    tim->setInterval(1000);
    connect(tim,SIGNAL(timeout()),this,SLOT(realTimeMonitoringProcessTable()));
    tim->start();
}

Home::~Home()
{
    delete ui;
}



// 默认进程表信息,自动调用
void Home::initTableBox(){
    QStringList headerText;
    headerText<< "进程ID" << "进程名称" << "游戏名";
    ui->processTable->setColumnCount(headerText.count());       // table列的数量与表头对其
    ui->processTable->setHorizontalHeaderLabels(headerText);    // 设置table表头

    ui->processTable->horizontalHeader()->setStyleSheet("QHeaderView::section{background:#F3F3F3;border:1px solid #CCCCCC; border-top:0px;}");     // 设置表头颜色
    ui->processTable->verticalHeader()->setHidden(true);        // 去除编号

    ui->processTable->setSelectionBehavior(QAbstractItemView::SelectRows); //设置选中状态为一整行
    ui->processTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);   // 设置自适应等宽
    ui->processTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive);   // 表示第0列可以手动设置,其他列自动分配宽度
    ui->processTable->setColumnWidth(0,80);     // 设置第一列宽度

}

// 根据进程名获取所有同名的进程列表,例如游戏多开,但进程名一样。要注入不同的进程
// 这里第二个参数,我理解的是地址传递,因为JS里没有所以我特地去查了查。可以百度上了解以下c++的指针。
// 简单的说就是,形参2 引用了 实参2的地址,修改他即修改了实参的值,不会C++的会云里雾里,我也是看了好久。所以这块还是建议找c++指针的资料看一下
void Home::getProcessList(QString strName ,QVector<QString>& vecProcess)
{
    // 创建一个快照
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);
    PROCESSENTRY32 pe32;//存放进程快照的结构体,和Process32First,Process32Next配合使用
    pe32.dwSize = sizeof(PROCESSENTRY32);
    BOOL bRet = Process32First(hSnapshot,&pe32);        //  Process32First用来获得进程快照的第一个进程
    // 每次进入这个函数,先清空原来旧的进程列表。然后将tableWidget的行数初始为0,如果不初始为0,他会一直增加原来的数据还会保留,不懂他什么机制,设置了就没事了。
    while (bRet) {
        QString strProcess = QString::fromWCharArray(pe32.szExeFile);       // wchar_t 转 QString
        strProcess.toLower();   //  因为进程名有大写小写。但是进程名并不区分大小写。所以统一转换为小写比较
        if(strProcess == strName){
            QString pid = QString::number(pe32.th32ProcessID);
            vecProcess.append(pid);
        }

        bRet = Process32Next(hSnapshot,&pe32);
    }
    CloseHandle(hSnapshot);     // 关闭句柄
}

void Home::realTimeMonitoringProcessTable(){
    QVector<QString> vecProcess;
    // 循环了进程快照,把需要的所有进程放到了vecProcess这个参数里
    getProcessList("mhmain.exe",vecProcess);
    // 循环需要的进程也就是vecProcess参数,把他的值打印在QTableWidget控件中,进程快照中的值不存在于QTableWidget中,才会向QTableWidget中写入项,否则不会写入
    for (int index = 0; index < vecProcess.size(); ++index) {
        QString pid = vecProcess[index];
        if(findProcess(pid) == -1){
            int row = ui->processTable->rowCount();
            ui->processTable->insertRow(row);
            ui->processTable->setItem(row,0,new QTableWidgetItem(pid));       // 获取进程ID
            ui->processTable->setItem(row,1,new QTableWidgetItem("mhmain.exe"));    // 进程名称
            ui->processTable->setItem(row,2,new QTableWidgetItem("暂无"));
        }
    }
    // 这会出现一种状况,未添加的进程可以实时添加,但是已退出的进程还在列表里,所以需要剔除他
    removeProcessTItem(vecProcess);
}


void Home::removeProcessTItem(QVector<QString> vecProcess){
    int totalRow = ui->processTable->rowCount();
    for (int index = 0; index < totalRow; ++index) {
        QString item_pid = ui->processTable->item(index,0)->text();
        if(findVecProcess(item_pid ,vecProcess) == -1){
            // 当进程已经不在了那么,在table中移除他
            ui->processTable->removeRow(index);
            // 这句很重要,是退出当前循环,大多数情况不退出也可以循环会继续循环,也就浪费资源而已,但是这里则不一样
            // ui->processTable->removeRow(index)会移除当前行,也就是移除第一行的时候 第二行会变成第一行。
            // 但如果循环不终止就会产生异常,这里假设数据有两条totalRow=2
            // 删除了之后当删除之后total还是等于2,但是此时的table里却只有一条数据了,假设我删除了下标为0的数据,那么此时0被删除,下标1变成了0,但是此时index变成了1
            // 所以当QString item_pid = ui->processTable->item(index,0)->text();再次调用的时候index是1。但是第1行已经变成了第0行,所以直接崩溃
            // 这里因为自己出现了这个错误,所以提醒一下
            break;
        }

    }
}

// 如果找到了返回该id所在行下表,如没找到返回-1,主要用来判断QTableWidget是否添加该项
int Home::findProcess(QString pid){
    int total = ui->processTable->rowCount();
    for (int i = 0; i < total; i++) {
        QString item_pid = ui->processTable->item(i,0)->text();
        if(pid == item_pid){
            return i;
        }
    }
    return -1;
}
// 在vecProcess数组里寻找Pid找不到返回-1找到了返回下标,主要用来判断是否进程已经消失所以要去除该进程所在的行。
int Home::findVecProcess(QString pid ,QVector<QString> vecProcess){
    for (int index = 0; index < vecProcess.size(); ++index) {
        if(pid == vecProcess[index]){
            return index;
        }
    }
    return -1;
}

这里的控件都是拖动的,所以直接粘贴代码还是不行的,需要有点QT的基础。。这个也简单。随便找个QT教程看3级 知道槽信号,怎么给button绑定事件就好了。

我就是这样,这次用到了QTableWidget , 所以在百度上搜一下怎么调用怎么遍历怎么赋值,怎么取值就好了。根本不需要去找个视频去重新走一边,那样很浪费事件。而且又不是找工作,实现就好。用到的时候在学,把痛苦留给明天

这里看一下程序暂时的样子吧。

这里大概就是这个样子。

学过前端框架 像VUE和react,dva之类的会觉得,这个玩意简直不要太简单。除了语法和某些逻辑来说。比他们方便的不要太多。

不多说了。总之以后的路线会跟各种学习视频走,等跟视频多了,在提升自己的逻辑思维,看了这么多 其实重要的并不是代码怎么写而是基址怎么找 call怎么找。这才是重要的。

所以找call的经验还是要学习。比如说FPS的自动瞄准。。是怎么做到的,LOL里的自动躲避技能又是怎么弄得。

加油~~~


标签:processTable,游戏,index,ui,QString,MMORPG,Home,挂机,vecProcess
From: https://www.cnblogs.com/dandingjun/p/18064014

相关文章

  • CTS2024 投票游戏
    首先手玩可以发现求出两人谁先被票出是困难的,但如果我们能求出两人各票出时的票数,那么只要比较一下票数的大小就可以直到票出的顺序,然而一个点的票数的大小与其子结点有关,如果我们能确定子结点最终票出时的票数,那么只要处理当且菊花图的一个问题即可,将子节点的最终票数从大到小排......
  • 原神游戏排行榜为什么超越了王者荣耀 ?
    《原神》游戏排行榜超越《王者荣耀》的现象,可能是由多个因素共同作用导致的。以下是一些可能的原因:全球化的影响:《原神》作为一款全球发行的游戏,其受众群体相对更广泛。与此同时,《王者荣耀》虽然在国内拥有庞大的用户基础,但在国际市场的推广和接受度上可能相对有限。因此,从全球范......
  • 8000MHz高频内存也赢不了AMD!锐龙7 7800X3D VS. i9-14900K网游与单机游戏性能对比
    一、前言:i9-14900K配8000MHz内存能否战胜锐龙77800X3D如今的Intel似乎有些魔怔,为了冲击高频而不顾一切。此前i9-14900K的满载功耗已经高达360W,而即将到来的i9-14900KS据闻峰值功耗已经超过400W,频率也来到了前所未有6.2GHz。与之形成强烈反差的是AMD的锐龙77800X3D,这款当前游戏......
  • 王者荣耀游戏需要用到哪些IT技术?
    《王者荣耀》作为一款备受欢迎的多人在线战术竞技游戏(Moba),其背后涉及了众多IT技术的运用。以下是一些关键的技术领域和具体的应用:游戏引擎:游戏引擎是开发游戏的核心工具。对于《王者荣耀》这样的3D游戏,通常会使用如Unity3D这样的游戏引擎。Unity3D提供了丰富的功能和工具,帮助开......
  • C语言0基础入门游戏辅助开发—学习笔记02
    C语言0基础入门游戏辅助开发—学习笔记02PS:这里仅作为本人学习过程中的随笔。数据类型、sizeof运算符数据类型数据类型是在关键字内的,或者说关键字包含数据类型。数据类型有哪些程序中的代码和数据都是以二进制的形式存储的,对计算机系统和硬件而言,数据类型的概念不存在,这......
  • 技术笔记(4)MMORPG开发
    技术笔记(4)MMORPG开发希望实现的功能或目标:框架搭建UI系统‍学习笔记:Rules文件夹CanGetLayersExtensionCanSendCommandExtensionEventExtensionIBelongToArchitectureICanGetModelICanGetSystemICanGetUtilityICanRegistAndUnRegistEventICanSendCommand......
  • 洛谷P4069 [SDOI2016] 游戏
    题目描述我们要操作的是一条在树上的路径\(s\)->\(t\)。(1)查询\(s\)->\(t\)最大的数字。(2)在\(s\)->\(t\)上增加一个数字,输入\(a\),\(b\),对于路径上的一个点\(u\)增加的数字是\(dis(s,u)\timesa+b\)。解题思路直接查询一条从\(s\)到\(t\)的路径是十分不方便的,所以我们......
  • c语言 推箱子小游戏二次开发
    内容来源:CSDN(额………………):https://blog.csdn.net/m0_71832999/article/details/128050830?ops_request_misc=&request_id=&biz_id=102&utm_term=c++推箱子小游戏&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-2-128050830.142v99pc_se......
  • 飞机大战小游戏改进与创新
    飞机大战小游戏来源:[https://github.com/WindrunnerMax/AirplaneWar]运行环境:visualstudio2019运行截图如下:对源文件的各项代码,我进行了一些修改和创新,Bomb.cpp文件中,我发现以下问题:魔法数值硬编码:在Draw函数中出现了数字12和10,应该将这些魔法数值定义成常量或者宏以提高......
  • C语言扫雷游戏
    在给出的代码中,使用了以下库来实现游戏功能和图形界面:graphics.h:这是一个基于BGI(BorlandGraphicsInterface)库的图形库,用于创建图形窗口、绘制图形等操作。stdlib.h:这是C标准库中的一个头文件,提供了一些常用函数,例如srand()和rand()用于生成随机数,NULL用于表示空指针。time.h:......