![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
![]() Здравствуйте, у меня возникла необходимость написать в сжатые сроки бот для одной MMORPG (1-2 недели, возиться дольше не вижу смысла), чисто из спортивного интереса и для личного пользования.
Однако собственных знаний для этого, мягко говоря, недостаточно. В наличии школьный курс по Pascal и основам ООП на Delphi, имею некоторые представления о синтаксисе языка С (но только, в сравнении с Pascal). Попробовал пошариться по тематическим форумам, но нарыл лишь самую общую информацию, требующую длительного усвоения, что не укладывается в рассчетные сроки. MMORPG имеет клиент с 3D-интерфейсом. Бот должен работать по следующей схеме: 1. Логировать все манипуляции пользователя с клавиатурой и мышью (перемещение игрока, выполнение действий, вращение камеры) в окне клиента в течении длительного времени (10-15 минут) 2. По команде, в точности воспроизводить действия пользователя из ранее записанного лога Что, собственно, вызывает 2 вопроса: 1. Возможно ли вообще реализовать такую схему? 2. Каким инструментарием лучше воспользоваться? |
#2
|
||||
|
||||
![]() Цитата:
дай угадаю.... линейка да? много вас таких, сам когда то баловался, только смысл? уже полно ботов + исходники - юзай гугл, у меня лично на винте есть 3-4 бота. с этим проблем нет ищи лучше! |
#3
|
|||
|
|||
![]() Во-первых, не угадал... это даже не WoW. Игра новая и малоизвестная, на стади открытого бета-теста, ни о каких готовых ботах к ней никто и в помине не слышал, так что проще написать самому с учетом специфики интерфейса.
Во-вторых, надоело задрить на добыче ресов, она реализована таким образом, что через пару часов сам становишься похожим на бота, хочется нормально поиграть. Но без ресов далеко не уедешь, а свободного времени у меня не так много. Т.е. имеется индивидуально генерируемая локация где кроме персонажа и расставленных на СТРОГО ОТВЕДЕННЫХ местах ресов больше ничего нет - создание бота напрашивается само-собой. Сейчас прикинул список логируемых действий обычного пользователя: 1. Нажатие клавиши клавиатуры - выполнение действия 2. Удержание клавиши клавиатуры - движение вперед/назад, круговое вращение камеры 3. Нажатие клавиши мыши - движение персонажа в точку позиционирования указателя, взаимодействие с объектом (это ключевое действие бота) 4. Удержание клавиши мыши + движение указателя - свободное вращение камеры 5. комбо из удержания клава+клава, мышь+клава, мышь+мышь - передвижение персонажа Задумался над логированием... особенно над п.5 и другими операциями с удержанием клавиш, порылся в интерфейсе клиента, пришел к выводу что все это можно заменить двумя операциями ввода данных: 1. Нажатие клавиши клавиатуры - выполнение действия, выставление вида камеры "по умолчанию" (вид со спины) 2. Нажатие клавиши мыши - перемещение персонажа, взаимодействие с объектом Сложно для игрока, но зато легко залогировать по простейшему алгоритму: 1. RunTimer 2. нажатие клавиши -> запись времени и параметров клавиши |
#4
|
||||
|
||||
![]() Глобальный хук на нужные сообщения, отсеивать по хендлу процесса. А потом - серии SendMessage. Я бы так делал
![]() Оставайтесь хорошими людьми... VK id2634397, ds [at] phoenix [dot] dj |
#5
|
|||
|
|||
![]() Все не было времени продолжить, два дня бегал по магазинам, собирал новый системник
![]() За идею с хуками спасибо. Сильно помогло, т.к. не знал с чего вообще подступиться. Столкнулся было с одной проблемой, но пока описывал, дорубился как поискать ответ ![]() Пойду терзать гугл... |
#6
|
||||
|
||||
![]() Товарищ! Не колупайте себе мозг!
Есть же волшебная штука AutoIt! Она как будто специально заточена для таких целей. Попробуй - понравится. Там всё легко и удобно. Если не ты, то кто? (с) Терри Пратчетт Не забывайте ставить плюсы и говорить спасибо! |
#7
|
|||
|
|||
![]() EvilRussian, а как ты думаешь, что проще: врубиться в совершенно незнакомый синтаксис и написать на нем код, или написать тот же код на известном синтаксисе?
Есть проблема при постановке хука: Если ставить глобальный затык Цитата:
А затык по pID, который ищется таким способом: Цитата:
|
#8
|
||||
|
||||
![]() Inkvisitor, бот дельфяшный очень легко перехватывается, кроме того, его сложно писать.
Поскольку ботоводство в 80% онлайн-игр карается вечным баном, это не вариант. AutoIt имитирует нафатия клавиш на клавиатуре и передвижения мыши, поэтому перехватить его практически невозможно. Кроме того, на нём на написание понадобится только 40 минут, ну и часа 2 в крайнем случае на обучению коду (синтаксис несложен). Ну и какие выводы?.. Если не ты, то кто? (с) Терри Пратчетт Не забывайте ставить плюсы и говорить спасибо! |
#9
|
||||
|
||||
![]() Тебе не надо все сообщения отлавливать. Отлавливай сообщения только нужного тебе процесса (то бишь игры), а все остальные сообщения винды просто игнорируй...
Помогаю за Спасибо ![]() |
#10
|
|||
|
|||
![]() Цитата:
v1s2222 а я это и делаю, логгер уже ловит только то, что нужно, но глобально, без привязки к процессу ![]() приложение имеет надцать скрытых окон (смотрел в WinSight), если ставить хук на хендл видимого окна или самого процесса, то он "слепнет" и выдает пустой лог. |
#11
|
||||
|
||||
![]() Делай хук на ThreadID, соответственно все окна, видимые и не видимые будут отлавливаться... кстати, если читать справку по функции SetWindowsHookEx, то там сказано, что функция должна находиться в библиотеке.
Вот пример задания хука для приложения: Код:
//библиотека library Hook; uses Windows, SysUtils; const crlf = #$0D#$0A; Var logfile : string = 'D:\log.txt'; Hook : dword; dwThreadId : dword; cFile : dword; Function kWriteFile( hFile:THANDLE; lpBuffer:Pointer; nNumberOfBytesToWrite:DWORD ; lpNumberOfBytesWritten:LPDWORD; lpOverlapped:pointer ):boolean; stdcall; external 'kernel32.dll' name 'WriteFile'; Function kReadFile( hFile:THANDLE; lpBuffer:Pointer; nNumberOfBytesToRead:DWORD ; lpNumberOfBytesReaden:LPDWORD; lpOverlapped:pointer ):boolean; stdcall; external 'kernel32.dll' name 'ReadFile'; Function FindWnd (pWndCaption: PChar) : boolean; var w : dword; begin result := false; w := FindWindow(nil,pWndCaption); if w = 0 then exit; dwThreadID := GetWindowThreadProcessId(w,nil); if dwThreadId <> 0 then result := true; end; procedure LibraryProc(Reason: Integer); begin if (Reason = DLL_PROCESS_ATTACH) or (Reason = DLL_THREAD_ATTACH) then begin cFile := CreateFile(PChar(logfile),GENERIC_WRITE or GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN,0); end else CloseHandle(cFile); end; function CbtProc(code: integer; wparam: integer; lparam: integer):Integer; stdcall; var written : dword; cFileSizeLow,cFileSizeHi : integer; sBuf : string; begin if code < 0 then result := CallNextHookEx(Hook,code,wParam,lparam) else begin cFileSizeLow := GetFileSize(cFile,@cFileSizeHi); SetFilePointer(cFile,cFileSizeLow,@cFileSizeHi,FILE_BEGIN ); sBuf := ParamStr(0)+': code = '+IntToStr(code)+' wparam = '+IntToStr(wParam)+' lparam = '+IntToStr(lParam)+crlf; kWriteFile(cFile,PChar(sbuf),length(sBuf),@written,nil); Result:=0; end; end; Function InstallHook (pWndCaption: PChar): boolean; begin result := false; if not(FindWnd(pWndCaption)) then exit; if not(ForceDirectories(ExtractFilePath(logfile))) then exit; Hook := SetWindowsHookEx(WH_CBT,@CbtProc,HInstance,dwThreadId); result := Hook <> 0; end; Function UnInstallHook: boolean; begin result := false; CloseHandle(cFile); if Hook <> 0 then result := UnhookWindowsHookEx(Hook); end; exports InstallHook name 'InstallHook',UnInstallHook name 'UnInstallHook'; begin DLLProc := LibraryProc; end. Код:
// и сама программа ... Function InstallHook (pWndCaption: PChar): boolean; external 'Hook.dll'; Function UnInstallHook: boolean; external 'Hook.dll'; ... procedure TForm1.Button1Click(Sender: TObject); begin if InstallHook('Блокнот') then ShowMessage('Installed'); end; procedure TForm1.Button2Click(Sender: TObject); begin if UnInstallHook then ShowMessage('Uninstalled'); end; Помогаю за Спасибо ![]() |
#12
|
|||
|
|||
![]() v1s2222, спс за листинг, по сути - то же, что и у меня, но смысла упаковывать все обработчики в отдельную библиотеку я лично не вижу...
попытка поставить хук на ThreadID, ни к чему хорошему не приводит, как и на processID или хендл любого скрытого окна клиента. Работает только глобальный хук: "0"; Из него как-нибудь можно выцепить хендл процесса, которому передавалось ссбытие? |
#13
|
||||
|
||||
![]() Цитата:
jmp $ ; Happy End! The Cake Is A Lie. |
#14
|
|||
|
|||
![]() Bargest, ну у меня хуки и без дллки ловят необходимый минимум событий.
Проблема сейчас в другом: я не знаю, куда посылать сообщения из лога. ![]() Получается, что по хендлу главного окна обрабатываются только события интерфейса - хоткеи различных окон и хоткеи панели действий. Т.е. я могу залезть в инвентарь или заюзать скил, но не могу перемещать персонажа мышью или выделить цель хоткеем. Поэтому у меня возникла пара вопросов на которые я икак не найду внятного ответа: 1. Можно ли в обработчике хука получить хендл окна, которому адресовано событие? 2. Как получить хендлы всех дочерних окон главного окна? P.S. и да... я уже пытался отсылать сообщения по хендлам процесса и потока. |