![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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. Я бы так делал
![]() |
|
#5
|
|||
|
|||
|
Все не было времени продолжить, два дня бегал по магазинам, собирал новый системник
потом еще столько же возился с вин7, хоть она мне и не нравится (многие привычные программы плохо с ней совместимы), но х64 проц, 4гб оперативы и DX11 вынудили... да и на работе аврал.За идею с хуками спасибо. Сильно помогло, т.к. не знал с чего вообще подступиться. Столкнулся было с одной проблемой, но пока описывал, дорубился как поискать ответ ![]() Пойду терзать гугл... |
|
#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
|
||||
|
||||
|
Цитата:
|
|
#14
|
|||
|
|||
|
Bargest, ну у меня хуки и без дллки ловят необходимый минимум событий.
Проблема сейчас в другом: я не знаю, куда посылать сообщения из лога. Получается, что по хендлу главного окна обрабатываются только события интерфейса - хоткеи различных окон и хоткеи панели действий. Т.е. я могу залезть в инвентарь или заюзать скил, но не могу перемещать персонажа мышью или выделить цель хоткеем. Поэтому у меня возникла пара вопросов на которые я икак не найду внятного ответа: 1. Можно ли в обработчике хука получить хендл окна, которому адресовано событие? 2. Как получить хендлы всех дочерних окон главного окна? P.S. и да... я уже пытался отсылать сообщения по хендлам процесса и потока. |