imaginary Опубликовано 18 февраля, 2018 Поделиться Опубликовано 18 февраля, 2018 (изменено) Terraria лицензия, потому смещения и адреса на репаках могут отличатся. Спойлер Здесь рассказывается как создать коллизию (просчет столкновений) между игроком и какими либо объектами в двумерном пространстве, без проверок на вталкивание в стену например. Суть заключается в том, что при создании такого скрипта персонаж не сможет пройти через существ, а они через персонажа. Скрипт в данной теме может быть сложным запутанным и скорее всего можно было сделать намного проще. Но главное, он работает. Для начала, нам нужно найти все необходимые адреса, как это сделать думаю понятно, адрес игрока можно найти по здоровью и сделать указатель на него. У меня получился вот такой указатель: Для вставки в скрипт: [[[Terraria.Main::DoDraw+375]]+08+[[Terraria.Main::DoDraw+37B]]*4] Принцип такого указателя: В Terraria.Main::DoDraw+375 в коде вписан адрес структуры с игроками Спойлер Таким образом в Terraria.Main::DoDraw+37B записан адрес хранящий номер активного игрока Спойлер Далее идет прибавление +08 до первого элемента, потом номер игрока умножается на 4, так как 1 адрес занимает 4 байта, вот и получается адрес игрока. Теперь необходимо найти структуру содержащую адреса существ, думаю это тоже понятно как найти, у меня вот такой адрес: Для вставки в скрипт: [[Terraria.Main::UpdateAudio+4F7]], по такому же принципу как и 2 адреса сверху. Теперь мы можем начать писать скрипт коллизии, суть скрипта в организации проверок координат касания углов персонажа и координат углов существа. Вот примерная схема этого действа: Спойлер Желтым изображены виртуальные полигоны коллизии, то есть промежутки в которых скрипт делает проверку, попадает ли точка игрока в них. Самый верхний желтый полигон используется для другой проверки, о которой будет сказано ниже. Итак, у нас есть адрес игрока, и предположительно адрес существа, для проверки существ нужно сделать цикл, перебирающий их и проверяющий координаты каждого: Спойлер //Вырезка из всего скрипта: StartCocleC: //Цикл перебора существ cmp ebx,#99 je back //Если проверены все нипы из структуры то закончить цикл add ebx,1 mov edx,[eax+ebx*4+08] //Адрес нпс cmp edx,esi //Проверка на совпадение с адресом существа для которого делается коллизия je StartCocleC cmp [edx+18],1 //Проверка на активность, если тут 1, то обьект существует, 0 - нет. jne StartCocleC Как тут указано, тут так же проверяется совпадение адреса существа в цикле с адресом существа для которого делается коллизия, это сделано для того что бы не было самоколлизии, то есть столкновения существа с самим собой. Так же имеется проверка на активность, есть ли вообще этот объект, или он отсутствует или отключен. Теперь, так как у нас имеется цикл перебора существ, мы можем сделать вычисление крайних точек существа. Координаты существа в игре - это его крайняя левая нижняя точка. Так же у существа есть размер, и исходя из этих данных игра центрирует точку координат перед выводом существа на позицию в карте. Координаты в структуре существа отображают именно крайнюю левую нижнюю точку. Делаем вычисления после цикла и записываем в метки координаты точек и расстояние: Спойлер //Вырезка из скрипта //Вычисления крайних точек и сторон по Х fild dword [edx+10] //Отношение правой нпс к левой игрока 2 (игрок справа) fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение fld dword [edx+20] //Загрузить координаты НПС fadd dword [CoordsTest+1C] //Получение координат правой стороны нпс fsub dword [esi+20] //Вычитание координат игрока из координат нпс fistp dword [CoordsTest] //Полученное число расстояния в метку fild dword [esi+10] //Отношение левой нпс к правой игрока 1 (игрок слева) fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение fld dword [esi+20] //Загрузить координаты игрока fadd dword [CoordsTest+1C] //Получение координат правой стороны игрока fsubr dword [edx+20] //Обратное вычитание координат игрока из коордиеат НПС fistp dword [CoordsTest+4] //Полученное число расстояния в метку //Вычисления крайних точек и сторон по Y fild dword [edx+14] //Отношение верхней нпс к нижней игрока 2 (игрок сверху) fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение fld dword [edx+24] //Загрузить координаты НПС fsub dword [CoordsTest+1C] //Получение координат верхней стороны нпс fsub dword [esi+24] //Вычитание координат игрока из координат нпс fistp dword [CoordsTest+8] //Полученное число расстояния в метку fild dword [esi+14] //Отношение верхней игрока к нижней нпс 1 (игрок снизу) fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение fld dword [esi+24] //Загрузить координаты игрока fsub dword [CoordsTest+1C] //Получение координат верхней стороны игрока fsubr dword [edx+24] //Обратное вычитание координат игрока из коордиеат НПС fistp dword [CoordsTest+C] //Полученное число расстояния в метку Теперь можно написать проверки. Данный код проверяет положение точек 1 существа, относительно другого, при этом проверяется как X так и Y, иначе коллизия будет размером во всю карту, а не только по размерам существа, из за этого в каждом блоке по 4 проверки. После проверок в метку записывается состояние персонажа, слева он, сверху, справа или снизу. Спойлер //Вырезка из скрипта //Проверки на положение игрока относительно существа TestCoordsP: cmp [CoordsTest],0 jl noRight cmp [CoordsTest],F //Виртуальный полигон коллизи (просто размер проверки) jg noRight cmp [CoordsTest+8],0 jl TestCoordsP2 jmp noRight TestCoordsP2: cmp [CoordsTest+C],0 jl noRight TestCoordsP3: mov byte ptr [CoordsTest+18],2 //Справа jmp WerhTest noRight: cmp [CoordsTest+4],0 jg WerhTest cmp [CoordsTest+4],#-15 //Виртуальный полигон коллизи (просто размер проверки) jl WerhTest cmp [CoordsTest+8],0 jl noRight2 jmp WerhTest noRight2: cmp [CoordsTest+C],0 jl WerhTest noRight3: mov byte ptr [CoordsTest+18],1 //Слева WerhTest: cmp [CoordsTest+8],0 jg SnizTest sub [CoordsTest+8],#3 cmp [CoordsTest+8],#-18 //Виртуальный полигон коллизи (просто размер проверки) jl SnizTest cmp [CoordsTest],0 jg WerhTest1 jmp SnizTest WerhTest1: cmp [CoordsTest+4],0 jg SnizTest WerhTest2: mov byte ptr [CoordsTest+19],2 //Сверху SnizTest: cmp [CoordsTest+C],0 jl ParamPrim cmp [CoordsTest+C],F //Виртуальный полигон коллизи (просто размер проверки) jg ParamPrim cmp [CoordsTest],0 jg SnizTest1 jmp ParamPrim SnizTest1: cmp [CoordsTest+4],0 jg ParamPrim SnizTest2: mov byte ptr [CoordsTest+19],1 //Снизу Следующий код делает проверку значения записанного в метку 1/2 1/2 и относительно этого выполняет действия с персонажем, убавляет его координаты или прибавляет на еденичку, создавая таким образом координатную коллизию, не пропускающую игрока сквозь существо. Спойлер //Вырезка из скрипта //Скрипт который выполняется если игрок касается какой либо стороны моба ParamPrim: cmp byte ptr [CoordsTest+19],2 //Сверху jne next1 fld1 //Загрузка еденички fsubr dword [esi+24] fstp dword [esi+24] //Проверка ускорения игрока fild dword [esi+2C] fistp dword [CoordsTest+1C] cmp [CoordsTest+1C],0 jg setzero jmp next1 setzero: mov [esi+2C],0 next1: cmp byte ptr [CoordsTest+18],2 //Справа jne next2 fld1 //Загрузка еденички fadd dword [esi+20] fstp dword [esi+20] fld1 //Загрузка еденички fsubr dword [edx+20] fstp dword [edx+20] next2: cmp byte ptr [CoordsTest+18],1 //Слева jne next3 fld1 //Загрузка еденички fsubr dword [esi+20] fstp dword [esi+20] fld1 //Загрузка еденички fadd dword [edx+20] fstp dword [edx+20] next3: cmp byte ptr [CoordsTest+19],1 //Снизу jne writeToV fld1 //Загрузка еденички fsubr dword [edx+24] fstp dword [edx+24] После выполнения данного скрипта, мы получаем коллизию, с учетом того, что если существо выше персонажа или наоборот, то персонаж или существо не будут вдавливать друг друга в землю, а вот толкнуть вверх могут. Теперь о том, зачем было использовать в скрипте полигон коллизии расположенный в самом верху. Если игрок попадает в тот полигон своей нижней стороной, то в таком случае делается проверка и в метку записывается значение: Спойлер writeToV: cmp [CoordsTest+8],0 jl nosetThis add [CoordsTest+8],D cmp [CoordsTest+8],#18 //Виртуальный полигон коллизи jg nosetThis cmp [CoordsTest],0 jg writeToV1 jmp nosetThis writeToV1: cmp [CoordsTest+4],0 jg nosetThis writeToV2: mov byte ptr [CoordsTest+1A],1 mov dword [CoordsTest+24],edx jmp NasledVeloctory nosetThis: cmp [CoordsTest+24],edx //Проверка касается игрок верхнего полигона того же существа или уже другого jne NasledVeloctory mov byte ptr [CoordsTest+1A],0 Если сделать скрипт без этой проверки, то персонаж на существе стоять не будет, то есть он будет висеть на нем с анимацией падения, и при слезании получит огромный урон, так как считается что он падает. Что бы избежать такого недоразумения находим функцию проверяющую стоит игрок на земле или нет, и вот как раз тут и пригодится нам наш полигон коллизии. В функцию делаем инъекцию кода параллельно с основным: Спойлер //Внедренные коды SetUscorInCode: cmp byte ptr [CoordsTest+1A],1 //Если игрок стоит на существе то не записывать увеличивать ускорение падения (стоит на земле) jne ispcode fstp dword [CoordsTest+20] jmp exitret ispcode: mov eax,[ebp-000005EC] fadd dword ptr [eax] fstp dword ptr [eax] exitret: ret Terraria.Player::Update+10C8F: //Иньекция call SetUscorInCode nop nop nop nop nop Таким образом персонаж будет стоять на существе как на земле, и при слезании не получит огромный урон. В скрипте так же имеются проверки на тип существа, и изменение его проверочного размера. Вот такой вот получается скрипт целиком: Спойлер //Весь мой скрипт включая недоработки и убранные функции [ENABLE] alloc(CollisionCreator,1300) registersymbol(CollisionCreator) label(adresStrs) label(CoordsTest) label(NpsPr) registersymbol(CoordsTest) CollisionCreator: mov esi,[[[Terraria.Main::DoDraw+375]]+08+[[Terraria.Main::DoDraw+37B]]*4] //Адрес игрока call CollisionCreateFunction mov eax,[[Terraria.Main::UpdateAudio+4F7]] mov byte ptr [NpsPr],1 //Начало проверки координат при совпадении mov ebx,0 //Обнуление счетчика sub ebx,1 StartCocleN: cmp ebx,#99 je backpotok //Если проверены все нипы из структуры то закончить цикл add ebx,1 mov edx,[eax+ebx*4+08] //Адрес нпс cmp [edx+18],1 jne StartCocleN mov esi,edx call CollisionCreateFunction jmp StartCocleN backpotok: mov byte ptr [NpsPr],0 {mov eax,[[Terraria.Main::CacheProjDraws+41]] mov byte ptr [NpsPr],1 //Начало проверки координат при совпадении mov ebx,0 //Обнуление счетчика sub ebx,1 StartCocleP: cmp ebx,#99 je backpotok1 //Если проверены все снаряды из структуры то закончить цикл add ebx,1 mov edx,[eax+ebx*4+08] //Адрес нпс cmp [edx+18],1 jne StartCocleP mov esi,edx call CollisionCreateFunction jmp StartCocleP backpotok1: mov byte ptr [NpsPr],0} ret CollisionCreateFunction: //Начало функции коллизии в esi адрес того для чего коллизия push eax push ebx push edx mov eax,[[Terraria.Main::UpdateAudio+4F7]] //Запись адреса с нпс //mov eax,[[Terraria.Main::CacheProjDraws+41]]//Запись адреса со снарядами //Начало проверки координат при совпадении mov ebx,0 //Обнуление счетчика sub ebx,1 mov [CoordsTest+14],BDCCCCCD //1 float StartCocleC: mov word ptr [CoordsTest+18],0 cmp ebx,#99 je back //Если проверены все нипы из структуры то закончить цикл add ebx,1 mov edx,[eax+ebx*4+08] //Адрес нпс cmp edx,esi //Проверка на совпадение с адресом существа для которого делается коллизия je StartCocleC cmp [edx+18],1 //Проверка на активность, если тут 1, то обьект существует, 0 - нет. jne StartCocleC //Вычисления крайних точек и сторон по Х fild dword [edx+10] //Отношение правой нпс к левой игрока 2 (игрок справа) fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение fld dword [edx+20] //Загрузить координаты НПС fadd dword [CoordsTest+1C] //Получение координат правой стороны нпс fsub dword [esi+20] //Вычитание координат игрока из координат нпс fistp dword [CoordsTest] //Полученное число расстояния в метку fild dword [esi+10] //Отношение левой нпс к правой игрока 1 (игрок слева) fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение fld dword [esi+20] //Загрузить координаты игрока fadd dword [CoordsTest+1C] //Получение координат правой стороны игрока fsubr dword [edx+20] //Обратное вычитание координат игрока из коордиеат НПС fistp dword [CoordsTest+4] //Полученное число расстояния в метку //Вычисления крайних точек и сторон по Y fild dword [edx+14] //Отношение верхней нпс к нижней игрока 2 (игрок сверху) fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение fld dword [edx+24] //Загрузить координаты НПС fsub dword [CoordsTest+1C] //Получение координат верхней стороны нпс fsub dword [esi+24] //Вычитание координат игрока из координат нпс fistp dword [CoordsTest+8] //Полученное число расстояния в метку fild dword [esi+14] //Отношение верхней игрока к нижней нпс 1 (игрок снизу) fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение fld dword [esi+24] //Загрузить координаты игрока fsub dword [CoordsTest+1C] //Получение координат верхней стороны игрока fsubr dword [edx+24] //Обратное вычитание координат игрока из коордиеат НПС fistp dword [CoordsTest+C] //Полученное число расстояния в метку //Если айди прыгательное или летательное добавить cmp byte ptr [NpsPr],1 je noadd cmp [edx+D8],1 jne noadd sub [CoordsTest+8],#25 noadd: sub [CoordsTest+8],#5 //Проверки на положение игрока относительно существа TestCoordsP: cmp [CoordsTest],0 jl noRight cmp [CoordsTest],F //Виртуальный полигон коллизи размером в 2 jg noRight cmp [CoordsTest+8],0 jl TestCoordsP2 jmp noRight TestCoordsP2: cmp [CoordsTest+C],0 jl noRight TestCoordsP3: mov byte ptr [CoordsTest+18],2 //Справа jmp WerhTest noRight: cmp [CoordsTest+4],0 jg WerhTest cmp [CoordsTest+4],#-15 //Виртуальный полигон коллизи размером в 2 jl WerhTest cmp [CoordsTest+8],0 jl noRight2 jmp WerhTest noRight2: cmp [CoordsTest+C],0 jl WerhTest noRight3: mov byte ptr [CoordsTest+18],1 //Слева WerhTest: cmp [CoordsTest+8],0 jg SnizTest sub [CoordsTest+8],#3 cmp [CoordsTest+8],#-18 //Виртуальный полигон коллизи размером в 2 jl SnizTest cmp [CoordsTest],0 jg WerhTest1 jmp SnizTest WerhTest1: cmp [CoordsTest+4],0 jg SnizTest WerhTest2: mov byte ptr [CoordsTest+19],2 //Сверху SnizTest: cmp [CoordsTest+C],0 jl ParamPrim cmp [CoordsTest+C],F //Виртуальный полигон коллизи размером в 2 jg ParamPrim cmp [CoordsTest],0 jg SnizTest1 jmp ParamPrim SnizTest1: cmp [CoordsTest+4],0 jg ParamPrim SnizTest2: mov byte ptr [CoordsTest+19],1 //Снизу //Скрипт который выполняется если игрок касается какой либо стороны моба ParamPrim: cmp byte ptr [CoordsTest+19],2 //Сверху jne next1 fld1 //Загрузка еденички fsubr dword [esi+24] fstp dword [esi+24] //Проверка ускорения игрока fild dword [esi+2C] fistp dword [CoordsTest+1C] cmp [CoordsTest+1C],0 jg setzero jmp next1 setzero: mov [esi+2C],0 next1: cmp byte ptr [CoordsTest+18],2 //Справа jne next2 fld1 //Загрузка еденички fadd dword [esi+20] fstp dword [esi+20] fld1 //Загрузка еденички fsubr dword [edx+20] fstp dword [edx+20] next2: cmp byte ptr [CoordsTest+18],1 //Слева jne next3 fld1 //Загрузка еденички fsubr dword [esi+20] fstp dword [esi+20] fld1 //Загрузка еденички fadd dword [edx+20] fstp dword [edx+20] next3: cmp byte ptr [CoordsTest+19],1 //Снизу jne writeToV fld1 //Загрузка еденички fsubr dword [edx+24] fstp dword [edx+24] writeToV: cmp [CoordsTest+8],0 jl nosetThis add [CoordsTest+8],D cmp [CoordsTest+8],#18 //Виртуальный полигон коллизи jg nosetThis cmp [CoordsTest],0 jg writeToV1 jmp nosetThis writeToV1: cmp [CoordsTest+4],0 jg nosetThis writeToV2: mov byte ptr [CoordsTest+1A],1 mov dword [CoordsTest+24],edx jmp NasledVeloctory nosetThis: cmp [CoordsTest+24],edx jne NasledVeloctory mov byte ptr [CoordsTest+1A],0 NasledVeloctory: jmp StartCocleC back: pop edx pop ebx pop eax ret //Конец функции коллизии //Внедренные коды SetUscorInCode: cmp byte ptr [CoordsTest+1A],1 jne ispcode fstp dword [CoordsTest+20] jmp exitret ispcode: mov eax,[ebp-000005EC] fadd dword ptr [eax] fstp dword ptr [eax] exitret: ret adresStrs: dd 0 0 CoordsTest: dd 0 0 0 0 0 0 0 0 0 0 0 NpsPr: db 00 Terraria.Player::Update+10C8F: call SetUscorInCode nop nop nop nop nop [DISABLE] Terraria.Player::Update+10C8F: mov eax,[ebp-000005EC] fadd dword ptr [eax] fstp dword ptr [eax] unregistersymbol(CollisionCreator) unregistersymbol(CoordsTest) dealloc(CollisionCreator) Этот скрипт должен на входе получить адрес структуры для проверки. Он выполняется 2 раза, 1 раз делает коллизию игроку, а 2 раз делает коллизию тому адрес чего получен дальше. В моём случае этот адрес - адрес существа. Этот скрипт вызывается другим скриптом с потоком: Спойлер [ENABLE] alloc(potoc,64) label(byteupr) registersymbol(byteupr) createthread(potoc) potoc: cmp byte ptr [byteupr],1 jne potoc cmp ecx,#20000 add ecx,1 jl potoc mov ecx,0 push ecx call CollisionCreator pop ecx cmp byte ptr [byteupr],2 jne potoc ret byteupr: db 00 [DISABLE] dealloc(potoc) unregistersymbol(byteupr) Вот эти сложные махинации создают коллизию между игроком и существами, и между самими существами. Картинки работы: Скрипт работает - существа не могут пройти сквозь друг друга и игрока: Спойлер Скрипт отключён: Спойлер Изменено 18 февраля, 2018 пользователем inaginary 2 2 Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения