-
Member
11.0.7.58162 ObjectMgr changes
Code:
// 4C 8B 3D ?? ?? ?? 02 33 F6 33 ED ?? 44 24 44 00 00 00 00 45 33 E4
var entityArrayPointer = process.Memory.Read<IntPtr>(objManagerAddress + 0x8);
var entityArrayCount = process.Memory.Read<uint>(objManagerAddress + 0x10);
for (int i = 0; i < entityArrayCount; ++i)
{
var entityBuilderPtr = process.Memory.Read<IntPtr>(entityArrayPointer + i * 8);
var index = process.Memory.Read<uint>(entityBuilderPtr + 0x10);
var entity_ptr = process.Memory.Read<IntPtr>(entityBuilderPtr + 0x28);
var objType = (ObjectType)process.Memory.Read<byte>(entity_ptr + 0x8);
var guidLow = process.Memory.Read<ulong>(entityBuilderPtr + 0x18);
var guidHigh = process.Memory.Read<ulong>(entityBuilderPtr + 0x18+ 0x8);
WowGuid128 guid = new WowGuid128(guidLow, guidHigh);
// ... read objects fields
}
Here's what I got so far for objectmgr changes. Seems similar to http:///forums/world-of-warcraft/wor...r-changes.html
Sometimes I can't access some objects for example reading targetguid will result in null in objectmgr, Any ideas?
-
Member
Originally Posted by
810810810
Code:
// 4C 8B 3D ?? ?? ?? 02 33 F6 33 ED ?? 44 24 44 00 00 00 00 45 33 E4
var entityArrayPointer = process.Memory.Read<IntPtr>(objManagerAddress + 0x8);
var entityArrayCount = process.Memory.Read<uint>(objManagerAddress + 0x10);
for (int i = 0; i < entityArrayCount; ++i)
{
var entityBuilderPtr = process.Memory.Read<IntPtr>(entityArrayPointer + i * 8);
var index = process.Memory.Read<uint>(entityBuilderPtr + 0x10);
var entity_ptr = process.Memory.Read<IntPtr>(entityBuilderPtr + 0x28);
var objType = (ObjectType)process.Memory.Read<byte>(entity_ptr + 0x8);
var guidLow = process.Memory.Read<ulong>(entityBuilderPtr + 0x18);
var guidHigh = process.Memory.Read<ulong>(entityBuilderPtr + 0x18+ 0x8);
WowGuid128 guid = new WowGuid128(guidLow, guidHigh);
// ... read objects fields
}
Here's what I got so far for objectmgr changes. Seems similar to
Site not installed - OVHcloud
Sometimes I can't access some objects for example reading targetguid will result in null in objectmgr, Any ideas?
I can confirm what you said, It looks like you can see the index of each entity now (in order - 0 to number of elements - 1) and based on my observations, the highest index + 1 == number of elements, which probably means we won't see those entity buckets, while iterating through objects with this method.
-
Post Thanks / Like - 1 Thanks
hb123220 (1 members gave Thanks to goblin2kx for this useful post)
-
Active Member
Fixed based on classic thread:
Code:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct EntityHashEntry
{
public Int128 Guid;
public long EntityIndex;
public long Hash
=> EntityIndex >> 54;
public long Index
=> EntityIndex & 0x3FFFFFFF;
public override string ToString()
{
return $"{EntityIndex} {Hash} {Index} {Guid}";
}
}
var entityArrayPointer = process.Memory.Read<IntPtr>(objManagerAddress + 0x8);
var entityArrayCount = process.Memory.Read<uint>(objManagerAddress + 0x10);
hashArrayMaximum = process.Memory.Read<uint>(objManagerAddress + 0x40);
hashArrayPointer = process.Memory.Read<IntPtr>(objManagerAddress + 0x48);
hashArrayCount = process.Memory.Read<uint>(objManagerAddress + 0x50);
for ( int i = 0; i < hashArrayMaximum; ++i)
{
var result = process.Memory.Read<EntityHashEntry>(hashArrayPointer + ((int)i * Marshal.SizeOf<EntityHashEntry>()));
if (result.Guid.IsValid() && !result.Guid.IsEmpty())
{
if (result.Index > 0)
{
var entityBuilderPtr = process.Memory.Read<IntPtr>(entityArrayPointer + (int)result.Index * 8);
//Trace.WriteLine($"[{i}]: 0x{entityBuilderPtr.ToString("X")}");
var entity_ptr = process.Memory.Read<IntPtr>(entityBuilderPtr + 0x20 + 8);
var objType = (ObjectType)process.Memory.Read<byte>(entity_ptr + 0x8);
var guidLow = process.Memory.Read<ulong>(entityBuilderPtr + 0x10 + 0x8);
var guidHigh = process.Memory.Read<ulong>(entityBuilderPtr + 0x10 + 0x8 + 0x8);
WowGuid128 guid = new WowGuid128(guidLow, guidHigh);
-
Post Thanks / Like - 3 Thanks
-
Active Member
Looks like the code to lookup the entityindex from a guid is at 0x142061A20 in 11.0.7.58328. This is probably the most efficient way to get the object from the guid. so then looking up a wow object struct is
Code:
struct om_obj *
get_obj(WOWGUID guid) {
int64_t eid;
GetEntityIndexFromGUID(&eid, &guid);
if (eid == 0) return NULL;
struct EntityRecord *ent = (*ps_curMgr)->entities[eid & 0x3fffffff];
return ent->obj;
}
Last edited by thateuler; 01-09-2025 at 01:01 AM.
-
Active Member
Originally Posted by
thateuler
Looks like the code to lookup the entityindex from a guid is at 0x142061A20 in 11.0.7.58328. This is probably the most efficient way to get the object from the guid. so then looking up a wow object struct is
i'm trying to convert that nice function to c# memory read.
i get mixed results like 50% correct and 50% zero.
someone can spot the error?
Code:
guid2entity(WowGuid g) {
k2 = a2aa033b * g.HI
k1 = d6d018f5 * g.LOW
hashArray_pos = (k1 + k2) % hashArrayMaximum
hash = MemoryReadStruct <Hash> ( hashArrayPointer + hashArray_pos * 0x18 )
entityArray_pos = hash.index & 0x3FFFFFFF
entity_ptr = MemoryReadLong ( entityArrayPointer + entityArray_pos * 8 )
entity = MemoryReadStruct <Entity> entity_ptr
* thx to thateuler, it was easy to fix:
Code:
while (hashArray_pos > 0 && hashArray_pos < hashArrayMaximum) {
hash = MemoryReadStruct <Hash> ( hashArrayPointer + hashArray_pos * 0x18 )
if (hash.guid == g) break;
hashArray_pos = (hashArray_pos + 1) % hashArrayMaximum;
}
Last edited by evil2; 01-29-2025 at 08:49 PM.
-
Active Member
This is my understanding of how it works. Caveat emptor.
Wow changed the om hash table from using separate chaining for collision resolution to open addressing with linear probing. The wikipedia article on hash tables is good. `hashArray_pos` is where to start searching the circular array. Terminate the search when you've gone through the entire array or when you hit the terminator. If you hit a guid w/ 0,0 you definately need to keep searching.
The terminator condition is: (this is the part i'm not 100% sure about.)
Code:
if (om->using_41_terminator && om->handles[ix].guid.low == 1 && om->handles[ix].guid.high == 0x400000000000000)
break;
I'm using this struct for `s_curMgr`.
Code:
struct objMgr {
// 11.0.7.58238 - 0x1a70 bytes
int64_t entitiesmax; /* 0x00 - 0x08 */
struct EntityRecord **entities; /* 0x08 - 0x10 */
int64_t nentities; /* 0x10 - 0x18 */
int64_t f1; /* 0x18 - 0x20 */
float fl1; /* 0x20 - 0x24 */
char pad2[0x1c]; /* 0x24 - 0x40 */
int64_t handlesmax; /* 0x40 - 0x48 */
struct EntityHandle *handles; /* 0x48 - 0x50 */
int64_t nhandles; /* 0x50 - 0x58 */
uint64_t using_41_terminator; /* 0x58 - 0x60 */
uint64_t pad3; /* 0x60 - 0x68 */
struct EntityCategory* categories; /* 0x68 - 0x70 */
uint64_t end[0x340]; /* 0x70 - 0x1a70 */
};
Oh. It might be more efficient to end the search once you've traversed nhandles valid guids, rather than the whole array. Assuming that the common case is fewer objects than array entries.
Last edited by thateuler; 01-24-2025 at 10:39 AM.
-
Post Thanks / Like - 1 Thanks
evil2 (1 members gave Thanks to thateuler for this useful post)