魔兽魔兽世界3.35机器人端人

后使用快捷导航没有帐号?
查看: 8971|回复: 23
有空一块吃河蟹
Lv.6, 积分 3815, 距离下一级还需 1185 积分
UID5030518帖子威望1 多玩草201 草
写在前面:
这是我在网上看到的最好的关于如何写一个游戏机器人的教程,不知有人翻译过没,反正我花了两天时间去翻译。分享给大家。
都看过黑客帝国吧,游戏的世界就像是矩阵,你是否想成为尼奥呢?
原文: [Guide] Howto make a Wow bot for complete newbs!
Hi! My name is Devon and I’m an alcoholic.
Actually I have about 10 days off work and my choices of entertainment wasdrinking my life away or writing an guide for complete newbs on how to make abot. So I decided to do both.
Moving on…
嗨,我叫Devon,是个酒鬼。实事上我有十天可以不去工作,我可以选择的娱乐是借酒消愁或写一个指南给那些想自己做个游戏机器人的新手。所以,我决定两个都做。开饭……
--Pre Introduction:--
I have spent a long timehopelessly searching the internet to learn everything I needed to know to makea bot. Well I failed miserably. But to my rescue came a kind person and helpedme in my adventure to the stars (or at least the addresses of world ofwarcraft). He not only spent his time helping me by showing me stuff in thecode I knew best but he also gave me great direction in where/what to search onthe forums . Because of him I have this knowledge. Thank you ^_^
(I do not know if hewants to be named or not.)
我曾经花费了很长时间非常苦逼的在网上搜索如何做一个游戏机器人。结果我可悲的失败了。但这时一个高手横空出世拯救了我并为我指出了一条璀璨的星光大道(至少是通往魔兽的道路)。他不仅教我如何用我最擅长的语言去做这件事,而且指导我如何如何有效的搜索论坛。因为他我才掌握了现在的知识。感谢他,?(不知他是否羞涩于将自己的名字公布出来)
--Introduction:--
Okay so many of younewbies (such as myself) are probably wondering “How the **** do I make a bot”.Well let me start out by saying, you need to know at least some sort ofcomputer language, whether it be C++, C#, Java, or the shit language I useAutoit (yeah, yeah …Scripting blah, blah, blah… Its shitty blah, blah,blah…Learn a real language blah, blah, blah. All in due time). If you do notknow a language then you will not understand this at all. So please go learn alanguage.
Okay, 很多新手(比如我)都曾经疑惑过“怎么他奶奶个甜甜圈的才能做一个游戏机器人呢?”。现在我来告诉你,你至少要懂一种计算机语言,不论哪种语言,C++、J***A、C#或者我用的狗屎语言Autoit(#此处为人们对这个脚本语言的轻蔑# 作者:老子没空学别的)。如果你一门语言都不会,那你肯定不会理解这篇文章。所以,赶快死开去补课。
On top of needing to knowa language, you need to have a function that can read memory addresses. Whetheryou make it yourself or not is up to you. 作为必要条件,你选择的语言要有一个函数可以直接读取计算机的内存,不论你找个现成函数的或你自己来编写。
One last thing, Ipersonally do not know everything as I have just started out. For example, I donot know very much about dlls, therefore I copy the memory function (fromnomadmemory.au3) and a “getwowbase” function provided by my dear ol’ champ Ispoke about in the Pre Introduction.
最后,我并不是一个专家,我也是刚刚开始。比如,我并没多少关于DLL的知识,所以我从nomadmemory.au3(Autoit脚本文件)直接复制了内存函数。Getwowbase这个函数是我前面提到的救星给我的。
Also, I will be usingAutoit seeing as it is the code I am currently most skilled in and it is afairly simple language so it should be simple enough to translate into yourpreferred code, but I will explain what is happening when necessary.
我将会用Autoit这个我最拿手而且非常简单的语言来展开这篇教程。相信你能非常容易的转换为你擅长的语言。关键点我将做一些必要的解释。
So let’s get down to it.终于可以坐下来开吃了。
--Analogy (sounds like a good time tome)/Terms:--
So …*Deep Breath*… We cancompare how we get info from World of Warcraft to our real world. Just like inreal life, where there are many objects and creatures, there are many objectsand creatures in Wow. We call these (because programmers aren’t creative)“WowObjects”.
So…*深呼吸*… 我们可以比较一下魔兽世界和我们真实的世界。就如我们真实的生活中一样,在魔兽世界中同样有许多物体和生物。我们权且统称为(程序员通常都是没想像力的)“WowObjects”.
So we say to ourselves wewant something from this world and we want to know a characteristic of this“something”. I would first need to know what kind of thing this something is.For example, is it a person or is it a table? Is it human or is it a dog or acat? Similar concept applies to Wow. We call this an “ObjectType”. Thereare 7 types of objects in Wow, listed below: 我们想从魔兽世界中得到某个对象并且得到这个对象的属性,首先我们要知道这个对象到底是个神马。比如神马到底是个人还是个桌子?是人类还是狗狗还是猫猫……?把这个概念引申到魔兽世界,我们称为”ObjectType(对象类型)”。WoW中主要有7种类型,如下:
Code:1 - Items2 - Contains3 - NPC's4 - Players5 - GameObjects (Nodes etc)6 - DynamicObjects (Spells and stuff)7 - Corpses
(Excellent guide. After you’re done, go check it out)(作者推荐的网文,E文)
After we find out ourtype of world object (say for example a human) how would we know which human itis seeing as there are billions in the world. Well, as I’m sure you alreadyknow, this is the reason people have names. So this means if we know a person’sname we can find even more details about that person. Names in Wowmemoryare called “GUIDs” (Globally Unique Id) which is in sense a tag to identify anobject.
当我们知道了一个对象的类型后(比如类型是人类),但世界上有几十亿人,我得到的这个神马人类到底是谁?这就是为什么我们每个人都要有一个名字。这个名字在wowMemory中被称作“GUIDs”(Globally Unique ID, 全局唯一标识),用于唯一标识一个对象。
After this we have“Descriptors” which Describe (man these programmers are so clever) a WowObject.They kind of act like adjectives in the real world. For example in the realworld if you asked someone how they’re health was they would say “good” or“bad”. Well in the programming world we don’t use adjectives, we use numbers.So if we had a Descriptor offset for our health it would tell us “health =100%” or “health = 0% (you dead!)” 接着我们有了另一个概念“描述符(Descriptors)”,用于描述(这些程序员们太特么聪明勒)一个对象的状态。它有点象我们真实生活中的形容词。比如真实世界中你问某人的健康情况,他通常会回答你“很好”或“不怎么样”。但在程序的世界我们不用形容词,而是用数字。所以如果你有一个标识符去描述你的健康(血量),它通常会告诉你“血量=100% 或 血量=0%(挂了)”。
So for good measure and alittle over kill I bring you another example analogy.分寸上似乎有点信息过量,下面是对提到的概念的一个形象类比:
WorldObject - Rick is describing an“object” that he says is a part of this world.
ObjectType - He says it’s a dog.
Guid - The dog’s name is Alfred
Descriptor - Alfred is happy
世界对象 WorldObject -瑞克在描述一个对象,它是这个世界的一部分。对象类型 ObjectType -他说这个对象是狗狗。全局唯一标识 Guid -狗狗的名字叫Alfred。描述符 Descriptor -Alfred很快乐。
(I will go into furtherdetail about these things later)(稍后我会深入这些概念)
So now that you get theidea behind it let’s see how they actually work in programming. 现在让我们走入这些概念的背后去看看在程序的世界它们是怎么工作的。
--Memory:--
Now to be thorough, I’mgoing to explain a little bit about how memory works. Memory or RAM (RandomAccess Memory) or the little stick you shove into your motherboard to make yourcomputer run, acts as a way to store information from running programs. Thinkof it as like little cubby holes that stores 1byte of information (generally anregular int is 4 bytes) that your program might need later.
为了让你彻底理解,我先解释下系统内存是如何工作的。内存或RAM(随机存储器)或那根你强插在主板上让计算机运行的条子,用于存储运行中的程序信息。想象成N多个存储一个字节数据的小房间(通常一个整型数据有四个字节,占四个小房间^_^),存储着你的程序运行中会用到的数据信息。
Well, each little cubbyhole has an address so that the program can find that information. This addressis called a hexadecimal (or hex for short) and it looks something like this “ 0x000000”.This address uses 16 symbols for each digit (0-9 and A-F), so if we increment0x000009 by 1 it would be 0x00000A.
每一个小房间都有一个唯一的地址,你的程序可以通过这个地址访问这个小房间里的数据。这个地址被称为“hexadecimal”,简称为hex。看上去象这样:0x000000。就是十六进制数啦,用16个字符表示(0-9 和 A-F),所以0x000000 + 1 = 0x00000A。
Memory Cubby Holepicture:示例图片:
【外部图片】
Example math: 示例计算:
1. 0xF + 0xF = 0x1E
2. 0x5 * 0x5 = 0x19
3. 0xBEAD - 0x4321 = 0x7B8C
4. 0xBEAD + 0x4321 = 0x101CE
5. 0x10000 - 0x1 = 0xFFFF
--Offsets:--
Offsetsin Wow memory reading are used to take an address, change it, and geta new address with (possibly) more information. For example, say I found myplayer at a dynamic address (the address changes each time the game loads) andI had a function called “GetPlayersAddress()” that returned the dynamic addressto me. I could then use a static offset (always stays the same) to get anaddress that contains the value of, say, my health.
偏移量(不知翻译是否准确)是去读取魔兽世界内存地址,改变它,计算出一个新址以得到更多信息。比如,我控制的游戏人物有一个动态地址(因为每次游戏运行加载到内存的区域是不同的)但我有一个程序函数(比如:GetPlayerAddress())可以得到这个动态地址。我就可以使用一个偏移量(这个偏移量永远都一样)去得到一个新地址,以获取更多的信息,比如“血量”。(译者:可以理解为,当你得到一个角色的地内存地址后,固定的偏移值指向固定的信息,比如人物的血量等)
For Example, say my dynamic address(remember this changes) was 0x000001 and my offset was 0x5. My new addresswould be 0x000006.
比如:如果我得到一个动态地址:0x000001 和一个偏移量0x5,那么新址就是0xx5=0x000006
Now the nice thing aboutthis forum is they have a little area called the dump thread which we will beusing since I will not be going into how to actually get these offsets foryourself by reverse engineering Wow. It’s a little too complicate for meat this time.
在作者发贴的这个论坛,有个专门的版块叫dump thread专门罗列了这些偏移值。
--GettingWowBase:--
Now for any bot readingthe memory that Wow uses, you will need to know the base address.This is done (from what I’ve seen) by calling a function that uses a couple ofdlls to check the memory for wow.exe. I do understand how this works, Ijust don’t know enough about dlls to be able to code it myself. ^_^
任何一个想要读取魔兽世界内存数据的机器人,你要获取它的起始地址。这个工作已经完成,我可以直接调用一个函数配合若干DLL动太链接文件去查找内存中的wow.exe。我明白它是如何工作的,但我并不熟悉DLL所以我没法自己写出一个这样的函数,?
So my recommendationwould be to search google for a function to get base addressof wow in your language of choice.
你可以在google上搜索,你所擅长的语言的相关函数。
This is the code inAutoit:下面的代码是用Autoit写的:
(created by IceFire32(unless refuted XD))Code: Func GETWOWBASEADDRESS($PID) & && && &$HSNAP =DllCall(&Kernel32.dll&, &HANDLE&,&CreateToolhelp32Snapshot&, &DWORD&, 8, &DWORD&,$PID) & && && &$STMODULE =DllStructCreate(&DWORD dwSDWORD th32ModuleID;DWORD th32ProcessID;&& &DWORD GlblcntUDWORD ProccntUptr modBaseA& &&DWORD modBaseSHANDLE hMWCHAR szModule[256];& &&WCHAR szExePath[260]&) & && && &DllStructSetData($STMODULE,&dwSize&, DllStructGetSize($STMODULE)) & && && &$RET =DllCall(&Kernel32.dll&, &BOOLEAN&,&Module32FirstW&, &HANDLE&, $HSNAP[0], &ptr&,DllStructGetPtr($STMODULE)) & && && &IF ($RET[0] =False) Then& && && && && && &DllCall(&Kernel32.dll&,&BOOLEAN&, &CloseHandle&, &HANDLE&, $HSNAP[0])& && && && && && &Return 0& && && &Else& && && && && && &$RET[0] =True& && && && && && &Do& && && && && && && && &&&IfDllStructGetData($STMODULE, &szModule&) = &Wow.exe& Then & && && && && && && && && && && &&&DllCall(&Kernel32.dll&,&BOOLEAN&, &CloseHandle&, &HANDLE&, $HSNAP[0]) & && && && && && && && && && && &&&ReturnDllStructGetData($STMODULE, &modBaseAddr&)& && && && && && && && &&&EndIf& && && && && && && && &&&$RET= DllCall(&Kernel32.dll&, &BOOLEAN&,&Module32NextW&, &HANDLE&, $HSNAP[0], &ptr&,DllStructGetPtr($STMODULE))& && && && && && &Until$RET[0] = False& && && &EndIfEndFunc&&;==&GETWOWBASEADDRESS
--ObjectManager:--
This is where we get intothe juicy stuff. With an object manager, it will search through the memory tofind a player memory location. And using some offsets, we can find most thingswe want to know about our player or any other object for that matter.
下面是我们感兴趣的部分了。使用对象管理器,去搜索内存,找到游戏角色在内存中的地址。然后使用偏移量,我们就可以得到大多数我们想得到的并于这个角色的信息。
So first thing we need todo is get a couple of addresses and offsets from the latest patch dump threadthat the mmowned community was nice enough to share with us.
那么我们首先要做的就是得到几个地址和偏移量从最新的patch dump thread,这是mmowned这个社区分享给我们的。
Code:; We make them Global so that every function can access them andConstant so they cannot be changed by the program;注释:定义这些变量为全局变量,以使所有函数可以访问。定义这些变量为固定变量,以使它们不会被我们的程序更改。 ;The first 2 are you create you manager from the baseaddress wow;注释: 用下面两个变量(wow起始地址)去创建管理器Global Const $ClientConnection = 0x8BF1A8Global Const $CurMgrOffset = 0x462C ;The next one is to get the address of your first object ONLY;注释:下面的偏移量去得到第一个对象Global Const $FirstObjectOffset = 0xB4 ;To cycle through the object you need this offset;注释:下面的偏移量是为了循环遍历这个对象Global Const $NextObjectOffset = 0x3C Global Const $PlayerGUID = 0xB8
;This next one is to find the objects type : 1 to 7 ;下面的偏移量可以用来发现对象类型Global Const $GameObjTypeOffset = 0x14 ;And this one is to find the objects GUID;这个偏移量可以找到对象的全局唯一标识Global Const $GameObjGUIDOffset = 0x30
With these and theWowBase we can create our GetObject Function.
有了这些我们可以创建我们自己的GetObject(得到对象)函数了
- We start by getting theProcess ID (or PID) from Wow.我们从得到wow的进程号(PID)开始(每个运行中的程序在操作系统中都有一个进程和用来标识这个进程的进程号)
- And then getting theBaseAddress from wow.exe using the PID然后从这个进程号得到wow.exe在内存中的起始地址。
(dots are there to showthat there is code above it)(省略号表示上面的代码被省略) Code:… $PID = WinGetProcess(&World of Warcraft&) Global $WowBase = GetWoWBaseAddress($PID)
Next we will get a handlefrom a function in nomadmemory.au3下面我们用momadmemory.au3中的函数去得到一个句柄。
(Which allows us to usethe _MemoryRead function):(它将允许我们使用_MemoryRead 这个函数)Code:… $hWow = _MemoryOpen($PID)
Now that that is done, wecan start adding our offsets and addresses together to create our ObjectFunction using the memoryread function provided by Nomad.
结束上面的工作,我们可以开始将我们得到的地址加上偏移量,然后用memoryread函数(由Nomad提供)去创建我们自己的对象函数。
But first we need to addthe offsets to our base and add an offset to that to get the manager. Afterthat, to get the PlayerGUID (which we will need to find our LocalPlayer) we addthe PlayerGUID offset to the current manager: 但首先我们需要添加一些常量去得到管理器。然后,去得到角色GUID(PlayerGUID,我们需要用它来找到我们的本地角色),我们添加PlayerGUID偏移量到当前的管理器。 Code:Global Const $ClientConnection = 0x8BF1A8Global Const $CurMgrOffset = 0x462C Global Const $FirstObjectOffset = 0xB4 Global Const $NextObjectOffset = 0x3C ;even though this says $playerGUID it is actually the offset to getthe player GUID (offsetting the manager and not the object)Global Const $PlayerGUID = 0xB8
Global Const $GameObjTypeOffset = 0x14Global Const $GameObjGUIDOffset = 0x30 $PID = WinGetProcess(&World of Warcraft&) Global $WowBase = GetWoWBaseAddress($PID)
$hWow = _MemoryOpen($PID)
; Starting Here; Params for our memoryread func is:_MemoryRead(Address,Handle,Type) $currMgr_pre = _MemoryRead(&0x& & Hex($WowBase +$ClientConnection), $hWow , &dword&)$currMgr = _MemoryRead(&0x& & Hex($currMgr_pre +$CurMgrOffset), $hWow , &dword&)$pGUID = _MemoryRead(&0x& & Hex($currMgr +$PlayerGUID), $hWow , &UINT64&) ; The reason we use hex is to because the _memoryread functionneeds that value to be in hex format.; To be honest I don’t think we need to use it but I do it anywaysXD
F theseare the many different types in programming:’下面列出的是Autoit的变量类型表:
(From Autoit help)Code:Type& &&&Detailsnone& &&&no value (only valid for return type -equivalent to void in C)BYTE& &&&an unsigned 8 bit integerBOOLEAN&&an unsigned 8 bit integershort& & a 16 bit integerUSHORT& &an unsigned 16 bit integerWORD& &&&an unsigned 16 bit integerint& && &a 32 bit integerlong& &&&a 32 bit integerBOOL& &&&a 32 bit integerUINT& &&&an unsigned 32 bit integerULONG& & an unsigned 32 bit integerDWORD& & an unsigned 32 bit integerINT64& & a 64 bit integerUINT64& &an unsigned 64 bit integerptr& && &a general pointer (void *)HWND& &&&a window handle (pointer)HANDLE& &an handle (pointer)float& & a single precision floating point numberdouble& &a double precision floating point numberINT_PTR, LONG_PTR, LRESULT, LPARAM an integer big enough tohold a pointer when running on x86 or x64 versions of AutoIt.UINT_PTR, ULONG_PTR, DWORD_PTR, WPARAM& && &an unsigned integerbig enough to hold a pointer when running on x86 or x64 versions of AutoIt.str& && &an ANSI string (a minimum of 65536 charsis allocated).wstr& &&&a UNICODE wide character string (a minimumof 65536 chars is allocated).*& && &&&Add * to the end of another type to passit by reference. For example &int*& passes a pointer to an&int& type.
Finally we can get to ourObject Function. Now the Idea behind this is to start at our first address andcheck it to see if what is in that address = the GUID given. (in this example,the LocalPlayer’s GUID)
终于我们可以让我们的对象工作了。工作原理就是从起始地址开始检查是否可找到GUID。(在这个例子中表示本地角色的GUID,LocalPlayer's GUID)
Thanks unnamed user that,after posting this, I’ll ask if it’s alright to mention him.Code:Func GetMemLocByGUID($guid)& && && &;Read the first wow object by adding our current manager address andour first object offset together& && && &$NextObject =_MemoryRead(&0x& & Hex($currMgr + $FirstObjectOffset), $hWow ,&dword&)& && && && && && && && && &;next get the object type buy adding our firstobject and our Objtype offset together and reading that& && && &$ObjType =_MemoryRead(&0x& & Hex($NextObject + $GameObjTypeOffset), $hWow ,&dword&)& && && && && && &;If the return of object type is less than orequal to 7 (which it should always be) and more than 0 in the case that we dohave an object in the list than do a while loop.
& && && &while (($ObjType&= 7) And ($ObjType & 0))& && && && && && &;NOTE: if there is an object in the list, objTypewill have to be = 1 to 7& && && && && && &; If ourobject plus the GUIDoffset = the GUID we are looking for (example ourlocalplayer GUID) …& && && && && && && && && && && & IF(_MemoryRead(&0x& & Hex($NextObject + $GameObjGUIDOffset), $hWow, &UINT64&) = $guid) T …then return our object& && && && && && && && && && && && && && &&&Return$NextOfound what we wanted.& && && && && && &EndIf
& && && && && && &;if noreturn happens (stays in the function) then cycle through the objects using ournext object offset on our next object (might also be called current object)& && && && && && &$NextObject= _MemoryRead(&0x& & Hex($NextObject + $NextObjectOffset), $hWow, &dword&) & && && && && && &;Wewill also need to see the type& && && && && && &$ObjType= _MemoryRead(&0x& & Hex($NextObject + $GameObjTypeOffset), $hWow, &dword&)& && && &Wend & && && &;if we find nothing Return 0 (address areprobably wrong or you messed up code)& && && &Return 0;EndFunc
Excitingly enough, we canactually get the XYZ cords and rotation (in rad) of our player just from thereturn of this function and a few offsets. Back in the dump thread we can seethat: 碉堡了,从这个函数返回的一些偏移量,我们可以得到我们的角色的XYZ坐标和角度。从dump thread 版块我们可以查到: Code:Under : internal enum WowObject&&X = 0x898,&&Y = X + 0x4,&&Z = X + 0x8,&&RotationOffset = X +0x10
(Posted byArutha532)
So…所以我们又得到了一些非常有用的偏移量: Code:…Global Const $UnitPosXOffset = 0x898Global Const $UnitPosYOffset = 0x898 + 0x4Global Const $UnitPosZOffset = 0x898 + 0x8Global Const $UnitRotationOffset = 0x8A8…$pObjectMemLoc = GetMemLocByGUID($pGUID); if we add$pXPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosXOffset), $hWow , &float&)$pYPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosYOffset), $hWow , &float&)$pZPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosZOffset), $hWow , &float&)$pRotation = _MemoryRead(&0x& & Hex($pObjectMemLoc+ $UnitRotationOffset), $hWow , &float&)…
But I’ll go further intodetails about the XYZ and Rotation later.
--Descriptors:--
Now it is time for ourdescriptors (as you could probably tell). Remember our descriptors explain tous our object. This would mean that, assuming we have the offsets, it couldtell us the health of the object, mana, rage, energy, stats, who it’s targeting(if unit), if it’s being attacked and so much more (check out the dump.) So letus look at a few of the simpler ones such as health.
现在轮到我们的描述者登场了。相信你还记得描述者是用来描述我们的对象的状态。这意味着它将告诉我们关于我们的对象的:魔法值,rage(是啥?)、能量、状态、及谁已经设该对象为目标,是否被攻击和许多其它的信息(查看dump thread)。让我们看下得到血量的例子:
Let us, for now, get ridof the XYZR of our object and bring back to focus our Memloc function and itsaddresses.
让我们抛开XYZR,回到MemLoc函数和它的地址。
Code:Global Const $ClientConnection = 0x8BF1A8Global Const $CurMgrOffset = 0x462C Global Const $FirstObjectOffset = 0xB4 Global Const $NextObjectOffset = 0x3C Global Const $PlayerGUID = 0xB8
$PID = WinGetProcess(&World of Warcraft&) Global $WowBase = GetWoWBaseAddress($PID)
$hWow = _MemoryOpen($PID)
; Params for our memoryread func is:_MemoryRead(Address,Handle,Type) $currMgr_pre = _MemoryRead(&0x& & Hex($WowBase +$ClientConnection), $hWow , &dword&)$currMgr = _MemoryRead(&0x& & Hex($currMgr_pre +$CurMgrOffset), $hWow , &dword&)$pGUID = _MemoryRead(&0x& & Hex($currMgr +$PlayerGUID), $hWow , &UINT64&)$pObjectMemLoc = GetMemLocByGUID($pGUID)…
Okay now that we have ourcode a little cleaned up, let’s look at the descriptor offset. The descriptoroffset is essentially telling the memory that we want to look at itsdescriptors now, so adding the descriptor offsets to this address will returnus an address (if I am correct) and then we will be able to add our offsets tothat address.
现在我们的代码看来清楚些了,让我们看下描述者的偏移量。描述者偏移量本质上是用来告诉内存,我们想要找到描述者,即添加一些偏移量在这个地址,我们将得到一个描述者地址,然后我们就可以添加我们的偏移量到这个描述者地址以得到更多信息了。
This address right nowis: 0x8这个地址为:0x8
And the address for ourhealth (from the dump thread)is :去得血量的地址(通过查看dump thread)
So now we can add this toour code : Code:…Global Const $PlayerHealthOffset = 0x68Global Const $DescriptorOffset = 0x8…$pDescriptor = _MemoryRead(&0x& &Hex($pObjectMemLoc + $DescriptorOffset), $hWow , &dword&)$pHealth = _MemoryRead(&0x& & Hex($pDescriptor +$PlayerHealthOffset), $hWow ,&dword&)…
That should be enough fordescriptors.
Now there is only onelast thing I would like to show to all the little newbs that might be readingthis.
这对描述者来说足够了。现在我只剩一件事我想和读这篇文章的新手们分享了。
And this is…..
--XYZR Manipulation:--
Back to this:回到这段代码: Code:…Global Const $UnitPosXOffset = 0x898Global Const $UnitPosYOffset = 0x898 + 0x4Global Const $UnitPosZOffset = 0x898 + 0x8Global Const $UnitRotationOffset = 0x8A8…$pObjectMemLoc = GetMemLocByGUID($pGUID); if we add$pXPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosXOffset), $hWow , &float&)$pYPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosYOffset), $hWow , &float&)$pZPos = _MemoryRead(&0x& & Hex($pObjectMemLoc +$UnitPosZOffset), $hWow , &float&)$pRotation = _MemoryRead(&0x& & Hex($pObjectMemLoc+ $UnitRotationOffset), $hWow , &float&)…
This is mostly for peoplewho do not know trigonometry. I’m not going to go into math because your programminglanguage should have a function like this or at least the function to createthis function.
这是为了那些不懂三角函数的同鞋。我不想深讲解数学,因为你用的语言应该有一个相似的函数去完成这个功能。
This is of course, theATan2 function. (of course…XD). In order to create this function we will at thevery least need the ATan (Arc Tangent) function. But I do not feel like goinginto math so im going to keep it like this. If your language doesn’t have anATan func (or ATan2) then go search up the math on google (for the ATan func)and then come meet me back here.
这是ATan2(返回给定的 X 及 Y 坐标值的反正切值)。为了创建这个函数,我们至少需要反正切函数。但我不打算深数学。如果你的语言没有这些函数,到google上查到后返回这里。
In Autoit, we have anATan function not an ATan2 function. With this ATan2 function we will be ableto calculate the angle from one point to the other. After that if we use ourplayer rotation and compare it to the angle from ATan2 we will then be able torotate our player and run to our target point.
在Autoit中,我们有ATan函数但没有ATan2函数。有了这个函数,我们可以计算出我们从一个点到另一个点的角度。然后通过角色的角度去对比计算出的角度,我们就可以转动我们的角色并距到目标的坐标了。
This is done by doing:_ATan2($targetY - $pYPos, $targetX -$pXPos)
这个功能被这个函数完成: _ATan2($targetY- $pYPos, $targetX - $pXPos)
I present to you ATan2:ATan2源代码: Code:Func _ATAN2(Const $NY, Const $NX)& && && &Const $NPI =3.79 ;Pi& && && &Local $NRESULT& && && &If IsNumber($NY) =0 T Makes sure Y value is anumber& && && && && && &SetError(1)& && && && && && &Return 0& && && &ElseIfIsNumber($NX) = 0 TMakes sure X value is a number& && && && && && &SetError(1)& && && && && && &Return 0& && && &EndIf& && && &If $NX = 0 T we would only need to turn 180 degrees or
pi(rad)& && && && && && &If $NY& 0 Then & && && && && && && && &&&$NRESULT= $NPI / 2 & && && && && && &ElseIf$NY & 0 Then& && && && && && && && &&&$NRESULT= 3 * $NPI / 2& && && && && && &Eif both x and y = 0 it would mean we werestanding on our target spot& && && && && && && && &&&SetError(2)& && && && && && && && &&&Return0& && && && && && &EndIf& && && &ElseIf $NX & 0Then& && && && && && &$NRESULT= ATan($NY / $NX) + $NPI& && && &Else& && && && && && &$NRESULT= ATan($NY / $NX)& && && &EndIf& && && &While $NRESULT& 0 ;we don’t like negativeangles & && && && && && &$NRESULT+= 2 * $NPI& && && &WEnd& && && &Return $NRESULTEndFunc& &;==&_ATAN2
(From(because I was toolazy to make it myself): )(来自 :)
After this you could theuse a temp variable to store the difference between the player rotation and theangle returned and use it like so:然后你可以使用一个临时变量去存储角色角度和返回角度的差值 :Code:If $tempangle & $pi then(Turn Left)Else(Turn right)endif
The last little functionI would like to share with you (it is very simple) is a function used to makesure your program is not comparing variables to closely. For example, theplayer x coord is a super long float so you would have to be too accurate to bedead on the target x position. This is a simple solution to that. 下面这个函数是为了不去比较两个非常想近的值。比如,角色X的坐标是一个超级长的值,你必须非常精确以使其不会dead在目标X点。下面函数是一个简单的解决方案:
Code:Func Around($sVal, $eVal, $bNum) & && && &If $sVal - $eVal& $bNum And $sVal - $eVal & (-$bNum) Then& && && && && && &ReturnTrue& && && &Else& && && && && && &ReturnFalse& && && &EndIfEndFunc& &;==&Around
So when comparing Playerx and y to Target x and y, you would go:去比较角色XY坐标和目标XY坐标: Code:If Not Around($pXPos, $targetXY[0], 0.8) Or Not Around($pYPos,$targetXY[1], 0.8) Then(blah blah bah)endif
--Names (NEW!):--
Getting names from theWorld of Warcraft memory is relatively simple depending on what type of objectyou are trying to get it from. For example, getting the names from NPCs andobject is pretty simple where as getting it from a player is complicated. Inthis portion i am not going to go into detail on how to get a players name buti will post code (to be honest i just copied and pasted code and changed thingsdepending on what google and the forum said...porting from one language toanother)
从内存中得到魔兽的名字相对简单,但取决于什么类型的对象你想得到。比如,到到NPC的名字和对象非常简单,但到到一个玩家角色的名字就复杂了。在这部分我不会深入如何得到一个角色名字的细节,但我会展示一些代码(说实话,我只是copy并通过google和论坛的进示做了一些修改,从其它语言移值)
So lets start withNPCS.
让我们从NPC说起。
First id like to say thatthe dump unitname is not a descriptor address. I have made this mistake =D.Also id like you to note that instead of 1 offset, there are 2. This isdifferent from all the other offsets we have seen so far but it is not anymorecomplicated than what we have previously seen.
首先我想说dump unitname不是一个描述者地址。这是我的一个错误。然后,这里有两个偏移量,而不是一个,这是和其它我们曾经看到过的偏移量不同的。
Now, you will start byadding your first offset (unitname1) to your objects memory location (returnedby ur memloc function). Memory read this to get back an address (preferablystore it in a variable maybe called $name1) and then add your 2nd offset to thememory address returned. This will also return an address. If you memory readthat 1 more time (read it as a char) then you should get the name ofthat wow object (NPC)现在我们从添加第一个偏移量到你的内存地址(通过memloc函数得到)开始(unitname1)。读取这个内存址(存在某个变量 中,如$name1)然后添加第二个偏移量到这个地址以得到另一个地址。然后再调用内存读函数读取最后得到的地址,你就会得到NPC的名字。 Code:;Declaring our Global Const variablesGlobal Const $UnitName1 = 0xA24Global Const $UnitName2 = 0x60 Func _GetUnitName($fGUID) ; adding first name offset to memloc returned by memloc function& && && &$Name1 =_Memoryread(_GetObjectMemLocByGUID($fGUID) + $UnitName1, $wow, &dword&);We get an address from this ;Next we add our second offset to our returned address& && & & && &&&$Name2 =_Memoryread($Name1 + $UnitName2, $wow, &dword&);This again returns us an address ;Memory read that again and set the type as char [and an amount ofcharacters]& && && &Return_MemoryRead($Name2, $wow,&char[20]&)EndFunc&&;==&_GetUnitName ;And you get the npcs name
For objects, it is prettymuch the same code with different addresses.对其它对象,情况相似:Code:Global Const $ObjName1 = 0x1CCGlobal Const $ObjName2 = 0xB4 Func _GetObjectName($fGUID)& && && &$Name1 =_Memoryread(_GetObjectMemLocByGUID($fGUID) + $ObjName1, $wow, &dword&)& && && &$Name2 =_Memoryread($Name1 + $ObjName2, $wow, &dword&)& && && &Return_MemoryRead($Name2, $wow,&char[20]&)EndFunc&&;==&_GetObjectName
And lastly to get aplayers name, here is some copy-pasta:最后是得到玩家角色名字的代码:Code:;So you know what the hell the offsets are...;BASE_STATIC_POINTER = 0x89ACC0 + 0x8;; MASK_OFFSET = 0x024;& && && &&&;BASE_OFFSET = 0x01c;& && && &&&;STRING_OFFSET = 0x020;...below Func _GetPlayerName($fGUID = $pGUID) & && && &$mask =_MemoryRead($WowBase + 0x89ACC0 + 0x8 + 0x024, $wow)& && && &$base =_MemoryRead($WowBase + 0x89ACC0 + 0x8 + 0x01c, $wow) & && && &$shortGUID =BitAND($fGUID, 0xffffffff)& && && &if ($mask =0xffffffff) Then& && && && && && &Return&&& && && &EndIf & && && &$offset = 12 *BitAND($mask, $shortGUID)& && && &$current =_MemoryRead($base + $offset + 8, $wow)& && && &$offset =_MemoryRead($base + $offset, $wow) & && && &if(BitAND($current, 0x1) = 0x1) Then & && && && && && &Return&&& && && &EndIf & && && &$testGUID =_MemoryRead($current, $wow) & && && &while ($testGUID&& $shortGUID) & && && && && && &$current= _MemoryRead($current + $offset + 4, $wow)& && && && && && &if(BitAND($current, 0x1) = 0x1) Then& && && && && && && && &&&Return&&& && && && && && &EndIf& && && && && && &$testGUID= _MemoryRead($current, $wow)& && && &WEnd& && && &Return_MemoryRead($current + 0x020, $wow, &char[20]&)EndFunc&&;==&_GetPlayerName
--Conclusion:--
I hopethis has helped at least a few people in their journey to making bots. Thistook me a few days to make (switching between watching awesome movies/ tv showsto working on this). If you actually took the time to read all this, you areamazing and should have a pretty good idea of whats going on … unless I suck atmaking guides.
我希望这篇文章能帮到想做个游戏机器人的新手们。这篇文花费了我几天时间(包括看精彩的电脑、电视剧)。如果你真的花了时间去读这篇文章,你应该可以知道该如何下手去做一个机器人,除非我的文太糟糕了。
Um…Remember to do some searching on your own and to play around with this stuff.Practice makes perfect and I’m sure we would all like some awesome bots to playthis game for us because we are too damn lazy to do it ourselves. Thanks forreading and goodluck! ^_^
记得自己去查些资料。练习才是编程的王道(熟能生巧)。我肯定我们都喜欢一些强大的机器人能帮我们控制角色,因为我们都太懒。感谢大家读这篇文,祝好运!^_^
If there is anythingwrong with any of the information, you have something to add or you needsomething better explained please let me know and I will correct.
如果文有任何不对的地方,你想添加一些东西或需要更多解释,请告之,我会更正。
And if I'm totally wrong, laugh and ridicule me until i cry myself to sleepbecause i could use a good nights rest.
One last thing!... Themystery man that helped me figure all this out is Megamike55. Thanks again mani really appreciate it! Purple just for you!
有空一块吃河蟹
Lv.6, 积分 3815, 距离下一级还需 1185 积分
UID5030518帖子威望1 多玩草201 草
作者用到的语言:
度受百科:
疯一样的男人
吕布我是貂蝉
Lv.7, 积分 5072, 距离下一级还需 4928 积分
UID5973324帖子威望1 多玩草17 草
unless I suck atmaking guides
恩,这句说中了
当全需成为习惯,当乱R变成正常,在玩家道德整体崩溃的年代,我做我自己,做一个有素质的WOWer
新人欢迎积分0 阅读权限40积分974精华0UID9096390帖子金钱1197 威望0
Lv.4, 积分 974, 距离下一级还需 26 积分
UID9096390帖子威望0 多玩草10 草
虽然不知道LZ在说些什么。但是很厉害的样子!
新人欢迎积分0 阅读权限50积分1801精华0UID3289033帖子金钱1837 威望0
Lv.5, 积分 1801, 距离下一级还需 699 积分
UID3289033帖子威望0 多玩草10 草
天书奇谭么?
新人欢迎积分2 阅读权限40积分447精华0UID帖子金钱1683 威望0
Lv.4, 积分 447, 距离下一级还需 553 积分
UID帖子威望0 多玩草0 草
牛啊& &先占楼再去看看
新人欢迎积分0 阅读权限30积分98精华0UID帖子金钱203 威望0
Lv.3, 积分 98, 距离下一级还需 152 积分
UID帖子威望0 多玩草0 草
去做个看看& &谢谢翻译
Lv.3, 积分 248, 距离下一级还需 2 积分
UID6733904帖子威望0 多玩草10 草
完全看不懂
Lv.4, 积分 426, 距离下一级还需 574 积分
UID1012210帖子威望0 多玩草10 草
=,- 这个是按键精灵 那种?脚本?运行?我个人觉得。。这玩意 除非我是拿来炸矿的时候用 其余时间 还真不知道 有什么用 刷怪?打钱?-,。。。。WO 还是少点工作室 之类的吧 会蛋疼的。。。
新人欢迎积分1 阅读权限60积分3713精华1UID2118186帖子金钱10595 威望0
Lv.6, 积分 3713, 距离下一级还需 1287 积分
UID2118186帖子威望0 多玩草151 草
虽然不知道楼主在说什么,但是好像很厉害的样子。
Lv.4, 积分 920, 距离下一级还需 80 积分
UID帖子威望0 多玩草0 草
不会用[ew55]
、我发现了,只要许愿的东西都没出、
果断不许愿了、
Lv.3, 积分 213, 距离下一级还需 37 积分
UID帖子威望0 多玩草0 草
虽然不知道楼主在说什么,但是好像很厉害的样子……
新人欢迎积分0 阅读权限40积分348精华0UID帖子金钱1197 威望0
Lv.4, 积分 348, 距离下一级还需 652 积分
UID帖子威望0 多玩草0 草
看不懂额......
残月丶枫魔
Lv.4, 积分 863, 距离下一级还需 137 积分
UID帖子威望0 多玩草0 草
占个座慢慢看
Lv.4, 积分 784, 距离下一级还需 216 积分
UID帖子威望0 多玩草0 草
到底是人玩游戏还是游戏玩人啊
手机论坛勋章
APP发帖双倍积分,登陆即送勋章!
需要金钱:1100
手机盒子客户端点击或扫描下载
Powered by

参考资料

 

随机推荐