-
Contributor
EntiyList never ends, like it always had
Since last patch my entityList never returns 0, which means the first couple loops are correct, but then it gets "stuck" on same the adress and i had to change my code so it quits when EntityType is out of bounds, which looks and feels ugly..
Here is how ive been doing it all these years, for both x86 and x64:
Code:
/* Get first entity */
CurEntity = read(EntityMgrPTR + FirstEntityOffset);
/* Loop through Entity untill it returns 0*/
while (curEntity)
{
CurEntity = read(CurEntity + NextEntityOffset);
}
return list of objects;
And here is what i get now instead of 0
Code:
CurEntity: 0x0000000029B1E9F0, EntityType: 3 <-- Correct
CurEntity: 0x0000000041C3344C, EntityType: 5 <-- Correct
CurEntity: 0x0000000041C35184, EntityType: 5 <-- Correct
CurEntity: 0x0000000041C345D4, EntityType: 5 <-- Correct
CurEntity: 0x000000002EF40054, EntityType: 4 <-- Correct
CurEntity: 0x0000000041C33FFC, EntityType: 3 <-- Correct
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
CurEntity: 0x00000000002565A9, EntityType: 33 <--- Incorrect
What could i do wrong?
/TT
-
Break when entity pointer is not aligned to 4 bytes -- if (CurEntity % 4 != 0) break;
-
Contributor
I tried that but the pointers are now all the same length ?!, and after a wow restart from 64 to 32 bit it works with my original code...
Code:
0x32F01030
0x2CA148AC
0x10A04B4D
0x0A115984
0x00000000
and then i switched back to 64 bit, and guess what
Code:
0x00000000410AD440
0x0000000041082280
0x0000000041092528
0x00000000262850E9
0x0000000000000000
What could cause a thing like this? i cannot seem to re-produce it anymore
/TT
-
Contributor
Well a new day with more code to write and the same "bug i assume" is happening, i cannot for my life figure out what it is, now i have a better fallback than before though. -- if CurEntity == PrevEntity break; but this still does not float my boat and rub me in the right direction
-
Established Member
The client does something like this - you should not skip the other condition because the first one seems to be enough
Code:
while (obj && !(obj & 1))
{
//stuff
}
-
Post Thanks / Like - 1 Thanks
natt_ (1 members gave Thanks to shauren for this useful post)
-
Tested old external code and works still. Use a hash set and add each entity to it / continue if the hash set contains the entity if you want to do mega overkill sanity check.
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
}
CurrentManager struct is on TOMS_RUS github ObjMgr test page.
-
Post Thanks / Like - 2 Thanks
-
Contributor
The bitWiseAnd operation together with my old method made it work, thank you for making it clear to me 
/TT