-
Active Member
Looping through object manager crash
Good evening. Don't know how to write correctly the exit condition from looping.
PHP Code:
// Win 7.1.0.22996 x64
public const uint Entity = 0x1602B20;
public const uint Entity_first = 0x18;
//....
[StructLayout(LayoutKind.Explicit)]
public unsafe struct CG_Object
{
[FieldOffset(0x10)]
public ObjectDescriptor* Descriptors;
[FieldOffset(0x20)]
public uint EntitiType;
[FieldOffset(0x70)]
public IntPtr NextEntity;
}
PHP Code:
public static unsafe IntPtr EntityList { get { return new IntPtr(*(long*)(Memory._baseAddress + (int)Offsets.Entity)); } }
public static unsafe IntPtr EntityFirst { get { return new IntPtr(*(long*)(EntityList + (int)Offsets.Entity_first)); } }
public static IntPtr GetObjectByGuid(Guid guid)
{
IntPtr pointer = EntityFirst;
while (pointer != IntPtr.Zero)
{
WoWObject wowObject = new WoWObject(pointer);
if (wowObject.Guid == guid) return pointer;
else pointer = wowObject.NextEntity;
}
return IntPtr.Zero;
}
This search is working, but, over time, the program crashes, because the last wowObject.NextEntity refers to does not need a value.
When was the last wowObject.NextEntity refers to 0x0, then everything is fine.
What you need to add to lopping always worked, under any circumstances?
Last edited by zdohdds; 11-27-2016 at 06:13 AM.
-
If you write out the entity pointers as bits you'll see something like this.
Code:
...
1011000101011110010001010010100
1011000101011110100000010101000
1011000101011110101111010111100
1011000101011110111110011010000
1011000101011111001101011100100
1011000101011111011100011111000
1011000101011111101011100001100
1011000101011111111010100100000
1011000101100000001001100110100
1011000101100000011000101001000
1011000101100000100111101011100
1011000101100000110110101110000
1011000101100001000101110000100
1010001111110000011000001110000
1011000101100001110010111000000
1010010010001001100011010010100
1011000101100011011100001001100
1010010010001000110111100011100
1010010010000111100000000101100
1011000101100010011111111111100
1010010010001000001011110100100
1011000101100011111010001110100
1010001111110000010100101001000
1011000101100010010000111101000
1011000101100001010100110011000
1011000101100010111110000100100
0000101011110000001000100100101 ← entity pointer that is causing the crash.
Do you see something special about the last entity pointer?
Last edited by MurderBurger; 11-27-2016 at 07:41 AM.
-
Post Thanks / Like - 1 Thanks
zdohdds (1 members gave Thanks to MurderBurger for this useful post)
-
Active Member
Originally Posted by
MurderBurger
If you write out the entity pointers as bits you'll see something like this.
Code:
...
1011000101011110010001010010100
1011000101011110100000010101000
1011000101011110101111010111100
1011000101011110111110011010000
1011000101011111001101011100100
1011000101011111011100011111000
1011000101011111101011100001100
1011000101011111111010100100000
1011000101100000001001100110100
1011000101100000011000101001000
1011000101100000100111101011100
1011000101100000110110101110000
1011000101100001000101110000100
1010001111110000011000001110000
1011000101100001110010111000000
1010010010001001100011010010100
1011000101100011011100001001100
1010010010001000110111100011100
1010010010000111100000000101100
1011000101100010011111111111100
1010010010001000001011110100100
1011000101100011111010001110100
1010001111110000010100101001000
1011000101100010010000111101000
1011000101100001010100110011000
1011000101100010111110000100100
0000101011110000001000100100101 ← entity pointer that is causing the crash.
Do you see something special about the last entity pointer?
Thanks for the quick response. Yes, I know about the first bit, but if I write this condition, it finds nothing, even TargetGUID.
PHP Code:
while ((pointer != IntPtr.Zero) && (pointer.ToInt64() & 1 == 0))
right? i don't know how to right to do for bits =)
Last edited by zdohdds; 11-27-2016 at 09:12 AM.
-
This is how I always did it externally, should still work fine with updated pointers.
Code:
/// <summary>
/// A static class to handle creating a list of entites containing the <see cref="WowObjectData" /> structure.
/// </summary>
public static class EntityList
{
#region Properties
/// <summary>
/// Collects a dictonary of current entitie with the guid as the key.
/// </summary>
public static Dictionary<WowGuid, WowObject> EntitiesAsDictionary
{
get
{
var woWObjects = new Dictionary<WowGuid, WowObject>();
CollectEntities(GetFirstObject(), woWObjects);
return woWObjects;
}
}
/// <summary>
/// A collection of current entities.
/// </summary>
public static IEnumerable<WowObject> Entities => EntitiesAsDictionary.Values.ToList();
#endregion
#region Methods
/// <summary>
/// Gets the pointer to the first object in the list.
/// </summary>
/// <returns></returns>
private static IntPtr GetFirstObject()
{
var mgr = Wow64.CurrentManager;
return mgr.VisibleObjects.m_fulllist.baseClass.m_terminator.m_next;
}
/// <summary>
/// Gets the pointer to the next object in the list.
/// </summary>
/// <param name="current">The current objects pointer.</param>
/// <returns>SetObjectManager pointer to the next object.</returns>
private static IntPtr GetNextObjectFrom(IntPtr current)
{
var mgr = Wow64.CurrentManager;
return Wow.Memory.Read<IntPtr>(current + mgr.VisibleObjects.m_fulllist.baseClass.m_linkoffset + IntPtr.Size);
}
/// <summary>
/// Generates the dictonary of entities.
/// </summary>
/// <param name="firstObject">The address to the first object of the entity list.</param>
/// <param name="wowObjectDictionary">The dictonary to fill results with.</param>
[SuppressMessage("ReSharper", "SwitchStatementMissingSomeCases")]
private static void CollectEntities(IntPtr firstObject, IDictionary<WowGuid, WowObject> wowObjectDictionary)
{
var current = firstObject;
while (((current.ToInt64() & 1) == 0) && current != IntPtr.Zero)
{
var type = (WoWObjectType) Wow.Memory.Read<int>(current + WowOffsets.EntityList.Type);
switch (type)
{
case WoWObjectType.Item:
AddTo(wowObjectDictionary, new WowItem(current));
break;
case WoWObjectType.Container:
AddTo(wowObjectDictionary, new WowContainer(current));
break;
case WoWObjectType.Unit:
AddTo(wowObjectDictionary, new WowUnit(current));
break;
case WoWObjectType.Player:
AddTo(wowObjectDictionary, new WowPlayer(current));
break;
case WoWObjectType.GameObject:
AddTo(wowObjectDictionary, new WowGameObject(current));
break;
case WoWObjectType.Corpse:
AddTo(wowObjectDictionary, new WowCorpse(current));
break;
default:
AddTo(wowObjectDictionary, new WowObject(current));
break;
}
current = GetNextObjectFrom(current);
}
}
private static void AddTo(IDictionary<WowGuid, WowObject> wowObjects, WowObject wowObject)
{
wowObjects.Add(wowObject.Guid, wowObject);
}
#endregion
}
-
Post Thanks / Like - 2 Thanks
zdohdds,
Alfalfa (2 members gave Thanks to lolp1 for this useful post)
-
Active Member