-
Постов
319 -
Зарегистрирован
-
Посещение
-
Победитель дней
43
Тип контента
Профили
Форумы
Загрузки
Блоги
Сообщения, опубликованные imaginary
-
-
Вот на примере 1 координаты, если больше то вычитаем, меньше то добавляем, и так двигаем персонажа (с постоянной скоростью) к точке где будет 0, то есть к нашей сохраненной точке, такое делается на все координаты.
Я думаю можно сделать как то проще.
Спойлерmovetocoords: //Полет на позицию fld qword [savecoords1] //Сохраненная позиция Х fsubr qword [eax+30] //Координаты игрока Х fcomp qword [multiplayer] //Сравниваем st(0) с нулём fstsw ax //В регистр ax sahf //Выталкиваем флаги в флаги обычного процессора ja subcoordX //Если больше //Если меньше - вычитаем fld qword [eax+30] fadd dword [multiplayer2+4] //Добавляем еденичку (к примеру) fstp qword [eax+30] jmp next subcoordX: //Если больше - прибавляем fld qword [eax+30] fsub dword [multiplayer2+4] //Вычитаем еденичку (к примеру) fstp qword [eax+30]
- 1
-
43 минуты назад, Antonshka сказал:
До момента написания предыдущего сообщения я не знал как осуществить эту идею. Спросил у тебя ради спортивного интереса, наверно.
На самом деле я знаю как сделать такое используя проверки, но это будет слишком много скрипта, например если больше нуля то вычитать еденичку из координат, меньше то добавлять, это уже 1 проверка, а всего их надо сделать 3 на три оси координат. Сейчас я напишу скрипт и пришлю пример. Только вот координаты там нельзя менять таким образом, то есть персонажа будет отбрасывать, там есть иные координаты, они меньше на некоторое значение и находятся в другой структуре, это координаты нижней точки персонажа, вот они уже влияют. Если еще как ты сказал делать ускорение, то надо засунуть проверку - если меньше дистанции то.. и цикл который будет убавлять значение делителя пока не будет больше дистанции проверки, потом значение делителя восстанавливается, и потом идет еще проверка на дистанцию остановки...
-
1 час назад, Antonshka сказал:
Если есть желание, то сделай наглядный пример написанного
Делаю я, делаю наглядный пример, и тут до меня доходит что координаты в структуре визуальные, а сервер будет откидывать без ускорения, это произошло как раз в тот момент как моего персонажа колбасило по всей комнате из за неправильного скрипта.
Мною была использована команда fprem для нахождения остатка при делении на 1. Еще была идея сделать с кучей проверок, это я могу запросто, правда вот 100% уверенность что все делается намного проще. -
10 минут назад, Antonshka сказал:
Использовать можно только координаты X,Y,Z игрока и X,Y,Z точки назначения
Я конечно сделаю ради интереса, но все же не вижу смысл так изгаляться, и меня не отпускает стойкое ощущение что ты то уже знаешь как по твоему проще сделать, и задаешь мне вопрос что бы увидеть как это у меня получится, а потом написать мне свой способ и если он проще, указать на это
-
4 минуты назад, Antonshka сказал:
30 метров пути в начале и в конце - расстояние статичное, для любых дистанций.
И как по твоей схеме должны обрабатываться расстояния меньше чем 60 метров?
В таком случае будет просто ускорение или замедление будет обрываться не заканчиваясь по прилету на точку, если уж ты мне условие написал то учти и этот аспект -
2 часа назад, Antonshka сказал:
*Что если необходимо сделать плавное перемещение (полёт) игрока до некоторой точки в пространстве, используя при этом лишь только 3 координаты положения игрока и 3 координаты положения точки
То есть ты предлагаешь не использовать ускорение?
Мною были запущены fsin и fcos и с радианами и с градусами в отдельном скрипте для тестов, получалась какая то ерунда что в радианах, что в градусах, возможно я просто не правильно их использую.
Вообще, спасибо за упрощённые методы, а в математике я не очень (особенно с этими градусами) То что в моём скрипте находит части не окружности а ромба, но разницы особо нету, разве что в немного неровном ускорении
То что ты предлагаешь - полет с постоянной скоростью, реализовывается просто с прибавлением фиксированных значений к координатам
-
В этой теме можно узнать как сделать управление запускаемыми снарядами в Terraria и сделать отправку их положения на сервер (Что бы другие игроки видели как летает снаряд, простая замена условия в коде)
Скрипт:Спойлер[ENABLE] alloc(newmem,200) label(returnhere) label(originalcode) label(exit) newmem: push eax mov eax,[[Terraria.Player::Update+33CF]] //CursorX mov [CoordSC],eax mov eax,[[Terraria.Player::Update+33CF]+4] //CursorY mov [CoordSC+4],eax fild dword [CoordSC] //X fmul dword [multiplayer+4] fsub dword [ecx+20] fdiv dword [multiplayer] //Добавим деление для полавного преследования fstp dword [ecx+28] //Записываем в ускорение fild dword [CoordSC+4] //X fmul dword [multiplayer+4] fsub dword [ecx+24] fdiv dword [multiplayer] //Добавим деление для полавного преследования fstp dword [ecx+2C] //Записываем в ускорение pop eax originalcode: fld dword ptr [ecx+000000A8] exit: jmp returnhere CoordSC: //Координаты курсора dd 0 0 multiplayer: dd (float)6 (float)16 Terraria.Projectile::Update+3B2C: db 90 90 90 90 90 90 90 db 90 90 Terraria.Projectile::ProjLight+7: jmp newmem nop returnhere: [DISABLE] Terraria.Projectile::Update+3B2C: cmp byte ptr [eax+000000E4],00 je Terraria.Projectile::Update+3B8D dealloc(newmem) Terraria.Projectile::ProjLight+7: fld dword ptr [ecx+000000A8] //Alt: db D9 81 A8 00 00 00
Видео:Спойлер
- 3
- 1
-
В этой теме можно узнать о том, как сделать полет по повороту камеры в 3D пространстве (лететь туда куда смотришь) и как сделать перевод числа в 360, если оно превышаем 360 или наоборот, ниже нуля. Перед просмотром видео лучше ознакомится с предыдущими темами, так как там показано как найти адрес персонажа.
Скрипт- функция расчета ускорения из поворота:Спойлер[ENABLE] alloc(FlyToCam,360) //createthread(FlyToCam) registersymbol(FlyToCam) label(Angle) label(upravlen) label(multiplayer) label(Veloctory) registersymbol(Angle) registersymbol(upravlen) registersymbol(multiplayer) registersymbol(Veloctory) FlyToCam: //Старт функции --- //Проверка с помощью FPU fld dword [Angle+8] //Сюда будет писать вызывающий скрипт fcom dword [StestChisl+4] //Сравниваем st(0) с нулём fstsw ax //В регистр ax sahf //Выталкиваем флаги в флаги обычного процессора ()_() ja NoInvert //Если больше fabs //Изменяем знак 360 после fsubr dword [StestChisl] //Вычитаем из 360 наше число и получаем альтернативное положительное, fsubR вычитает не источник из приёмника а наоборот. NoInvert: fst dword [Angle+4] //Сохраняем не выгружая из стека fdiv dword [StestChisl] //Делим на 360 и узнаем сколько раз оно там //Вычитаем 0,5 и потом округляем, что бы округление происходило до целого нижнего fsub dword [StestChisl+8] frndint //Округление до ближайшего целого //fst dword [Angle] //Делаем выноску что бы узнать нормальное число fmul dword [StestChisl] //Умножаем на 360 fsubr dword [Angle+4] //Вычитаем из нашего числа 360 умноженое на округленное целое {Это все должно дать нам поворот в 360 градусной системе, даже если число будет 2763 или -315, поворот будет расчитан точно.} fstp dword [Angle] //Выгружаем в поворот, нам же надо проверить работоспособность скрипта fld dword [Angle] fcom dword [StestChisl2] //Сравниваем st(0) с 90 fstsw ax //В регистр ax sahf ja p90 //Если больше //Тут если от 0 до 90 fchs //Меняем знак fst qword [Veloctory] //Записываем в 8 байт тип doble 1 часть от 90 fchs //Возвращаем знак fsubr dword [StestChisl2] //Вычитаем из 90 наше число поворота fst qword [Veloctory+8] //Записываем в 8 байт тип doble 2 часть от 90 jmp goend p90: fcom dword [StestChisl2+4] //Сравниваем st(0) с 180 fstsw ax //В регистр ax sahf ja p180 //Если больше //Тут если от 90 до 180 fsub dword [StestChisl2] //Вычитаем 90 fchs //Меняем знак fst qword [Veloctory+8] //Записываем в 8 байт тип doble 1 часть от 90 fchs //Возвращаем знак fsubr dword [StestChisl2] //Вычитаем из 90 наше число поворота fchs //Меняем знак fst qword [Veloctory] //Записываем в 8 байт тип doble 2 часть от 90 jmp goend p180: fcom dword [StestChisl2+8] //Сравниваем st(0) с 270 fstsw ax //В регистр ax sahf ja p270 //Если больше //Тут если от 180 до 270 fsub dword [StestChisl2+4] //Вычитаем 180 fst qword [Veloctory] //Записываем в 8 байт тип doble 1 часть от 90 fsubr dword [StestChisl2] //Вычитаем из 90 наше число поворота fchs //Меняем знак fst qword [Veloctory+8] //Записываем в 8 байт тип doble 2 часть от 90 jmp goend p270: //Тут если от 270 до 360 fsub dword [StestChisl2+8] //Вычитаем 180 fst qword [Veloctory+8] //Записываем в 8 байт тип doble 1 часть от 90 fsubr dword [StestChisl2] //Вычитаем из 90 наше число поворота fst qword [Veloctory] //Записываем в 8 байт тип doble 2 часть от 90 jmp goend //Вот такие проверочки, если больше 90, больше 180, больше 270. на 4 отрезка окружности. goend: emms //Очистка стека FPU fld qword [Veloctory] fst qword [Veloctory] //1 fdiv dword [StestChisl2] //Делим на 90 fst qword [Veloctory] //2 fdiv qword [multiplayer] //Делим на делитель скорости fstp qword [Veloctory] fld qword [Veloctory+8] fdiv dword [StestChisl2] //Делим на 90 fdiv qword [multiplayer] //Делим на делитель скорости fstp qword [Veloctory+8] ret //Конец функции --- //Метки upravlen: dd 0 StestChisl: dd (float)360 0 (float)0.5 //360, 0, 0.5 StestChisl2: dd (float)90 (float)180 (float)270 //Части проверки для круга Angle: dd 0 0 0 multiplayer: dq 4024333333333333 //10.1 doble Veloctory: dq 0 0 [DISABLE] unregistersymbol(FlyToCam) unregistersymbol(Veloctory) unregistersymbol(multiplayer) unregistersymbol(upravlen) unregistersymbol(Angle) dealloc(FlyToCam)
Скрип записывающий в ускорение игрока и вызывающий функцию выше:
Спойлер[ENABLE] alloc(callFlyTo, 120) createthread(callFlyTo) callFlyTo: cmp byte ptr [upravlen],5 je retmetka cmp byte ptr [upravlen],1 jne callFlyTo mov esi,[playeradress+4] mov eax,[esi+88] //Поворот mov [Angle+8],eax call FlyToCam //Вызов инструкции movq xmm0,[Veloctory] movq [esi+48],xmm0 movq xmm0,[Veloctory+8] movq [esi+58],xmm0 //Вызов инструкции для X,Z осей поворота mov eax,[esi+8C] //Поворот mov [Angle+8],eax call FlyToCam //Вызов инструкции movq xmm0,[Veloctory] movq [esi+50],xmm0 jmp callFlyTo retmetka: ret [DISABLE] dealloc(callFlyTo)
Видео:
Часть 1:Спойлер
Часть 2:Спойлер
Часть 3:Спойлер- 2
- 3
-
В этой теме можно узнать как сделать полёт на определённые координаты исходя из координат точки и координат персонажа. Для созданий этого скрипта надо иметь у себя адрес персонажа, потому лучше еще прочитать предыдущую тему.
Скрипт:
Спойлер[ENABLE] alloc(PlFly,160) createthread(PlFly) label(flyTo) label(multiplayer) label(savecoords1) registersymbol(flyTo) registersymbol(multiplayer) registersymbol(savecoords1) PlFly: cmp byte ptr [flyTo],5 //Если введем значение 5 то поток вернется je retmetka cmp byte ptr [flyTo],1 je savecoords2 cmp byte ptr [flyTo],2 je movetocoords jmp PlFly //Зацикливание потока savecoords2: //Сохранение позиции mov byte ptr [flyTo],0 //Обнуление управления mov eax,[playeradress+4] movq xmm0,[eax+30] movq [savecoords1],xmm0 //Сохраняем координату X (movq переписываем 8 байт из 1 в другое) movq xmm0,[eax+38] movq [savecoords1+8],xmm0 //Координату Y movq xmm0,[eax+40] movq [savecoords1+10],xmm0 //Координату Z jmp PlFly movetocoords: //Полет на позицию mov eax,[playeradress+4] mov edx,[eax+34] //Правая часть doble координат cmp edx,[savecoords1+4] //Проверка равны ли координаты jne Gocoords mov byte ptr [flyTo],0 Gocoords: movq xmm0,[savecoords1] //X subsd xmm0,[eax+30] //Делаем вычитание из сохраненной координаты, теперешней. divsd xmm0,[multiplayer] //Будет делится на это число, так можно управлять скоростью movq [eax+48],xmm0 //Записываем в ускорение полученное число movq xmm0,[savecoords1+8] //Y subsd xmm0,[eax+38] //Делаем вычитание из сохраненной координаты, теперешней. divsd xmm0,[multiplayer] //Будет делится на это число, так можно управлять скоростью movq [eax+50],xmm0 //Записываем в ускорение полученное число movq xmm0,[savecoords1+10] //Z subsd xmm0,[eax+40] //Делаем вычитание из сохраненной координаты, теперешней. divsd xmm0,[multiplayer] //Будет делится на это число, так можно управлять скоростью movq [eax+58],xmm0 //Записываем в ускорение полученное число jmp PlFly //Вот и вся функция, зато какой результат! retmetka: //Перед выключением скрипта для его редактирования надо вернуть поток ret //Метки flyTo: //Это будет метка которая будет управлять скриптом dd 0 savecoords1: //метка с сохраненными координатами в doble, 1 координата 8 байт dq 0 0 0 multiplayer: dq 4024333333333333 //10.1 (doble) [DISABLE] unregistersymbol(savecoords1) unregistersymbol(multiplayer) unregistersymbol(flyTo) dealloc(PlFly)
Видео:Спойлер- 1
- 3
-
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)
Вот эти сложные махинации создают коллизию между игроком и существами, и между самими существами.
Картинки работы:
Скрипт работает - существа не могут пройти сквозь друг друга и игрока:СпойлерСкрипт отключён:
Спойлер- 2
- 2
-
Minercraft 1.7.10, java x64
Проектный
Скрытый текстЗдесь рассказано как сделать скрипт ищущий адрес игрока (простой переход по указателям) из структуры хранящей основные адреса связанные с игроком, эта структура в свою очередь будет искаться с помощью aobscan. Проектный Minercraft это вид minercraft с лаунчером проекта, то есть лаунчером отличным от обычного лаунчера этой игры, то есть он имеет тематический лаунчер проекта (не знаю как лучше объяснить). Как мне удалось заметить, он отличается от обычного, но все проектные схожи друг с другом, потому созданный в этой теме скрипт скорее всего будет работать на любом проектном minecraft на любых серверах.
Для начала необходимо найти сам адрес игрока, сделать это на сервере проще всего по векторному ускорению игрока. Оно имеет тип doble.
Делать мы это будем следующим образом:
Встаём на земле, ищем неизвестное значение, залезаем в воду - ищем увеличилось, и так далее. Вместо залезания в воду можно прыгнуть или еще как либо изменить ускорение игрока по вертикальной оси.Скрытый текстЗначение в 4х байтах: 3214179041 в воде, 3216249349 на суше.
Предположим нам удалось найти адрес структуры игрока таким образом. У нас есть адрес игрока, делаем все так же как и при простом поиске указателя, ищем полученный адрес с помощью поиска в hex 4 байта, у нас найдет очень много значений. Отсеиваем их пока не останется около 30
Скрытый текст
Ставим бряк на доступ к найденным адресам и находим тот в котором будет инструкция со смещением.Скрытый текст
Мы находим адрес структуры в которой лежит адрес игрока, он то нам и нужен, делаем анализ структурСкрытый текст
Наш адрес игрока лежит по смещению +84. Дальше указатели искать бессмысленно, лучше вывести сигнатуру из части этой структуры, которая всегда будет одинакова и уникальна, сделать это можно из первых значений в структуре.Скрытый текст
Это - размеры отображаемого пространства, проверить можно изменив одно значение:Скрытый текст
Исходя из этого можно понять что эти адреса всегда будут уникальны, потому можно смело сделать из этого следующую сигнатуру, у меня получилась вот такая: C0 02 00 00 10 27 00 00 56 03 00 00
Осталось лишь написать скрипт который будет записывать в метки нужные нам адреса, так как 64x процесс CE думает что указатели по 8 байт, и при простом переходе по указателям получается невесть что, потому попробуем сделать запись адресов через скрипт.
Получившийся у меня скрипт:Скрытый текст[ENABLE] aobscan(FindDynamicPlayerPointer,C0 02 00 00 10 27 00 00 56 03 00 00) //Поиск куска структуры alloc(adresspl,100) label(playeradress) label(strplayeradress) registersymbol(adresspl) registersymbol(playeradress) registersymbol(strplayeradress) adresspl: mov eax,FindDynamicPlayerPointer //Адрес найденной сигнатуры sub eax,30 //Смещает до начала структуры с адресами mov dword [strplayeradress+4],eax //Записываем адрес структуры в метку mov eax,[eax+84] //Добавляем смещение до адреса игрока mov dword [playeradress+4],eax //Записываем адрес игрока в метку //Мои дополнения: mov eax,[strplayeradress+4] //Возвращаем в eax адрес структуры с адресами mov eax,[eax+6C] //Записываем в eax адрес структуры с данными о выделенном блоке mov dword [strplayeradress+C],eax //В метку его mov eax,[strplayeradress+4] //Возвращаем адрес структуры с адресами mov eax,[eax+A8] //По смещениям mov eax,[eax+F8] //По смещениям mov dword [strplayeradress+14],eax //В метку адрес с параметрами о предмете в руке ret //Возврат playeradress: dd 0 0 strplayeradress: dq 0 0 0 0 0 createthread(adresspl) //Создание потока [DISABLE] dealloc(adresspl) unregistersymbol(strplayeradress) unregistersymbol(playeradress) unregistersymbol(adresspl)
Таким образом - скрипт ищет адрес структуры, потом вызывает поток который запишет адреса в метки и вернется.
Как выглядит у меня:Скрытый текстАктивируем:
Скрытый текстВаши значения в структуре могут быть иными, потому сигнатура может не работать, например из за иного разрешения экрана, потому надо найти её самостоятельно.
Использовать эти адреса можно как угодно, например сделать моментальное ломание любых блоков на сервере, в том числе и коренной породы. Надо учитывать что адреса меняются после перехода в другой мир или при смерти игрока, потому надо перезапускать поиск. Я считаю что есть способы более удобные, но это пожалуй для 32 битной java, а здесь лучшего способа чем этот мне пока найти не удалось.- 1
- 3
-
Terraria steam версия, потому смещения на репаках могут не совпадать. Дело в том что в этой игре есть функция отправки данных на сервер "Terraria.NetMessage::SendData", которая получает на входе байты пакета и тип действия, например тип действия 11 это ломание или постройка блока.
С такими параметрами вызывается функция при ломании блока, ей нужны координаты места ломания и тип действия, промежуточные байты встраиваются позже в сам пакет.Скрытый текстpush -01 push 00 //Байт пакета push 00 //Бп push (Координаты во float X) push (Координаты во float Y) push 00 //Бп push 00 //Бп push 00 //Бп push 00 //Бп mov ecx, (назначение пакета, его действие и размер, тут - 11) edx FFFFFFFF
Пакет о ломании блока выглядит следующим образом:
0B 00 11 00 70 10 62 02 00 00 00 0B - размер пакета 11 - тип действия 70 10 и 62 02 - координаты
Проблема возникла с вызовом этой инструкции с использованием нового потока, код выглядит следующим образом:
Скрытый текст//Вызов отправки пакета о ломании тайла на сервер push -01 push 00 push 00 fild dword [coordsp] //Координаты курсора Х sub esp,04 //Вычитаем из esp 4 fstp dword [esp] //Засовываем в стек координаты во float fild dword [coordsp+4] //Координаты курсора Y sub esp,04 //Вычитаем из esp 4 fstp dword [esp] //Засовываем в стек координаты во float push 00 push 00 push 00 push 00 mov ecx,11 mov edx,FFFFFFFF call Terraria.NetMessage::SendData
Стек после этого принимает нужный вид, регистры получают нужные значения, функция после вызова идет исправно вплоть до момента вызова функцией
Terraria.NetMessage::SendData+94 - E8 029ADB58 - call clr.dll+2023
В которой идет вызов
clr.dll+2036 - E8 AD030000 - call clr.dll+23E8
В том вызове находится следующий код:
clr.dll+23E8 - 64 A1 3C0E0000 - mov eax,fs:[00000E3C] { 3644 } clr.dll+23EE - C3 - ret
Проблема в том, что после его выполнения при вызове инструкции из игры, eax приобретает какой то адрес, а при выполнении вызова с использованием нового потока eax приобретает 0, а дальше после возврата по коду идёт:
clr.dll+203B - 8B F0 - mov esi,eax clr.dll+203D - 8B 46 04 - mov eax,[esi+04] clr.dll+2040 - 83 E0 5F - and eax,5F { 95 }
И как понятно [00000000+04] вызывает вылет, при этом все аргументы совпадают и все выполняется отлично именно до этой функции с регистром fs, при чем мне так и не удалось разобраться что вообще делает такой код
clr.dll+23E8 - 64 A1 3C0E0000 - mov eax,fs:[00000E3C] { 3644 }
Регистр fs в отладчике всегда показан 53 и он никогда не меняется, потому я интересуюсь в чем может быть проблема? К тому же, другие функции этой игры удаётся вызывать без проблем, в том числе если они содержат функцию отправки данных. У меня есть лишь одна догадка, где то в стеке далеко лежит какое то значение которое по коду где то необходимо, но это вряд ли, потому что в разных функциях стек разный, и полностью возвращается после выполнения. Главный вопрос в том, что делает
clr.dll+23E8 - 64 A1 3C0E0000 - mov eax,fs:[00000E3C] { 3644 }
// Читаем правила форума - нарушен пункт 1.5, если не знаешь как делать спойлера - почитай ФАК Garik66
-
@SergBrNord Почему бы тебе просто не попробовать занопить инструкцию которая отбавляет твои ходы, или сделать в твоём скрипте создание адреса который бы указывал на количество ходов, тогда ты бы мог включить свой скрипт и вынести это значение в таблицу по указателю от твоей метки, сделать это можно примерно так:
После того как ты сделал инъекцию сюда"RomeTW-BI.exe"+1817DD: D9 98 7C 02 00 00 - fstp dword ptr [eax+0000027C]
Сделать такой скрипт:
label(mymetka) registersymbol(mymetka) //Регистрация метки newmem: mov [mymetka],eax code: fstp dword ptr [eax+0000027C] jmp return mymetka: //Задание метке размера dd 0 [DEALLOC] unregistersymbol(mymetka) //Снятие регистрации
Теперь если ты добавишь к себе в таблицу эту метку и сделаешь её pointer типа float со смещением 27C, у тебя в таблице всегда будет значение с ходами, это при условии если инструкция будет работать только с ходами чего то одного, если она работает с многими то надо сделать фильтр в зависимости от твоей цели, хочешь ты себе ходы сделать или еще что другое.
Возможно такой способ может быть альтернативой записи в скрипте -
2 минуты назад, Garik66 сказал:
ну я не вдавался в такие подробности ассемблера. Я даже не знаю и пока ни разу не видел опкод emms.
Нам же просто нужно вытолкнуть значение из st(0) сдвинув стек, а потом вернуть его обратно загрузив в st(0) нужное значение.
Но это, повторюсь скорее всего не сработает, так как второй скрипт у ТС верен.
Ну это да, а по моему не обязательно сразу загружать значение во float, если использовать команду fild, она загрузит целое число как число float.
Странно что число ходов во float, быть может это значение какое нибудь для вывода на экран, или вроде того, а настоящее другое -
@Garik66 по моему чистку стека еще можно организовать командой emms, но она очищает весь стек fpu
-
@Garik66, я скорее имею ввиду то, что если просто написать скрипт после функции загрузки не выгружая, то стек будет заполнятся и заполнятся все дальше и может случится что то плохое.
-
А если делать инъекцию в том месте где делаешь, то надо заменить нопами верхнюю инструкцию, что бы не происходило заполнения стека fpu, ведь она загружает.
"RomeTW-BI.exe"+1817DA: D9 45 EC - fld dword ptr [ebp-14]
Или же можно перед своим кодом сделать выгрузку из стека
fstp dword ptr [eax+0000027C]
Но как сказал Garik66, лучше делать инъекцию на инструкцию выше твоей иньекции.
x64 Проектный Minecraft делаем полёт по повороту камеры
in Статьи для новичков
Опубликовано
Ты конечно же полностью прав. Смотри что ты предлагаешь - делать функцию ускорения в игре. То есть сделать с нуля функцию ускорения, ( то которое управляет смещениями, так как ты сказал что его нельзя использовать. При том оно есть почти во всех играх, не проще ли вместо того что бы изгаляться сделать это же но с ускорением, при этом с постоянной скоростью движения