Ловим урон с Мемхаком

» опубликован
» Способ реализации: Jass
» Тип: Алгоритм
» Версия игры: 1.26\1.27
Собственно обновленный детект типов урона и атаки от DracoL1ch, который позволяет отловить все параметры урона, такие как атака ближнего\дальнего боя, тип атаки, тип урона, изначальный урон без учета резистов.
Для работы этого хака нужна последняя версия мемхака, который приложен ниже.
» сам хак

globals
	integer DamageIncrementer = 0
	integer array DamageAttackTypes
	integer array DamageDamageTypes
	real array DamageValues
	//прочие переменные есть в самом мемхаке
endglobals

function TestMissileHandlerWorker takes nothing returns nothing
    local integer offset=RMem(pDamageEspData)
    local integer target=RMem(pDamageTarget)
   
    if offset>0 then
        set offset=Memory[offset/4+2]//RMem(offset+0x8)
    endif
    if DamageIncrementer>8000 then
        set DamageIncrementer=10
    endif
    set DamageIncrementer=DamageIncrementer+1
    //call BJDebugMsg("dmg event "+I2S(DamageIncrementer)+" source="+Id2String(RMem(target+0x30))+" val="+R2S(mI2R(Memory[offset/4+0x10/4])))
    if offset>0 then
        set DamageAttackTypes[DamageIncrementer]=Memory[offset/4+0x20/4]//RMem(offset+0x20)
        set DamageDamageTypes[DamageIncrementer]=Memory[offset/4+0x14/4]//RMem(offset+0x14)
        set DamageValues[DamageIncrementer]=mI2R(Memory[offset/4+0x10/4])//RMem(offset+0x10))
        //call ExecuteFunc("PreDamageWorker")
    endif
endfunction
 
function TestMissileHandler takes nothing returns nothing
    call TestMissileHandlerWorker( )
//  local integer offset=RMem(RMem(pDamageEspData)+0x8)
//  if DamageIncrementer>8000 then
//      set DamageIncrementer=10
//  endif
//  set DamageIncrementer=DamageIncrementer+1
//  set DamageValues[DamageIncrementer]=mI2R(RMem(offset+0x10))
//  set DamageAttackTypes[DamageIncrementer]=RMem(offset+0x20)
//  set DamageDamageTypes[DamageIncrementer]=RMem(offset+0x14)
//  call TestIfdamageHookCrash()
//  return
//  call ExecuteFunc("PreDamageWorker")
    //Barrage missiles always have 0x8 == 0x10000000
//  call BJDebugMsg("Target" + Int2Hex(RMem(pDamageTarget)))
//  call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0x0)))//source
//  call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0x8)))//proj or link onto something
// 
//  call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0xC)))//0x101 == ranged, 0x100 == melee
//  call BJDebugMsg("Damage:" + R2S(mI2R(RMem(RMem(RMem(pDamageEspData)+0x8)+0x10))))//damage val
endfunction
 
function InitializeDamageHandler takes integer pTriggerHandle returns nothing
    local integer pUnitDamageHandler = pUnitVtable+0x120
    local integer oldprotection = ChangeOffsetProtection(pUnitDamageHandler,4,0x40)
    set Memory[pReservedMemoryForDamageHandler/4+0]=0xB890C08B
    set Memory[pReservedMemoryForDamageHandler/4+1]=pDamageTarget
    set Memory[pReservedMemoryForDamageHandler/4+2]=0xB8900889
    set Memory[pReservedMemoryForDamageHandler/4+3]=pDamageEspData
    set Memory[pReservedMemoryForDamageHandler/4+4]=0x68602089
    set Memory[pReservedMemoryForDamageHandler/4+5]=pTriggerHandle
    set Memory[pReservedMemoryForDamageHandler/4+6]=0xB890C08B
    set Memory[pReservedMemoryForDamageHandler/4+7]=pTriggerExecute
    set Memory[pReservedMemoryForDamageHandler/4+8]=0xC483D0FF
    set Memory[pReservedMemoryForDamageHandler/4+9]=0xB8906104
    set Memory[pReservedMemoryForDamageHandler/4+10]=pRealUnitDamageHandler
    set Memory[pReservedMemoryForDamageHandler/4+11]=0xCCCCE0FF
 
     //call BJDebugMsg(Int2Hex(pReservedMemoryForDamageHandler))
   
    call WMem(pUnitDamageHandler,pReservedMemoryForDamageHandler)
   
    set oldprotection = ChangeOffsetProtection(pUnitDamageHandler,4,oldprotection)
   
endfunction
» Инициализация хака
	set t=CreateTrigger()
    call TriggerAddAction(t,function TestMissileHandler)
    call InitializeDamageHandler(GetHandleId(t))
	//далее уже делаем что хотим в функции TestMissileHandler )
А вот еще одна полезная функция:
» Проверка типа урона
Кто уже скачал систему заметил, что тип атаки это числа от 0 до 6, каждый тип имеет свое число, задается через ConvertDamageType(N)
Но как же быть с типом урона, система выводит на экран какие то числа от 0 до нескольких тысяч, которые не похожи на damagetype, как же их превратить в тип урона, если ConvertDamageType() возвращает null с этих чисел? А вот как, код приведенный ниже поможет вам сопоставить константы типов урона и выведенные системой данные:
function DT2DT takes integer k returns integer
    local integer i = 1
    if k == 0 then
        return 0
    endif
    loop
        exitwhen k / 2 <= 1
        set i = i + 1
        set k = k / 2
    endloop
    return i
endfunction

	//пример использования:
	ConvertDamageType(DT2DT(dmgTypeHex))==DAMAGE_TYPE_FIRE


Просмотров: 2 198

Это сообщение удалено
quq_CCCP #2 - 9 месяцев назад 0
Надо же, нет ни 1 вопроса, у всех все работает. Какая радость.
Bornikkeny #3 - 9 месяцев назад 0
У меня куча вопросов, но пока что у меня 04:08 по времени и я думаю,, что не стоит на утро тестить :D
quq_CCCP #4 - 9 месяцев назад 0
Bornikkeny, ну слушаю...
Ige #5 - 7 месяцев назад 0
Как с этим вообще можно разобраться?
Код в шапке и в примере(карте) разный. Более того, в карте такой бардак, что пока найдешь что-нибудь и поймешь за что это отвечает, можно состариться. Словом, жуть какая-то =)
  • зачем здесь используется массив? - это что-то связанное с дотой, т.е. для работоспособности он не требуется?
  • как получить юнитов (GetTriggerUnit() и GetEventDamageSource() возвращают null)?
Вроде бы есть target, но это integer => нужно что-то типа Int2Unit();
Я не сразу понял, что offset == источник урона (DamageSource), мб тогда изменить имя переменной?
  • если перезаписать значение урона до расчета брони, не будет ли проблем?
pro100master #6 - 7 месяцев назад 0
Ige, узнать цель и атакующий есть уже в мемхак переменная это
цель
call BJDebugMsg("Target" + Int2Hex(RMem(pDamageTarget)))
Атакующий
call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0x0)))//source
Ige #7 - 7 месяцев назад 0
pro100master, как с помощью этого получить юнита(ов)?
pro100master #8 - 7 месяцев назад 0
Ige, Тебе наверно рано еше такой делать, бери готовых библиотек. Как освоиш чуток. То поймеш =)
quq_CCCP #9 - 7 месяцев назад 0
Ige, смотрим кат Сам хак
Там сама наработка, это хук на событие внутри движка.
Собственно нам потребуется триггер, функцией InitializeDamageHandler мы лезим в структуру триггерна и ставим коверкаем его чтобы мы могли получать нужные нам данные.
Массив - дота код, рассчитан на то что юнитов получающих урон будет овер дофига как и кол-во инстансов урона, таким образом он гарантирует что при срабатывании 1 триггера, во время его потока, данные полученные с помощью функций не перезапишутся. Т.е представь что ты юзаешь GetTriggerUnit() в потоке триггера, первый раз оно вернет одного юнита, второй раз другое? Тебе оно надо, массив это вроде фикс этого эффекта.
В потоке триггера (в кондишине) ты получаешь всех кого хочешь, а значение урона берешь из глобалок, все ок?
Оффсет это офсет, не трогай чего не понимаешь -
Barrage missiles always have 0x8 == 0x10000000
call BJDebugMsg("Target" + Int2Hex(RMem(pDamageTarget))) адресс цели, не путать с хендлом и прочим говном, это адресс юнита в памяти игры, нужно для работы с адресом а не с юнитом.
call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0x0)))source адресс источника урона, тоже самое.
call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0x8)))proj or link onto something// адрес куда пишут флаги всякие орбы, или что то еще..

call BJDebugMsg(Int2Hex(RMem(RMem(RMem(pDamageEspData)+0x8)+0xC)))0x101 == ranged, 0x100 == melee адресс в котором хранится значение, 0x101, что означет что урон является уроном дальнего боя (UnitDamageTarget(a,b,100, false, true, null,null,null )), 0x100 урон от ближнего боя (UnitDamageTarget(a,b,100, true, false, null,null,null ))
call BJDebugMsg("Damage:" + R2S(mI2R(RMem(RMem(RMem(pDamageEspData)+0x8)+0x10))))damage val кол-во урона без учета брони, сколько было на момент успешного завершения снаряда или указанно в настройках способности которая нанесла урон.
Ige #10 - 7 месяцев назад 0
pro100master, очевидно, что RMem(pDamageTarget) возвращает адрес юнита, значит нужен некий "конвертер" (как я уже писал выше Int2Unit())
quq_CCCP #11 - 7 месяцев назад 0
Ige, зачем вам конвертор? Вы в кондишине триггера или экшине эти данные возьмете, нах вам лезть в DamageHandler?
Когда триггер сработал в условии триггер берешь GetTriggerUnit(), GetEventDamageSource() и так далее, тип урона берешь из глобалок. в глобалки данные пишутся перед срабатыванием условий и действий триггера.
pro100master #12 - 7 месяцев назад 0
Ige, конвентировано в Int2Hex есть же!
Ige, а знать GUI уже предоставлено стандартный ответ выше описали!!
quq_CCCP #13 - 7 месяцев назад 0
pro100master, дальше то что?
Нахрена вам там понадобился юнит?
pro100master, Мб я что то не понимаю, что собрались делать то?
Ige #14 - 7 месяцев назад 0
quq_CCCP, так в том и дело, что GetTriggerUnit(), GetEventDamageSource() возвращают null
quq_CCCP #15 - 7 месяцев назад 0
Ige, в потоке триггера...
Ige #16 - 7 месяцев назад 0
вот приблизительный пример того, что мне нужно
	integer Int2Unit
    integer l__Int2Unit

    function setInt2Unit takes integer i returns nothing
        set l__Int2Unit = i
        return //Prevents JassHelper from inlining this function
    endfunction

    function Typecast4 takes nothing returns nothing
        local unit Int2Unit
    endfunction

    function Int2Unit takes integer i returns unit
        call setInt2Unit(???) // вот что сюда писать?)
        return l__Int2Unit
    endfunction
pro100master #17 - 7 месяцев назад 0
function TestMissileHandler takes nothing returns nothing
    call TestMissileHandlerWorker( )


	тут берем адреса таргета и источика и работаем
endfunction
quq_CCCP #18 - 7 месяцев назад 0
Вот все работает...
pro100master, блин, я толкую сударю об одном, он о другом...
Нафиг забудь call TestMissileHandlerWorker( ) и ничего там не пиши, все далай в триггере, в этой функции просто идет записть значений в глобалки, все там больше нечего делать, ок?
прикреплены файлы
Ige #19 - 7 месяцев назад 0
Вроде бы откопал в доте, то что нужно. Проверю и отпишусь
    integer Int2Unit
    integer l__Int2Unit

    function setInt2Unit takes integer i returns nothing
        set l__Int2Unit = i
        return //Prevents JassHelper from inlining this function
    endfunction

    function Typecast4 takes nothing returns nothing
        local unit Int2Unit
    endfunction

    integer pGetUnitForAddress = 0
    function GetUnitForAddress takes integer addr returns integer // не знал какое имя дать -> дал первое, что пришло в голову)
        if pGetUnitForAddress == 0 then
            pGetUnitForAddress = GameDLL + 0x2DCC40
        endif

        return CallFastCallWith2Args(pGetUnitForAddress, addr, 0)
    endfunction

    function Int2Unit takes integer i returns unit
        call setInt2Unit(GetUnitForAddress(i))
        return l__Int2Unit
    endfunction
quq_CCCP #20 - 7 месяцев назад 0
Ige, Это не то что нужно, я тебе скинул код.
Все там работает и GetTriggerUnit() и GetEventDamageSource()
pro100master #21 - 7 месяцев назад 0
Инициализация ему надо еше и толковать мб???
Ige #22 - 7 месяцев назад 0
quq_CCCP, я, наверно, неправильно выразился. То что ты мне скинул - это совсем не то, что я имел ввиду. Минуту, я итоговый скрин сделаю.
quq_CCCP #23 - 7 месяцев назад 0
Ige, еще раз, чтобы отловить урон нужен триггер, с событием юнит получает урон.
К нему цепляется функия из мемхака и читает данные в памяти, записывая в глобалки, все
Ige #24 - 7 месяцев назад 0
прикреплены файлы
quq_CCCP #25 - 7 месяцев назад 0
Ты дальше работаешь с юнитами в триггере, ненадо никаких конвертов юнитов, не говоря о том что это медленно, CallFastCallWith2Args(pGetUnitForAddress, addr, 0) заставляет игру выполнить внутринний алгоритм и рассчитать нам хендл по адресу + туча паразитных действий, которые ненужны совершенно.
pro100master #26 - 7 месяцев назад 0
Ige, ну вот
quq_CCCP #27 - 7 месяцев назад 0
Ige, код мб юзер нам покажет, а ?
Ige #28 - 7 месяцев назад (отредактировано ) 0
quq_CCCP, суть было в том, что бы отловить урон ДО расчета брони

quq_CCCP, над кодом еще работаю
quq_CCCP #29 - 7 месяцев назад 0
Ты и так и так до брони его получаешь, лол. В глобалку пишется начальный урон.
pro100master #30 - 7 месяцев назад 0
quq_CCCP, но ведь иногда людям нужно изменить количество урона по своему формулу так что события получает урон уже нельзя заменить.... а внутри мемхак можно
Ige #31 - 7 месяцев назад 0
quq_CCCP, на скрине показан урон до расчета брони и после
50 -> 40
100 -> 35
51->41
quq_CCCP #32 - 7 месяцев назад 0
Ige, причем тут броня?
Чего за глупость, ты получаешь начальный урон до брони set DamageValues[DamageIncrementer]=mI2R(Memory[offset/4+0x10/4])//RMem(offset+0x10))
И GetEventDamage после, дальше в потоке триггера работай с юнитами как хочешь, зачем тебе адресса?
pro100master #33 - 7 месяцев назад 0
quq_CCCP, но есть проблема то что его нельзя изменить по своему всегда выходит 0 урон а если минус то 0.50 снимает стремно как то =)
Ige #34 - 7 месяцев назад 0
Ige:
quq_CCCP, суть было в том, что бы отловить урон ДО расчета брони
Сам сморозил глупость и сам повелся на нее -_- Хотел сказать не "отловить" урон, а "изменить" его.
Чем чреват подобный финт:
// чтение
DamageValues[DamageIncrementer]=mI2R(Memory[offset/4+0x10/4])
// запись (обратный процесс)
Memory[offset/4+0x10/4] = mI2R(newValue)
// либо так
WMem(offset+0x10, mI2R(newValue))
pro100master #35 - 7 месяцев назад 0
Ige, так нельзя делать его реальный число =) так как целое число надо возврашать в массив!!!
quq_CCCP #36 - 7 месяцев назад 0
Ige, нетак, фигню написал...
Методом тыка вам тут только фаталы ловить, нужен Cheat Engine и познание структуры триггеров, покуда у вас этого нету, можно не старатся, у драколича ушело на это больше года...
Пишите личу про смену урона, только он колупал и проверял это, возможно что урон вовсе не сменить с уровня jass.
pro100master, Нужно еще понимать как там устроена структура и где прилеплен код к событию...
pro100master #37 - 7 месяцев назад 0
call WMem(offset+0x10, положительное число) // будет сигналить урон 0.000
call WMem(offset+0x10, отрицательное число) // будет сигналить отрицательный урон 0.500

Дальше колдую с 0x10 машиный код 
quq_CCCP:
Ige, нетак, фигню написал...
Методом тыка вам тут только фаталы ловить, нужен Cheat Engine и познание структуры триггеров, покуда у вас этого нету, можно не старатся, у драколича ушело на это больше года...
Пишите личу про смену урона, только он колупал и проверял это, возможно что урон вовсе не сменить с уровня jass.
pro100master, Нужно еще понимать как там устроена структура и где прилеплен код к событию...
Он чета не в сети уже день даже на хайве молчит подождем =)
Ige #38 - 7 месяцев назад 0
quq_CCCP, пока нет какого-либо руководства, приходится все проверять эмпирическим методом.
Фигня или не фигня (хотя я склоняюсь как раз к первому варианту), только она пока что работает и без сбоев
прикреплены файлы
DracoL1ch #39 - 7 месяцев назад 2
function OnDamageReceivedHookWorker takes nothing returns nothing
	local integer offset=Memory[pDamageEspData/4]
	local integer target=Memory[pDamageTarget/4]
	local integer hu
	local real bonusdmg
	local real flatbonusdmg
	if offset>0 then
		set offset=Memory[offset/4+2]//RMem(offset+0x8)
	endif
	if DamageIncrementer>8000 then
		set DamageIncrementer=10
	endif
	set DamageIncrementer=DamageIncrementer+1
	set RaindropBeenActivated=false
	if offset>0 then
		set DamageAttackTypes[DamageIncrementer]=Memory[offset/4+0x20/4]//RMem(offset+0x20)
		set DamageDamageTypes[DamageIncrementer]=Memory[offset/4+0x14/4]//RMem(offset+0x14)
		set DamageValues[DamageIncrementer]=mI2R(Memory[offset/4+0x10/4])//RMem(offset+0x10))
		
		set tt_unit2=I2Unit(target)//tt_unit2 = target
		if DamageValues[DamageIncrementer]>0.1 then
			set tt_unit1=I2Unit(RMem(offset))//tt_unit1 == source
//			call echo(GetUnitName(tt_unit1)+" damages "+GetUnitName(tt_unit2)+" for "+R2S(DamageValues[DamageIncrementer]))
		endif
		if true then
			set bj_meleeNearestMineDist=RMaxBJ(DamageValues[DamageIncrementer] - 120.,1.)
			set bj_randomSubGroupChance=DamageValues[DamageIncrementer]-bj_meleeNearestMineDist
			call WMem(offset+0x10,mR2I(bj_meleeNearestMineDist))
			set DamageValues[DamageIncrementer]=bj_meleeNearestMineDist
		endif
	endif
endfunction
Элементарно, ватсон. По аналогии тому, как здесь я меняю урон, меняешь и тип урона, переписывая через WMem. просто вспомни, что там степени двойки должны быть, в типе атаки/урона, а не голые числа. ну а про отрицательные значения хз
pro100master #40 - 7 месяцев назад 0
DracoL1ch, отрицательный работает если способность было пройдено то лечит а чистый урон не идет прям крутой хил =)
Ige #41 - 7 месяцев назад 0
call WMem(offset+0x10,mR2I(bj_meleeNearestMineDist))
А вот это неожиданно!)
// либо так
WMem(offset+0x10, mI2R(newValue))
DracoL1ch:
просто вспомни, что там степени двойки должны быть, в типе атаки/урона, а не голые числа. ну а про отрицательные значения хз
Тип атаки,вроде бы имеет значения 0..6, т.е. без степени 2
	attackType[0] = "Заклинание"
	attackType[1] = "Обычная"
	attackType[2] = "Дальний бой"
	attackType[3] = "Артиллерия"
	attackType[4] = "Магическая"
	attackType[5] = "Сила Тьмы"
	attackType[6] = "Герой"

а еще стоит заметить, что источник урона это:
set tt_unit1=I2Unit(RMem(offset))//tt_unit1 == source
о чем я писал ранее
Я не сразу понял, что offset == источник урона (DamageSource)
DracoL1ch #42 - 7 месяцев назад 0
а, ну возможно. для типа урона точно нужна степень, тип атаки мне проверять не надобно было. ничего неожиданного не вижу в переписи, пару глобалок у близзов забрал, чтобы локалки не создавать
Graf_Men9999 #43 - 6 месяцев назад 0
DracoL1ch:
а, ну возможно. для типа урона точно нужна степень, тип атаки мне проверять не надобно было. ничего неожиданного не вижу в переписи, пару глобалок у близзов забрал, чтобы локалки не создавать
Воришка)