Работаем с хештейблами на примере мобов вокруг нас
На примере написанной мной программки xCube.
Смещения ру офф клиента можно взять [Ссылки могут видеть только зарегистрированные пользователи. ]
Написана на Codegear C Builder 2007 ( впрочем от 6 билдера до XE, особо разницы нету...с юникодом ток немного)
[Ссылки могут видеть только зарегистрированные пользователи. ]
Описание проекта: на форме у нас 4 компонента: PopupMenu, ImageList, Timer, TrayIcon.
Итак: чего нам надо сделать
1. Посчитать шарики в 5, 27 комнатах
2. Смотреть в таргет на предмет наличия гусениц.
Что для этого потребуется: Смотреть свой таргет, заглянем в смещения
GAME_ADD = A5BFCC;
Структура игрока:
GA +20: HostPlayer Struct
+B0C; -Target
Смотреть окружающих нас мобов:
GA +8 +24 +14: - Mobs count
Структура мобов
GA +8 +24 +18 +[I*4] + (+0)^J +4: (I in [0..300 hex])
+11C MobWorldID
+120 MobID
Как нам надо читать: если хотим прочитать кто у нас в таргете, смотрим выше описанные смещения и считываем 4 бафта по смещению GA, далее по полученному смещению +20, далее по полученному + B0C - получили таргет.
С мобами интересная вещь, самому лень было сразу осиливать))
там где +0 это значит считать в это адресе адрес след. элемента
(+0)^J это наши страницы памяти
в итоге у нас получится такая охинея
1-я страница GA +8 +24 +18 +[I*4] +4:
2-я страница GA +8 +24 +18 +[I*4] +0 +4:
2-я страница GA +8 +24 +18 +[I*4] +0 +0 +4:
и так далее, особо останавливаться не будем, по ходу поймем
а теперь вгрыземся в код
смотрим комменты после // дабы оставить код рабочим
Код:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
DWORD dwPid=0;
HANDLE hProc;
int iRed, iWhite, iBlue;
int iGA = 0xa5bfcc; // Гейм Адресс
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
Form1->Hide(); // прячемся в трей
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// собственно по таймеру, у меня он кажется установле в 400мс, запускаем основную обработку
// объявляем переменные, замечу борланд как то не адекватно читает память если не инизиализировать переменные заранее
DWORD dwPlCount=0;
DWORD dwMass=0, dwPlId=0;
DWORD dwWid=0;
DWORD dwTarget=0;
iRed=0; iWhite=0; iBlue=0;
//Ищем окошко с названием Perfect World и получаем его хенлд
HWND hHandle = FindWindow("ElementClient Window","Perfect World");
//По хэндлу получаем индефикатор процесса, чтобы читать память
GetWindowThreadProcessId(hHandle, &dwPid);
//открываем выбранный процесс
hProc = OpenProcess(0xfff, false, dwPid);
if (hProc) // проверяем открыли
{
DWORD dwTemp = 0;
DWORD dwFind = 0;
//----------------------читаем таргет GA +20 +B0C
ReadProcessMemory(hProc, (LPVOID) iGA, &dwTemp, 4, NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x20), &dwTarget, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTarget + 0xb0c), &dwTarget, 4 , NULL);
//---------------------------------------------------------
//-------------------------читаем структуру мобов GA + 20 мы уже считали в dwTemp, дальше +8 +24
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x8), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x24), &dwTemp, 4 , NULL);
//------------------------------- в dwTemp GA +20 +8 +24, и считываем +14 это таргет, а GA +20 +8 +24 +18 это начало массива
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x14), &dwPlCount, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x18), &dwMass, 4 , NULL);
//-----------самая порнуха [I*4] + (+0)^J +4: (I in [0..300 hex])
// делаем это в 2х циклах, переменная i это J
// ii это I, 300 в 16тиричной это 768
for (int i = 0; i < 5; i++) {
for (int ii = 0; ii < 768; ii++)
{
//считали GA +8 +24 +18 +[I*4]
ReadProcessMemory(hProc, (LPVOID) (dwMass + ii*4), &dwTemp, 4 , NULL);
// тут пошел разбор страниц
switch (i){
case 1:
//1-я страница GA +8 +24 +18 +[I*4] +4:
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
break;
case 2:
//2-я страница GA +8 +24 +18 +[I*4] +0 +4: и далее...
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
break;
case 3:
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
break;
case 4:
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
break;
case 5:
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
ReadProcessMemory(hProc, (LPVOID) (dwTemp), &dwTemp, 4 , NULL);
break;
default:
;}
// и вот почти пройдена наша 3х этажная хнень)) дочитываем +4 до GA +8 +24 +18 +[I*4] + (+0)^J +4 . тут мы добрались уже до самой ячейки структуры моба
ReadProcessMemory(hProc, (LPVOID) (dwTemp+4), &dwTemp, 4 , NULL);
// мда, названа dwPlId, писал для игроков :) вобщем не пугаемся это айдишка моба GA +8 +24 +18 +[I*4] + (+0)^J +4 +120 MobID
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x120), &dwPlId, 4 , NULL);
// если в записи чтото присутствует читаем и WorldID моба GA +8 +24 +18 +[I*4] + (+0)^J +4 +11C MobWorldID
if (dwPlId > 0){
ReadProcessMemory(hProc, (LPVOID) (dwTemp + 0x11c), &dwWid, 4 , NULL);
dwFind++;
// тут уже непосредственно реализация программы, если в нашем таргете попался моб с идентичным WID, смотрим кто это
// если 18710 значит это злая гусеница, красим трей иконку в красный цвет
// если 18711 в зеленый, ну и если не гусеницы то в серенький
if (dwTarget == dwWid){
switch (dwPlId) {
case 18710:TrayIcon1->IconIndex = 1;break;
case 18711:TrayIcon1->IconIndex = 2;break;
default: TrayIcon1->IconIndex = 0;
;}}
// дальше считаем сферки в 5 или 27 комнате
// просто инкрементируем счетчик, по названию переменной думаю понятно где какой шарик
switch (dwPlId) {
case 18716: iRed++; break;
case 18717: iWhite++; break;
case 18718: iBlue++; break;
default:
;}
dwPlId=0;
}
// если мы прочитанное количество мобов совпало с GA +8 +24 +14: - Mobs count останавливаем циклы, дабы не гонять память в пустую
if (dwFind == dwPlCount) break;
}
if (dwFind == dwPlCount) break;
}
};
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TrayIcon1Click(TObject *Sender)
{
ShowMessage(
"Красных: " + IntToStr(iRed) + "\n\r" +
"Белых: " + IntToStr(iWhite) + "\n\r" +
"Синих: " + IntToStr(iBlue));
}
//---------------------------------------------------------------------------
Ну вот)) критикуйте)) будем добавлять править и все такое
Re: Работаем с хештейблами на примере мобов вокруг нас
jdark, это как раз к вопросу о том, что "программа написанная на Borland Builder ... работает пошустрее [чем под .NET]". На самом деле, не так важно на чём пишут программу, важно как это делают. Твой алгоритм обхода списка мобов - просто жутко не оптимальный по времени исполнения, громоздкий, да ещё в редких случаях обходит не всех мобов. Правда, для задачи подсчёта сфер в кубе это не так критично, а вот если ты варкланов на згд ищешь, такой обход списка никуда не годится.
На самом деле, нет там никаких "страниц памяти", есть массив односвязных списков. Их и надо обходить по очереди. Правильный обход списка есть в PWFrameWork:
[Ссылки могут видеть только зарегистрированные пользователи. ]
________________
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Re: Работаем с хештейблами на примере мобов вокруг нас
я про этот метод в курсе, просто пока некогда на билдере повторить
но я так понимаю говоря про оптимальность ты хотел сказать только про гусениц, для подсчета шариков все равно прийдется пробежаться по всему массиву (а хотяяяя...да, ты же знаешь количество мобов, то и читать память меньше)
присылай свой вариант решения
Последний раз редактировалось jdark; 29.07.2011 в 10:43.
Re: Работаем с хештейблами на примере мобов вокруг нас
jdark, нет, подсчёт у тебя тоже кривой. Одни и те же ячейки считываются из памяти много раз. Переписывать на С++ обход списка мне лень, а на C# код уже есть, я ссылку дал. На словах тоже объяснил, что надо сделать: считать сразу весь массив по GA +8 +24 +18, сразу все 0х300 элементов, потом по отдельности пройти до конца все эти 0х300 списков (большинство из них будут пустыми или из 1 элемента).
________________
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Re: Работаем с хештейблами на примере мобов вокруг нас
jdark, меня всегда удивляет код типа
Код:
for(int i=0; i<10; ++i)
switch(i)
{
case 0: ...
case 1: ...
case 2: ...
...
}
Чем-то подобным меня "радовали" мои студенты-первокурсники, но они не рвались писать ботов для онлайн-игр, гайды по этому делу, и даже по-моему курсовые сами не писали, а скачивали из интернетов
Но таки да, эта версия будет работать гораздо шустрее.
________________
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий).
Re: Работаем с хештейблами на примере мобов вокруг нас
хз)))) вроде как раз удачное применение ))) на самом деле ни когда без бряков не использовал свитч, и даж попадался на ошибки изза этого))) но этот случай точно для него
а так дальше уже хз куда оптимизировать))) с линейным списком разве что ковыряться