当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

传奇游戏脚本开发入门:从图色模拟到自动化逻辑构建实操

热度:
一、图色模拟的底层原理与调用链路

图色脚本不读游戏内存,只截取屏幕像素矩阵做特征匹配。核心流程:GDI/DX截图→颜色提取→区域比对→键鼠注入。传奇客户端窗口类名通常为TForm1或传奇自定义类,用WindowsAPIFindWindow获取窗口句柄后,GetDC抓前台图;DirectX模式需用DXHook或PrintWindow绕过重绘拦截。

颜色特征提取:传奇界面固定色值多,比如土城安全区地面主色BGR(789452),红药图标角点BGR(3636196)。用GetPixel(hdcxy)单点取色慢,实际用GetDIBits批量读位图数据进BYTE数组,逐行扫描。特征匹配分两种:单点锚定(一个坐标一个色值)和多点阵列(5-8个坐标同时比对,容差±5色阶)。多点阵列防误判率远高于单点,比如区分金创药和强效金创药靠图标右上角高光点色值差异。

键鼠注入走PostMessage/SendMessage发WM_LBUTTONDOWN/WM_LBUTTONUP模拟点击,SendMessage发WM_KEYDOWN/WM_KEYUP模拟按键。直接调mouse_event是全局注入,切窗口就断,必须用窗口消息级注入才能后台运行。

二、内存读值的接口与结构体定位

图色上限是肉眼速度,内存读值直接拿角色坐标、血量、背包列表。核心API:OpenProcess(PROCESS_ALL_ACCESSFALSEpid)拿进程句柄→ReadProcessMemory读内存。难点是找基址偏移链。

传奇角色属性基址定位路径(以老版M2客户端为例):用CE(CheatEngine)搜当前血量整数→回到游戏掉血再搜变化值→锁定血量地址→查什么访问了这个地址→找到汇编指令MOVEAX[ESI+0xDC]→ESI来自[EBX+0x08]→EBX来自全局基址0x0045A000。最终偏移链:[[[0x0045A000]+0x08]+0xDC]=当前血量。同理HPMax在+0xE0,MP在+0xE4,X坐标在+0x24(WORD),Y坐标在+0x26(WORD),地图编号在+0x30(DWORD)。

背包物品遍历:背包数组基址[[[0x0045A000]+0x10]+0x04],每个物品槽0x1C字节步进,偏移+0x00为物品ID(WORD),+0x04为数量(WORD),+0x08为耐久(WORD)。遍历到ID=0即为空槽。内存读值比图色快100倍以上,且不依赖分辨率、界面缩放、主题皮肤。

三、封包截取与协议解析

图色和内存都受窗口和进程限制,封包直接构造TCP数据流发给GameGate,等于自己写了一个无窗口客户端。工具用WPEPro或自制DLL注入ws2_32.dll的send/recv函数挂钩。

传奇协议头固定2字节长度+1字节命令字+N字节数据。常用命令字:0x10=登录账号,0x11=登录角色,0x12=行走,0x13=跑步,0x14=攻击,0x20=说话,0x30=捡物,0x31=丢弃,0x32=使用物品。行走包结构:长度(2)+0x12+X(WORD)+Y(WORD)+方向(BYTE)。跑步包:长度(2)+0x13+X(WORD)+Y(WORD)+方向(BYTE)。攻击包:长度(2)+0x14+目标ID(DWORD)+技能ID(BYTE)。

封包发送用WSASend直接往GameGate的TCP连接写数据,绕过客户端所有校验。但M2有包频率限制(每秒最多10个移动包),超速直接踢线。封包脚本必须加定时器控制发包间隔100ms以上。

四、自动化逻辑构建的分层架构

脚本逻辑分三层:感知层(获取状态)→决策层(判断做什么)→执行层(发指令)。以自动打怪脚本为例:

感知层:读内存拿当前HP/MP、X/Y、周围怪物列表(怪物数组基址[[[0x0045A000]+0x14]+0x00],每个怪物结构0x40字节,+0x00=怪物ID,+0x04=X,+0x06=Y,+0x08=当前HP,+0x0C=最大HP)。过滤条件:距离≤视野范围(默认9格)、HP>0、非友方(通过名称颜色判断,名称字符串在+0x20偏移)。

决策层:ifHP<HPMax*0.3→执行喝药/回城;elseif周围有怪→选最近怪物执行攻击;else→沿路径点移动到下一个挂机点。攻击方式选择:近战怪贴脸发0x14攻击包;远程怪保持2-3格距离用技能包(0x15+技能ID+目标X+目标Y)。

执行层:发攻击包后Sleep(800)等动画硬直结束再发下一个;喝药走使用物品包0x32+物品槽位(BYTE);回城读回城卷轴坐标发使用包后等3秒传送读条。

五、定时循环与状态机设计

脚本主循环用while(1)或SetTimer定时器,周期100-200ms扫一次状态。纯while(1)占满单核CPU,必须Sleep(100)让出时间片。状态机用enum定义:IDLE(待机)→WALKING(移动中)→FIGHTING(战斗中)→HEALING(回血)→BACKTOWN(回城)→DEAD(死亡等待复活)。每个状态对应一个处理函数,主循环根据当前状态调用对应函数,函数返回下一个状态。这样比if-else嵌套清晰,且方便加新行为(如捡物、交易)而不破坏整体结构。

六、多开同步与窗口管理

多开传奇客户端每个窗口独立进程,用EnumWindows枚举所有窗口标题含"传奇"的HWND,用GetWindowThreadProcessId拿到每个窗口的pid,分别OpenProcess拿句柄。内存读值要每个pid单独开句柄;图色截图要每个HWND单独GetDC;封包要每个进程hook独立的ws2_32连接。多开同步逻辑:主窗口发指令(如"全体回城"),通过共享内存或命名管道广播给所有子脚本进程,子脚本收到后各自执行回城序列。

七、常见脚本故障定位

•图色点击偏移:窗口分辨率改了但脚本坐标没改,用GetClientRect动态获取窗口尺寸再按比例换算坐标。

•内存读值突然全0:客户端更新后基址偏移链变了,CE重新搜一遍,通常只有最后一级偏移会变(如+0xDC变+0xE0)。

•封包发过去没反应:包长度字段算错(长度不含自身2字节)、命令字版本不匹配(不同引擎命令字有差异)、GameGate校验序列号缺失。

•脚本跑一会角色不动:被M2踢下线(包频率超限或坐标跳变),加发包间隔和路径平滑处理。

•多开时某个窗口不响应:pid获取错乱,用GetWindowText校验窗口标题后再绑定。

八、脚本与引擎脚本的边界

上述是外部辅助脚本开发。传奇引擎内置TXT脚本(NPC对话/任务/爆率)和Lua脚本(996_24引擎等)是服务端侧逻辑,与外部脚本完全隔离。外部脚本只跟客户端进程交互,服务端脚本只控制M2行为。两者不能互相调用——外部脚本无法触发服务端的[@TakeOn17]标签,服务端脚本也无法读取外部脚本的内存数据。做自动化逻辑时要分清哪层该放客户端侧(移动、打怪、喝药),哪层该放服务端侧(任务判定、奖励发放、属性加成)。
[顶部]