Originally Posted by
leo11173
While bnet deployed 1.03 patch we had some trouble getting attrib again via autoit. So we used that way because it was allready made. It's kinda faster but not realy convinient. If you get the new way of getting attrib easyly via autoit just drop me a pm with, or a quote where it's explained and we'll get ride off that dll.
I'm really not the open-source kind guy (never was) but I'm pretty sure that your life will be MUCH easier if you don't have to use external DLLs...
Btw the attribute reading is the same since 1.0.0 - your problem is probably that the most-known autoit library ([AutoIt] Diablo 3 Click To Move, Interaction, Actor Handling. (Version 2)) has a ton of bugs and the IterateActorAtribs function (which is the reference for 1/2 of the beginners in the non-existing D3 scene) doesn't even try to load the linked lists in the attribute groups. This is the reason of the "instability" of the attribute reading...
So, here is a little snippet made for you:
Code:
Global $acd_data_start_ofs = 0
Global $attrib_data_start_ofs = 0
Global $acd_structure_size = 0x2D0 ; 1.0.5
Global $acd_ofs__guid = 0x000 ; 1.0.5
Global $acd_ofs__attrib_group_id = 0x120 ; 1.0.5
Global $attrib_link_ofs__next = 0x000 ; 1.0.5
Global $attrib_link_ofs__id = 0x004 ; 1.0.5
Global $attrib_link_ofs__value = 0x008 ; 1.0.5
Func kjInitMemPartialForAttributeReadingOnly($ofs_ObjectManager)
Local $ObjectManagerBase = kjMemoryReadPtr($ofs_ObjectManager)
Local $ObjectManagerStorageOfs = $ObjectManagerBase + 0x794
Local $ObjectManagerStorageDataOfs = kjMemoryReadPtr($ObjectManagerStorageOfs + 0x0A8)
Local $ObjectManagerStorageLocalOfs = kjMemoryReadPtr($ObjectManagerStorageOfs + 0x1B8)
; ACD
Local $ObjManACDOffset = 0xD4
Local $a = kjMemoryReadPtr($ObjectManagerStorageOfs + $ObjManACDOffset)
Local $container_ofs = kjMemoryReadPtr($a)
Local $a = kjMemoryReadPtr($container_ofs + 0x148) ;container.List, double pointer
Global $acd_data_start_ofs = kjMemoryReadPtr($a) ;container.List
; actor attribs
Local $a = kjMemoryReadPtr($ObjectManagerStorageOfs + 0x0C8)
Local $container_ofs = kjMemoryReadPtr($a + 0x070)
Local $a = kjMemoryReadPtr($container_ofs + 0x148) ;container.List, double pointer
Global $attrib_data_start_ofs = kjMemoryReadPtr($a) ;container.List
Global $attrib_data_count_ofs = $container_ofs + 0x108 ;container.Count
EndFunc
Func kjGetActorAttributeFast($GUID, $Attrib, $req_mask, $default_value = -1)
$acd_index = BitAnd($GUID, 0xFFFF)
$acd_ofs = $acd_data_start_ofs + $acd_index * $acd_structure_size
$aguid = kjMemoryReadGeneric($acd_ofs + $acd_ofs__guid, 'int')
If ($aguid <> $GUID) Then Return $default_value
$attrib_group_id = kjMemoryReadGeneric($acd_ofs + $acd_ofs__attrib_group_id, 'int')
$attrib_group_index = BitAnd($attrib_group_id, 0xFFFF)
$group_ofs = $attrib_data_start_ofs + $attrib_group_index * $attrib_structure_size
$group_formula_ofs = kjMemoryReadGeneric($group_ofs + 0x010, 'ptr')
$group_formula_map_data_ofs = kjMemoryReadGeneric($group_formula_ofs + 0x008 + 0x000, 'ptr')
$mask = kjMemoryReadGeneric($group_formula_ofs + 0x418, 'int')
$full_id = BitOr($Attrib[0], BitShift($req_mask, -12))
$idxmask = BitXOR($full_id, BitShift($full_id, 16))
$idx = BitAnd($mask, $idxmask)
$link_root_ofs = $group_formula_map_data_ofs + ($idx * 4)
$link_ofs = kjMemoryReadGeneric($link_root_ofs, 'ptr')
$n = 0
While ($link_ofs <> 0x0)
$n += 1
$id = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__id, 'int')
If ($id = $full_id) Then
$value = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__value, $Attrib[1])
Return $value
EndIf
$link_ofs = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__next, 'ptr')
If ($n > 10) Then ExitLoop ; inifinite loop safety
WEnd
Return $default_value
EndFunc
Func kjEnumActorAttributeFastSampleCode($GUID)
$acd_index = BitAnd($GUID, 0xFFFF)
$acd_ofs = $acd_data_start_ofs + $acd_index * $acd_structure_size
$aguid = kjMemoryReadGeneric($acd_ofs + $acd_ofs__guid, 'int')
If ($aguid <> $GUID) Then Return
$attrib_group_id = kjMemoryReadGeneric($acd_ofs + $acd_ofs__attrib_group_id, 'int')
$attrib_group_index = BitAnd($attrib_group_id, 0xFFFF)
$group_ofs = $attrib_data_start_ofs + $attrib_group_index * $attrib_structure_size
$group_formula_ofs = kjMemoryReadGeneric($group_ofs + 0x010, 'ptr')
$group_formula_map_data_ofs = kjMemoryReadGeneric($group_formula_ofs + 0x008 + 0x000, 'ptr') ; formula's map's data
For $link_index = 0 To 255
$link_root_ofs = $group_formula_map_data_ofs + ($link_index * 4)
$link_ofs = kjMemoryReadGeneric($link_root_ofs, 'ptr')
$n = 0
While ($link_ofs <> 0x0)
$n += 1
$id = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__id, 'ptr')
$maskedid = StringRight($id, 3)
$mask = StringMid($id, 3, 5)
$value = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__value, 'int') ; or float
$link_ofs = kjMemoryReadGeneric($link_ofs + $attrib_link_ofs__next, 'ptr')
If ($n > 10) Then ExitLoop ; inifinite loop safety
WEnd
Next
EndFunc
You should replace my generic cached memory routines by the Nomad's ones - the result will be the same.
If you don't want a crash, then kjInitMemPartialForAttributeReadingOnly() has to be called many times in your code - not only once.
The reason is that the base offsets are changing sometimes even in-game (maybe some kind of garbage collection happening in D3).
The best way is to call it before you are starting every attribute read cycle (not before every attrib read, but every time you start reading attributes...)
kjEnumActorAttributeFastSampleCode() is just a dumb example to iterate through all attributes. Inside that you have to know the type of the current attrib (int vs float, I fixed 'int' in the example)
kjGetActorAttributeFast($GUID, $Attrib, $req_mask, $default_value = -1)
The GUID is the Actor/ACD ID, the Attrib is a [2] array like in the well-known toolkit.
The req_mask is a must have too (most stuff has 0xFFFFF)
For example the "Resistance_All" has a mask of 0xFFFFF, but the "Resistance"'s mask is 0 for Physical, 1 for Fire, 2 for Lightning an so on...
Wah, sorry for my english
EDIT: extra info: $ofs_ObjectManager = 0x1873414 (for 1.0.SIX!)