Прошу совета вот в такой проблеме, как сделать быстрое сканирование лута?
У меня делается так, при биьте моба постоянно сохраняются его координаты. Как только моб убит, бот идёт собирать лут вблизи этого моба.
Идёт проход по всему массиву лута и вычисление расстояния до точки, где умер моб. Если это расстояние в норме(то-есть лут вблизи моба), то он собирается(это если упрощённо). Но почему-то при сканировании лута чувствуется задержка секунды 3(хотя сканирование мобов почти так же сделано, но происходит быстро, хотя тоже не настолдько, как хотелось) Ниже код, как лучше его оптимизировать/переделать? Или может как нибудь можно "одним залпом" считать весь массив лута? Так же интересует такой вопрос, при считывании какого-нибудь параметра лута происходит ReadProcessMemory несколько раз в зависимости от длины цепочки оффсетов, к примеру 5 раз. Судя по коду ReadProcessMemory вызовется 0x300*(5+5+5)=11520 раз. При том что при каждом считывании у меня происходило открытие и закрытие процесса. Процесс я открыл 1 раз в начале работы, но существенного прироста скорости не увидел. Можно ли как-нибудь считать весь массив лута за 1 Read? И будет ли это быстрее(всётаки обьём считанных байт намного увеличится)? И кто как делает сканирование по массивам?
Код:
void BOT::ScanLoot()
{
msg="Собираем лут";
if (count==0) Sleep(1000); // Ждём секунду пока инфа о новом луте придёт с сервера
if (count<0x300) // если не конец массива
while (client.mem.lootWID(count)==0) //пока не наткнёмся на существующую кучку
count++;
if (count<0x300) //конец ещё не достигнут
{
float dist=Dist(client.mem.lootCoord(count),Target);
if ((dist<6)&&(client.mem.lootType(count)!=2)) // это не рес и лежит вблизи моба
{
st.Push(); // запомним режим сканирования
st.Action=A_GET_LOOT; // Переход в режим сбора кучи
}
else count++; //Проверяем следующую кучу
}
else // всё, конец массива
{
count=0; // глобальный счётчик обнулим
lootgotow=true; // лут собран
st.Pop(); // восстанавливаем предыдущий режим
}
}
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 14.06.2012 в 11:32.
Хм всегда замечял что вид моба равен виду лута который с него упадет.
Хм.. Странно.. Не должно так быть.. Если с моба упало 2 кучки в каждой по 1 одинаковому ресу, то получается что в массиве лута присутствует 2 совершенно одинаковых элемента. Как тогда клиент их различает, ведь и ID и WID у этих двух кучек с одного моба одинаков? А если случилось такое, что другой персонаж убил моба с WID 111, с него выпало 4 кучки, каждая с WID 111, моб реснулся(с тем же самым WID) и затем пока чужой лут ещё лежит, я убил этого моба, и выпало ещё 4 кучки, каждая с WID 111. Итого получается что будут лежать 8 кучек с одинаковым WID, причём половина лута не моя.. Странно всё это... Проверить надо..
Может в структуре лута помимо WID самой кучки лежит ещё и WID моба с которого это выпало?
Есть ли в консоли команда, включающая показ WID лута?
Пока что решил оптимизировать "в другую сторону". Избавиться от всех ReadMemory и использовать данный БритишКолонистом код
[quote="BritishColonist;2766875"]А этот код загружает структуру игрока и некоторые нужные оффсеты:
Но его придётся инжектить. Отсюда вопрос - как вернуть из инжекта к примеру InventoryStart, если я не использую внедрение ДЛЛок? Есть вариант что InventoryStart тоже будет лежать в клиенте, но чтобы его получить оттуда, опять же придётся использовать ReadProcessMemory, итого 768 раз. Хоть и в 15 раз меньше, но всё же хотелось бы сразу получить значение
И ещё в догонку один вопросик. Допустим я хочу вообще избавиться от чнетия по цепочкам оффсетов. Я создам функцию, которая будет это делать и помещать готовое значение по заданному мной адресу. Дополню этой функцией клиент, а именно заинжекчу её, после чего она будет работать с клиентом, а я в свою очередь из своей проги буду считывать только одно значение по определённому мной адресу, тогда придётся делать так, чтобы поток с моей функцией считывания по цепочке работал циклично(чтобы перед считыванием из своей проги не запускать постоянно этот поток) Можно ли сделать такой поток, который мы запустили и не стали дожидаться его завершения, и к тому же он самоповторялся после окончания его кода?
Добавлено через 2 часа 12 минут
Кто может помочь с "тыканьем меня носом" в нужную информацию для тупых?
Хочу сделать:
1)Создать ДЛЛ, в которой есть множество функций с ассемблерными вставками, позволяющими читать значения по цепочкам быстро и возвращать значение.
2)Инжектить эту ДЛЛ в процесс PW, чтобы она "чувствовала себя" в адресном пространстве PW, и работала с памятью клиента без всяких получений доступа и открытий процессов.
3)Обращаться к функциям этой ДЛЛ из своей проги, куда и получать значения из этих функций.
Хотелось бы почитать информацию, досконально разжёванную:
Как вызывать функции внутри родной ДЛЛ(читал читал, так и не врубился, везде слишком сложно обьясняют)?
Как вызывать функции внутри ДЛЛ, внедрённой в чужой процесс?
Как вообще создать ДЛЛ, содержащую несколько функций, к которым можно из проги обращаться?
Добавлено через 6 часов 12 минут
Цитата:
Сообщение от dwa83
Как вызывать функции внутри родной ДЛЛ(читал читал, так и не врубился, везде слишком сложно обьясняют)?
Как вызывать функции внутри ДЛЛ, внедрённой в чужой процесс?
Как вообще создать ДЛЛ, содержащую несколько функций, к которым можно из проги обращаться?
В 1 и 3 разобрался
С 2 почти разобрался, и можно с клиентом вытворять что хочешь посредством функций внедрённой ДЛЛки, но вызывая их из нашей проги. Осталось научиться получать адреса внедрённых функций..
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 14.06.2012 в 20:01.
Причина: Добавлено сообщение
Идёт проход по всему массиву лута и вычисление расстояния до точки, где умер моб.
У тебя, по-моему, нет выхода из перебора, когда нашли весь лут. Мы же заранее знаем сколько всего лута в локации. Может поэтому тормозит?
________________
-------------------------------------------- PerfectAutoLogin v 7.4 - Совершенный автологин для Perfect World [RUOFF, PWI, Фришек 1.4.4 - 1.4.5]
-------------------------------------------- [for 1.4.6] PW Patcher 12.0 - Патч на Горны, Красный (да и любой) чат, Анфриз, Бесконечный зум, Моментальный разгон на полете для RUOFF, PWI и прочих 1.4.6 и фришек 1.4.4, 1.4.5.
-------------------------------------------- InGamePatcher 1.2 - патчер для серверов 1.4.5 и 1.4.4 работающий с включенной игрой.
--------------------------------------------
Так же интересует такой вопрос, при считывании какого-нибудь параметра лута происходит ReadProcessMemory несколько раз в зависимости от длины цепочки оффсетов, к примеру 5 раз.
цепочку офсетов достаточно считать один раз. например: где-то вначале (у меня в конструкторе) вычисляем смещение
static DWORD InvTable[] = {Game_Adress,0x34,0xD18,0xC};
static DWORD InvCount[] = {Game_Adress,0x34,0xD18,0x10};
дальше в коде:
Код:
CountCell=(int)ReadDWORD(OffSetInvCount); // определяем колличество доступных ячеек
for ( int i=0; i < CountCell; i++)
{
AdressCell = ReadDWORD(OffSetInvList + (i * 4));
byte TmpCell[ 0x1A0]; // длина структуры ячейки инвентаря
ReadArrayByte(AdressCell,TmpCell, 0x1A0);
if (AdressCell!=0)
{ CellInventory* pCellInv=new CellInventory;
pCellInv->Cell =i;
pCellInv->ID = *((DWORD*)&TmpCell[ OffSetItemInvID]) ;
pCellInv->Type = *((DWORD*)&TmpCell[ OffSetItemInvType]) ;
pCellInv->Count= *((DWORD*)&TmpCell[ OffSetItemInvCount]) ;// Колличество в ячейке
pCellInv->AdressCell=AdressCell;
InventoryList.SetAt (pCellInv->Cell,pCellInv);
}
}
тоесть на каждый итем в инвентаре затрачиваем всего 2 ReadProcessMemory. раз для адреса, другой для считывания массива байт. потом уже приводим типы.
так же и с любыми списками.
считать один раз как массив байт и привести типы намного быстрее чем считывать по по одному значению.
что- же касаемо ДЛЛ, тут одна незадача- нельзя напрямую дергать методы из своего процесса. как вариант- передавать данные через пайпы или мейлслоты. никакого выиграша в скорости. если знаешь способ как дернуть
метод из ДЛЛ в чужом процессе и вернуть данные- поделись плз.
используя инжект можно получить данные из процесса:
Это кстати да, может помочь, надо попробовать, но как быть в случае если некоторые кучки занимают последние места в массиве? Тогда всё равно получится перебор всего массива..
ПС: ДЛЛ похоже делать не буду, помоему лучше видеть тормоза и смерть бота из-за них, чем взрывать себе мозг поиском адресов функций во внедрённой дллке..
Добавлено через 11 минут
Цитата:
Сообщение от GenOstr
если знаешь способ как дернуть
метод из ДЛЛ в чужом процессе и вернуть данные- поделись плз.
[Ссылки могут видеть только зарегистрированные пользователи. ]
тут написаны функции для получения адресов методов внедрённой дллки(есть так же выполнение функции и получение результа), но я запарился с получением одного из параметров..
// Находит нужную функцию в указанной DLL в указанном процессе.
void* GetProcAddress(HANDLE hProcess, HMODULE hLib, const char* name)
Цитата:
...Но если DLL внедрялась с помощью создания в процессе-жертве потока, поточной функцией которого является LoadLibrary, можно поступить проще. В этом случае код завершения потока является возвращаемым значением LoadLibrary, то есть как раз адресом загрузки DLL в процессе-жертве.
Как получить код завершения потока?)) И он ли подставляется в параметр HMODULE hLib, я так и не смог вкурить))
Мы можем найти адрес нужной функции в длл и создать поток по этому адресу, а результат работы функции можно как то получить в результате работы CreateThread, но я не вкурил как(
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 15.06.2012 в 00:03.
Причина: Добавлено сообщение
Получить адрес загрузки DLL.
Получить адрес функции.
Вызвать функцию при помощи CreateRemoteThread.
(опционально) Дождаться завершения потока и получить возвращаемое значение функции вызовом GetExitCodeThread.
используя инжекты, мы автоматически используем все это. только вместо "получить адрес функции" делаем "загружаем свою функцию (код) в чужой процесс.
используя инжект можно получить данные из процесса:
Тоже об этом думал, но тут появляется сам инжект(создание потока) и ReadProcessMemory чтобы считать готовое значение(или оно по другому получается?). Получится ли так выигрыш в скорости?
Добавлено через 7 минут
Цитата:
Сообщение от GenOstr
используя инжекты, мы автоматически используем все это. только вместо "получить адрес функции" делаем "загружаем свою функцию (код) в чужой процесс.
Длл посредством некоторых манипуляций загружает сам клиент, и я, почитав темку по ссылке, понадеялся использовать функции в этой длл как из своей длл, но видимо всё не так - опять адреса функций и потоки. Потому я забил на это дело.
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 14.06.2012 в 22:24.
Причина: Добавлено сообщение
Вот как сделано у меня.
Увы, избежать ReadProcessMemory не получиться. выход: внедрять полностью свою программу в клиент, и работать в адресном пространстве клиента. но тогда другая проблема: интерфейс с пользователем надо через .опу делать.
по поводу выиграша скорости. есть разумные пределы. лично я задержку ввожу, чтоб клиент успел отреагировать.
все зависит от того, насколько правильно и продумано составлен алгоритм.
например у меня в вечном цикле организовано считывание инфы. организовано много потоков, каждый занимается своим делом. слежение за здоровьем, мобами и т.д.и т.п. цикл считывания прошол- запускаются потоки обработки.
есть потоки приоритетные, есть которые можно приостановить в случае ненадобности.
ктоме того, если возвращаешь результат успешности ReadProcessMemory- тут свои заморочки. бывает если попадет в залоченую память- может долго пытаться считать. я по-этому и перешол на считывание массива вместо последовательного считывания значений
Последний раз редактировалось GenOstr; 14.06.2012 в 22:34.
вариант отказа от ReadProcessMemory и использования ДЛЛ.
1.загружаем с помощью Loadlib свою длл, адреса функций получить не проблема. кода примеров море.
2. организовываем с помощью маппедфайла (пайпов, мейлслотов и т.д.) взаимодействие.
причем работать должно в полу-дуплексе. или два канала. по одному командуем, по другому получаем.
3. организовываем в своей ДЛЛ обработку очереди сообщений). нам же надо сказать что хотим получить.
будет выиграш в скорости - НЕТ.
проблемы: синхронизация между посылкой команды и получением результата. -решаемо.
плюсы: крутясь в процессе клиента отпадают проблемы синхронизации данных. тоесть нормально юзаются критические секции самого клиента
Вообще изначально я длл(или инжект с такой же функцией, выполняющийся в бесконечном цикле) хотел использовать для такой цели:
1)Выделяем в памяти процесса специальний массив для хранения конечных значений.
2)Внедряем в клиент функцию, которая бесконечно работает, считывает по цепочкам нужные значения, и уже готовые записывает в массив.
3) Мы уже из нашей программы Всего одним Read получаем всё что нам нужно из этого массива.
Жизнеспособен ли такой вариант?
А после я уже задумался о получении значения прямо вызвав функцию внедрённой длл, в чём нифига не преуспел.
Жизнеспособен. но какими силами? и главное- зачем? можно пойти дальше.для чего мы все это мутим? правильно- чтобы получить данные. как мы знаем почти все нужные нам данные хранятся в хеш-таблицах и в редких случаях в связных списках. сами данные- это структуры. как поступили бы правильные пацаны? они бы создали свои прототипы таблиц и списков. благо структура их извесна. потом просто присвоением адреса типа myHash *pHash= ((myHash*)adressHashClient) подключали данные клиента. дальше работа тривиальна. конечно, это все мутим в длл.
итого имеем:всю рутину крутим в ДЛЛ, на выход подаем только обработаные данные. как ты и хотел. Но правильные пацаны редко пишут ботов, они как правило, по другую сторону баррикад )).