Thanks for the responses.
I do get the feeling I haven't quite hit the mark on the offsets or perhaps my additions are wrong somewhere. I'm fairly confident that my actual code to loop the gameobjects is OK as I have run from Elwynn to Stormwind and I went from looping 70 objects to around 200 or so. This to me feels like a good indication that that area is OK.
I spent most of last night scouring the forums for examples from the old days (2.4.3) to see what the object structs look like and I can't seem to find anything wrong with the proposed offsets.
Currently I'm getting a funny issue of having my guid match with a GameObject:
wowgameobject.png
Code:
using Process.NET;
using System;
using System.Collections.Generic;
using System.Linq;
using WoWTestConsole.Models;
namespace WoWTestConsole
{
public class ObjectManager
{
private const int ObjManager = 0x2CFF7E8;
private const int firstObjectOffset = 0x18;
private const int nextObjectOffset = 0x70;
private readonly IProcess process;
private IntPtr objManagerAddress;
private Guid localGuid;
public ObjectManager(IProcess process)
{
this.process = process;
var basePointer = process[process.ModuleFactory.MainModule.BaseAddress];
// Step one: read the address of the object manager
this.objManagerAddress = basePointer.Read<IntPtr>(ObjManager);
this.localGuid = basePointer.Read<Guid>(0x2BD9B40);
Console.WriteLine($"My guid {this.localGuid}");
Console.WriteLine($"CurMgr: 0x{objManagerAddress.ToString("X")}");
}
public void Pulse()
{
var count = 0;
// Step two: Read the first object by using object manager address (Retrieved in step one) added to the first object offset
var CurrentObject = new WowObject(this.process, this.process[objManagerAddress].Read<IntPtr>(firstObjectOffset));
// Step four: Each WowObject needs to query its base address + property offset to fill related information
Console.WriteLine($"GUID: {CurrentObject.Guid} Type: {CurrentObject.Type} X: {CurrentObject.XPosition} Y: {CurrentObject.YPosition} Z: {CurrentObject.ZPosition}");
var players = new List<PlayerObject>();
var npcs = new List<NpcObject>();
while (CurrentObject.BaseAddress.ToInt64() != 0 && CurrentObject.BaseAddress.ToInt64() % 2 == 0)
{
if (CurrentObject.Guid == this.localGuid)
{
// This appears to match my guid with an game item??
Console.WriteLine("Match");
}
++count;
//Console.WriteLine($"Base: 0x{CurrentObject.BaseAddress.ToString("X")} | Descriptors: 0x{CurrentObject.DescriptorFields.ToString("X")} Type: {CurrentObject.Type} X: {CurrentObject.XPosition} Y: {CurrentObject.YPosition} Z: {CurrentObject.ZPosition}");
// Step four: Each iteration indicates another object in the list, update the existing WowObject with the new 'base' address which populates the object
if (CurrentObject.Type == ObjectType.Unit) // a npc
{
var npc = new NpcObject(this.process, CurrentObject.BaseAddress);
Console.WriteLine($"NPC - Name: {npc.Name} Health: {npc.CurrentHealth} Mana: {npc.CurrentMana} Level: {npc.Level}");
npcs.Add(npc);
}
if (CurrentObject.Type == ObjectType.Player) // a player
{
var player = new PlayerObject(this.process, CurrentObject.BaseAddress);
Console.WriteLine($"Player - Guid: {player.Guid} Health: {player.CurrentHealth} Mana: {player.CurrentMana} Level: {player.Level}");
players.Add(player);
}
CurrentObject.BaseAddress = this.process[CurrentObject.BaseAddress].Read<IntPtr>(nextObjectOffset);
}
//Step five: let's try and find ourself in the local player list
var localPlayer = players.Where(x => x.Guid == this.localGuid).FirstOrDefault();
var myMana = npcs.Where(x => x.CurrentMana == 190);
Console.WriteLine($"Total: {count}");
Console.ReadLine();
}
}
}
Code:
using Process.NET;
using Process.NET.Memory;
using System;
using WoWTestConsole.Models;
namespace WoWTestConsole
{
class WowObject
{
protected const int GuidOffset = 0x58,
TypeOffset = 0x20,
XPositionOffset = 0x1600,
YPositionOffset = XPositionOffset + 0x4,
ZPositionOffset = XPositionOffset + 0x8,
RotationOffset = XPositionOffset + 0x10,
DescriptorFieldsOffset = 0x10;
protected IntPtr baseAddress;
protected IProcess wowProcess;
public WowObject(IProcess wowProcess, IntPtr baseAddress)
{
this.wowProcess = wowProcess;
this.baseAddress = baseAddress;
}
public IntPtr BaseAddress
{
get { return baseAddress; }
set { baseAddress = value; }
}
public IntPtr DescriptorFields
{
get { return this.wowProcess.Memory.Read<IntPtr>(this.baseAddress + DescriptorFieldsOffset); }
}
public ObjectType Type
{
get { return (ObjectType)this.wowProcess.Memory.Read<byte>(this.baseAddress + TypeOffset); }
}
public virtual Guid Guid
{
get { return this.wowProcess.Memory.Read<Guid>(this.baseAddress + GuidOffset); }
set { return; }
}
public virtual float XPosition
{
get { return this.wowProcess.Memory.Read<float>(this.baseAddress + XPositionOffset); }
}
public virtual float YPosition
{
get { return this.wowProcess.Memory.Read<float>(this.baseAddress + YPositionOffset); }
}
public virtual float ZPosition
{
get { return this.wowProcess.Memory.Read<float>(this.baseAddress + ZPositionOffset); }
}
public float Rotation
{
get { return this.wowProcess.Memory.Read<float>(this.baseAddress + RotationOffset); }
}
}
}
Code:
using Process.NET;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WoWTestConsole.Models
{
class CreatureObject : WowObject
{
protected const int LevelOffset = 0x134,
CurrentHealthOffset = 0xDC,
MaxHealthOffset = 0xFC,
CurrentManaOffset = 0xE4,
MaxManaOffset = 0x104,
TargetGuidOffset = 0x9C;
public CreatureObject(IProcess wowProcess, IntPtr baseAddress)
: base(wowProcess, baseAddress)
{
}
public float Pitch
{
get { return this.wowProcess.Memory.Read<float>(this.wowProcess.Memory.Read<IntPtr>(baseAddress + 0x17B8) + 0xE0); }
}
public ulong TargetGuid
{
get { return this.wowProcess.Memory.Read<ulong>(DescriptorFields + TargetGuidOffset); }
}
public int Level
{
get { return this.wowProcess.Memory.Read<int>(DescriptorFields + LevelOffset); }
}
public int CurrentHealth
{
get { return this.wowProcess.Memory.Read<int>(DescriptorFields + CurrentHealthOffset); }
}
public int MaxHealth
{
get { return this.wowProcess.Memory.Read<int>(DescriptorFields + MaxHealthOffset); }
}
public int CurrentMana
{
get { return this.wowProcess.Memory.Read<int>(DescriptorFields + CurrentManaOffset); }
}
public int MaxMana
{
get { return this.wowProcess.Memory.Read<int>(DescriptorFields + MaxManaOffset); }
}
public int HealthPercent
{
get
{
double percentage = CurrentHealth / MaxHealth;
percentage = percentage * 100;
return (int)Math.Round(percentage);
}
}
}
}
Code:
enum ObjectType : int
{
Object = 0,
Item = 1,
Container = 2,
Unit = 3,
Player = 4,
GameObject = 5,
DynamicObject = 6,
Corpse = 7,
AreaTrigger = 8,
SceneObject = 9,
NumClientObjectTypes = 0xA
}
As a side point, it's pretty amazing reading through some of the early 2009 onwards content in this forum, I've spent the majority of the last few evenings trying to work through this and it's incredibly addictive!
Charles420 - if you read this, would you be able to point me in the direction of any reading content to reverse the PlayerGUID? I was actually searching the forum last night trying to figure that out but most posts are just providing the GUID rather than explaining how it is actually retrieved.