I used this guide to get started and I found it extremely helpful. I translated some of it into C++ (albeit very poorly) and I'm pasting it here jic someone would like to toy around with it.
All credit goes to the OP - Jbrauman. Offsets are for 3.0.9
C++ Code for ObjectManager:
Code:
class oManager
{
public:
oManager()
{
Memory::AddDebugPrivileges(); //Required as no instance of the class has been made.
LoadAddresses();
}
void LoadAddresses()
{
DWORD clientConnection = Memory::Read<DWORD>(0x11CB310); //Get Client Connection:
objectManagerBase = Memory::Read<DWORD>(clientConnection + 0x28A4);
localGuid = Memory::Read<INT64>(objectManagerBase + 0xC0); //Object manager base + localGUID offset
}
list<oNpc> oNpcList;
list<oGame> oGameList;
list<oPlayer> oPlayerList;
void PopulateLists()
{
oNpcList.erase(oNpcList.begin(), oNpcList.end());
oGameList.erase(oGameList.begin(), oGameList.end());
oPlayerList.erase(oPlayerList.begin(), oPlayerList.end());
WowObject CurrentObject = WowObject(Memory::Read<DWORD>(objectManagerBase + firstObjectOffset));
while (CurrentObject.baseAddress != 0 && CurrentObject.baseAddress % 2 == 0)
{
if (CurrentObject.GetType() == 3) // a npc
oNpcList.push_back(oNpc(CurrentObject.baseAddress));
if (CurrentObject.GetType() == 4) // a player
oPlayerList.push_back(oPlayer(CurrentObject.baseAddress));
if (CurrentObject.GetType() == 5) // a gameobject
oGameList.push_back(oGame(CurrentObject.baseAddress));
DWORD CurrentBase = CurrentObject.baseAddress;
CurrentObject = WowObject(Memory::Read<DWORD>(CurrentBase + nextObjectOffset));
}
}
void populatePlayer()
{
//DWORD constPlayerBase = Memory::Read<DWORD>(Memory::Read<DWORD>(Memory::Read<DWORD>(0x127F13C) + 0x30) + 0x28);
DWORD oFirst = Memory::Read<DWORD>(objectManagerBase + firstObjectOffset);
DWORD oThis = oFirst;
INT64 oGuid = NULL;
while (oGuid != localGuid)
{
oGuid = Memory::Read<INT64>(oThis + 0x30);
if (oGuid == localGuid)
{
//This is where your player will be!!
}
oFirst = oThis;
oThis = Memory::Read<DWORD>(oFirst + nextObjectOffset);
}
}
private:
const static DWORD firstObjectOffset = 0xAC; // offset from the object manager to the first object
const static DWORD nextObjectOffset = 0x3C; // offset from one object to the next
DWORD objectManagerBase; // the address off the object manager
INT64 localGuid; // the local guid.
};
C++ Code for the other Objects
*Note that string names don't function due to my lack of skill.
Code:
class WowObject
{
public:
WowObject(DWORD baseAddress)
{
this -> baseAddress = baseAddress;
RefreshFields();
}
void RefreshFields()
{
SetDescriptorFields();
SetType();
SetGuid();
SetXPosition();
SetYPosition();
SetZPosition();
SetRotation();
}
void SetDescriptorFields()
{
this -> descriptorFields = Memory::Read<DWORD>(baseAddress + descriptorFieldsOffset);
}
int GetDescriptorFields()
{
return descriptorFields;
}
void SetType()
{
this -> type = Memory::Read<int>(baseAddress + typeOffset);
}
int GetType()
{
return type;
}
void SetGuid()
{
this -> guid = Memory::Read<INT64>(baseAddress + guidOffset);
}
INT64 GetGuid()
{
return guid;
}
virtual void SetXPosition()
{
this -> xPosition = Memory::Read<float>(baseAddress + xPositionOffset);
}
float GetXPosition()
{
return xPosition;
}
virtual void SetYPosition()
{
this -> yPosition = Memory::Read<float>(baseAddress + yPositionOffset);
}
float GetYPosition()
{
return yPosition;
}
virtual void SetZPosition()
{
this -> zPosition = Memory::Read<float>(baseAddress + zPositionOffset);
}
float GetZPosition()
{
return zPosition;
}
void SetRotation()
{
this -> rotation = Memory::Read<float>(baseAddress + rotationOffset);
}
float GetRotation()
{
return rotation;
}
DWORD baseAddress;
DWORD descriptorFields;
float zPosition,
yPosition,
xPosition,
rotation;
INT64 guid;
int type;
protected:
const static DWORD guidOffset = 0x30;
const static DWORD nextObjectOffset = 0x3C;
const static DWORD typeOffset = 0x14;
const static DWORD xPositionOffset = 0x7D0;
const static DWORD yPositionOffset = 0x7D4;
const static DWORD zPositionOffset = 0x7D8;
const static DWORD rotationOffset = 0x7DC;
descriptorFieldsOffset = 0x08;
};
class Creature : public WowObject
{
public:
Creature(DWORD baseAddress) : WowObject(baseAddress)
{
this -> baseAddress = baseAddress;
RefreshFields();
}
void RefreshFields()
{
SetTargetGuid();
SetLevel();
SetCurrentHealth();
SetMaxHealth();
SetHealthPercent();
SetCurrentMana();
SetMaxMana();
SetPitch();
}
void SetPitch()
{
this -> pitch = Memory::Read<float>(Memory::Read<DWORD>(baseAddress + 0x110) + 0x20);
}
float GetPitch()
{
return this -> pitch;
}
void SetTargetGuid()
{
this -> targetGuid = Memory::Read<INT64>(descriptorFields + targetGuidOffset);
}
INT64 GetTargetGuid()
{
return this -> targetGuid;
}
void SetLevel()
{
this -> level = Memory::Read<int>(descriptorFields + levelOffset);
}
int GetLevel()
{
return this -> level;
}
void SetCurrentHealth()
{
this -> currentHealth = Memory::Read<int>(descriptorFields + currentHealthOffset);
}
int GetCurrentHealth()
{
return this -> currentHealth;
}
void SetMaxHealth()
{
this -> maxHealth = Memory::Read<int>(descriptorFields + maxHealthOffset);
}
int GetMaxHealth()
{
return this -> maxHealth;
}
void SetCurrentMana()
{
this -> currentMana = Memory::Read<int>(descriptorFields + currentManaOffset);
}
int GetCurrentMana()
{
return this -> currentMana;
}
void SetMaxMana()
{
this -> maxMana = Memory::Read<int>(descriptorFields + maxManaOffset);
}
int GetMaxMana()
{
return this -> maxMana;
}
void SetHealthPercent()
{
double percentage = static_cast<double>(currentHealth) / static_cast<double>(maxHealth);
percentage = percentage * 100;
this -> healthPercent = static_cast<int>(floor(percentage));
}
int GetHealthPercent()
{
return this -> healthPercent;
}
virtual void SetName()
{
}
//Other Public Identifiers:
INT64 targetGuid;
int level;
int maxHealth;
int currentHealth;
int healthPercent;
int currentMana;
int maxMana;
float pitch;
string name;
protected:
const static DWORD levelOffset = 0x35 * 4;
const static DWORD currentHealthOffset = 0x17 * 4;
const static DWORD maxHealthOffset = 0x1F * 4;
const static DWORD currentManaOffset = 0x18 * 4;
const static DWORD maxManaOffset = 0x20 * 4;
const static DWORD targetGuidOffset = 0x12 * 4;
};
class oPlayer : public Creature
{
public:
oPlayer(DWORD baseAddress) : Creature(baseAddress)
{
RefreshFields();
}
void RefreshFields()
{
SetCurrentRage();
SetCurrentEnergy();
SetMaxEnergy();
}
void SetCurrentRage()
{
int rageTemp = Memory::Read<int>(descriptorFields + currentRageOffset);
this -> currentRage = static_cast<int>(floor(static_cast<double>(rageTemp) / 10));
}
int GetCurrentRage()
{
return this -> currentRage;
}
int GetMaxRage()
{
return 100;
}
void SetCurrentEnergy()
{
this -> currentEnergy = Memory::Read<int>(descriptorFields + currentEnergyOffset);
}
int GetCurrentEnergy()
{
return this -> currentEnergy;
}
void SetMaxEnergy()
{
this -> maxEnergy = Memory::Read<int>(descriptorFields + maxEnergyOffset);
}
int GetMaxEnergy()
{
return this -> maxEnergy;
}
void SetName()
{
}
//Other Public Identifiers
int maxEnergy;
int currentEnergy;
int maxRage;
int currentRage;
protected:
const static DWORD currentRageOffset = 0x19 * 4;
const static DWORD currentEnergyOffset = 0x1B * 4;
const static DWORD maxEnergyOffset = 0x23 * 4;
};
class oNpc : public Creature
{
public:
oNpc(DWORD baseAddress) : Creature(baseAddress)
{
RefreshFields();
}
void RefreshFields()
{
SetName();
SetAttackingGuid();
SetSummonedBy();
}
void SetName()
{
}
string GetName()
{
}
void SetAttackingGuid()
{
this -> attackingGuid = Memory::Read<INT64>(baseAddress + attackingGuidOffset);
}
INT64 GetAttackingGuid()
{
return this -> attackingGuid;
}
void SetSummonedBy()
{
this -> summonedBy = Memory::Read<INT64>(descriptorFields + summonedByOffset);
}
INT64 GetSummonedBy()
{
return this -> summonedBy;
}
/*int GetAggroRadius(CreatureObject LocalPlayer)
{
// if they are the same level as us, the aggro radius is roughly 20 yards
int AggroRadius = 20;
// aggro radius varies with level difference at a rate of roughly 1 yard/level
if (LocalPlayer.Level > Level)
AggroRadius -= (int)BotControl.DifferenceBetween(LocalPlayer.Level, Level);
if (LocalPlayer.Level < Level)
AggroRadius += (int)BotControl.DifferenceBetween(LocalPlayer.Level, Level);
if (AggroRadius < 5)
AggroRadius = 5;
AggroRadius += 3; // give us a bit of leeway
return AggroRadius;
}*/
//Other Public Identifiers
INT64 summonedBy;
INT64 attackingGuid;
protected:
const static INT64 summonedByOffset = 0xE * 4;
const static INT64 attackingGuidOffset = 0x0A38;
};
class oGame : public WowObject
{
public:
oGame(DWORD baseAddress) : WowObject(baseAddress)
{
}
void SetName()
{
}
string GetName()
{
}
void SetXPosition()
{
this -> xPosition = Memory::Read<float>(descriptorFields + gameObject_XPositionOffset);
}
void SetYPosition()
{
this -> yPosition = Memory::Read<float>(descriptorFields + gameObject_YPositionOffset);
}
void SetZPosition()
{
this -> zPosition = Memory::Read<float>(descriptorFields + gameObject_ZPositionOffset);
}
void SetDisplayId()
{
this -> displayId = Memory::Read<int>(descriptorFields + displayIdOffset);
}
int GetDisplayId()
{
return this -> displayId;
}
string name;
protected:
const static DWORD gameObject_XPositionOffset = 0x10 * 4;
const static DWORD gameObject_YPositionOffset = 0x11 * 4;
const static DWORD gameObject_ZPositionOffset = 0x12 * 4;
const static DWORD displayIdOffset = 0x8 * 4;
private:
int displayId;
};
class oDynamic : public WowObject
{
public:
oDynamic(DWORD baseAddress) : WowObject(baseAddress)
{
}
void SetXPosition()
{
this -> xPosition = Memory::Read<float>(descriptorFields + dynamicObject_XPositionOffset);
}
void SetYPosition()
{
this -> yPosition = Memory::Read<float>(descriptorFields + dynamicObject_YPositionOffset);
}
void SetZPosition()
{
this -> zPosition = Memory::Read<float>(descriptorFields + dynamicObject_ZPositionOffset);
}
protected:
const static DWORD dynamicObject_XPositionOffset = 0xB * 4;
const static DWORD dynamicObject_YPositionOffset = 0xC * 4;
const static DWORD dynamicObject_ZPositionOffset = 0xD * 4;
};
It's messy, I wanted to keep members private but ended up getting extremely sloppy and throwing them into the public. Easy fixed Copy/Pasta in any case.
Below:
I included these functions in the object manager calling them immediately after populating the lists. This makes a very basic object dumper (Without names).
Code:
void PrintoNpcToScreen(list<oNpc> oNpcList)
{
list<oNpc>::iterator i;
for (i = oNpcList.begin(); i != oNpcList.end(); i++)
{
cout << "Name: " << (*i).name;
cout << " Type: " << (*i).type << "\n";
cout << "x: " << (*i).xPosition << " y: " << (*i).yPosition << " z: " << (*i).zPosition << "\n";
cout << endl;
}
}
void PrintoGameToScreen(list<oGame> oGameList)
{
list<oGame>::iterator i;
for (i = oGameList.begin(); i != oGameList.end(); i++)
{
cout << "Name: " << (*i).name;
cout << " Type: " << (*i).type << "\n";
cout << "x: " << (*i).xPosition << " y: " << (*i).yPosition << " z: " << (*i).zPosition << "\n";
cout << endl;
}
}
void PrintoPlayerToScreen(list<oPlayer> oPlayerList)
{
list<oPlayer>::iterator i;
for (i = oPlayerList.begin(); i != oPlayerList.end(); i++)
{
cout << "Name: " << (*i).name;
cout << " Type: " << (*i).type << "\n";
cout << "x: " << (*i).xPosition << " y: " << (*i).yPosition << " z: " << (*i).zPosition << "\n";
cout << endl;
}
}
i know this is sloppy code and all criticism is welcome. I hope this can still be of use to somebody.
Again. All credit goes to the OP.