Author Topic: Снять ограничения в READMEM на SIZE, для чтения текстовых данных.  (Read 3792 times)

0 Members and 1 Guest are viewing this topic.

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
При попытке оптимизации кода, уперся в ограничение размера блока читаемой информации.
Желательно снять ограничения в READMEM на SIZE, для чтения текстовых данных или добавить новую команду для чтения текстовых данных из памяти процесса.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Ну тут можно же извернуться в пару строк. Читать побайтово и писать в массив или в строку.

Вот пример чтения строки из памяти кликермана:


Или имелось в виду чтото другое?

Johnny

  • Создатель
  • Герой форума
  • *
  • Posts: 593
    • View Profile
А в каком формате у вас текст? Однобайтовый ANSI? Двухбайтовый Юникод?..
Нет там никаких "ограничений". Все что кажется ограничением - это лишь недопонимание того, что и откуда берется.
Команда чтения памяти - команда довольно низкого уровня. Самого представления данных (число, число с точкой, строка) в ней быть не должно.
size в данном случе лишь описание стандартных СИшных целочисленных типов, сделанное по аналогии с Artmoney

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Символы 2х байтные. Длина текста до 96 байт в конце 0x0.

Читаю данные из массива указателей в памяти процесса. Процесс добавляет новые указатели в конец массива и затирает устаревшие, сдвигая хвост ближе к началу.
Абсолютные адреса объектов в конце массива изменяются, если одновременно удаляются и добавляются новые объекты (дроп, смерть мобов, уход и появление в зоне видимости).
Нужно найти по координатам ближайшего моба. На 35-50 указателей уходит 2-3 сек. А могут быть сотни, если дроп не собирать - тысячи объектов. Пока досчитаешь до конца, в  середине что-нибудь изменится.
 
Сначала идут фильтры. Отбор всех мобов, отбор живых мобов (мертвые исчезают не сразу), исключение мобов на других уровнях(выше-ниже), посимвольное чтение имени моба, отбор нужных имен мобов (в этом же цикле определяется ближайший).
Первые 12 объектов, вещи на игроке, последний объект сам игрок. Остальное мобы, персы, npc, дроп.

Code: (clickermann) [Select]
      $minD = 0
      print("+ТАБЛИЦА МОБОВ+")
      FOR ($a=12, $a < $_kp)  //0
         
         $_addr_zap1 = 0x0000000C * $a + $_tab + 8
         $_zap1 = readmem($_pid, $_addr_zap1, 4)
         if($_zap1 != 0x00000000)
            $_addr_UserTO = $_zap1 + 0x00000004  //адрес таблицы User в ТО
                       
            $_UserTO = readmem($_pid, $_addr_UserTO, 4)
            if($_UserTO != 0x00000000)
               
               //перс 00000, моб 00101, npc 00100
               $_UserTO_0 = readmem($_pid, ($_UserTO + 0x00000000), 4)
               if($_UserTO_0 = 0)
                  $_UserTO_4 = readmem($_pid, ($_UserTO + 0x00000004), 4)
                  if($_UserTO_4 = 0)
                     $_UserTO_8 = readmem($_pid, ($_UserTO + 0x00000008), 4)
                     if($_UserTO_8 = 1)
                        $_UserTO_C = readmem($_pid, ($_UserTO + 0x0000000C), 4)
                        if($_UserTO_C = 0)
                           $_UserTO_10 = readmem($_pid, ($_UserTO + 0x00000010), 4)
                           if($_UserTO_10 = 1)
                             
                              $_mobHPmax = readmem($_pid, ($_UserTO + 0x78), 4) // mobHPmax
                              $_mobHPtek = readmem($_pid, ($_UserTO + 0x7c), 4) // mobHPtek
                             
                              if(($_mobHPtek = 0)and($_mobHPmax!=0)) //моб мертв
                              else //моб жив или нет данных
                                 //начало таблицы AActor в ТО
                                 $_AActorTO = readmem($_pid, ($_UserTO + 0x00000158), 4)
                                 if($_AActorTO != 0x00000000)
                                   
                                    $_koor_Z1 = readmem($_pid, ($_AActorTO + 0x000001C4), 2)
                                    $_koor_Z0 = readmem($_pid, ($_AActorTO + 0x000001C6), 2)
                                    CALL("float_int.dll", $_koor_Z0, $_koor_Z1)
                                    $_koor_Zf = $_return1
                                   
                                    $_mod =  $_koor_Zf - $_koor_Zpf
                                    if(($_mod < $_modZ) and ($_mod > $_mod_Z)) //искл по высоте Z
                                       
                                       //начало таблицы SrvAActor в ТО
                                       $_SrvAActorTO = readmem($_pid, ($_AActorTO + 0x0000003c), 4)
                                       if($_SrvAActorTO != 0x00000000)
                                          $_AActorTrgTO = readmem($_pid, ($_SrvAActorTO + 0x00000400), 4)
                                          if($_AActorTrgTO != 0x00000000)
                                             $_IDtrgTO = readmem($_pid, ($_AActorTrgTO + 0x00000060), 4) //ID цели из ТО
                                             IF($_IDtrgTO = $_ID)
                                                print("В ФОКУСЕ")
                                                //тут будет досрочный выход из цикла, а пока заглушка
                                             end_if
                                          end_if
                                       end_if
                                       
                                       //побайтно счититываем имя
                                       $_name = ""
                                       $_kb = readmem($_pid, ($_UserTO + 0x0000001C),2) //<----
                                       $b = 0
                                       WHILE ($_kb != 0)
                                          if($_kb!=39)
                                             $_bukva = char($_kb)
                                             $_name = strconcat ($_name, $_bukva)
                                          end_if
                                          $b = $b + 2
                                          $_kb = readmem($_pid, ($_UserTO + 0x0000001C + $b), 2)
                                       end_cyc
                                       
                                       for($r=0, $r < $_kol_name)  //дано несколько имен
                                          if($arr_name[$r] = $_name) //проверка на совпадение
                                             
                                             $_n = $_n + 1
                                             
                                             $_koor_X1 = readmem($_pid, ($_AActorTO + 0x000001BC), 2)
                                             $_koor_X0 = readmem($_pid, ($_AActorTO + 0x000001BE), 2)
                                             CALL("float_int.dll", $_koor_X0, $_koor_X1)
                                             $_koor_Xf = $_return1
                                             
                                             $_koor_Y1 = readmem($_pid, ($_AActorTO + 0x000001C0), 2)
                                             $_koor_Y0 = readmem($_pid, ($_AActorTO + 0x000001C2), 2)
                                             CALL("float_int.dll", $_koor_Y0, $_koor_Y1)
                                             $_koor_Yf = $_return1
                                             
                                             $_ar_d[$_n] = INT(DIST($_koor_Xpf,$_koor_Ypf,$_koor_Xf,$_koor_Yf))
                                             $_ar_UserTO[$_n] = $_UserTO //начало UserTO
                                             $_ar_AActorTO[$_n] = $_AActorTO //начало AActorTO
                                             
                                             $_ar_name[$_n] = $_name
                                             $_ar_id[$_n] = readmem($_pid, ($_UserTO + 0x00000018), 4) //id
                                             
                                             //определение min1
                                             if(($_n = 0) or ($_ar_d[$_n] < $min1D))
                                                $min1D = $_ar_d[$_n]
                                                $min1In = $_n
                                             end_if
                           
                                             $r =  $_kol_name //досрочный выход если имя совпало
                                          end_if
                                       end_cyc
                                    end_if
                                 end_if
                              end_if
                           end_if
                        end_if
                     end_if
                  end_if
               end_if
            end_if
         end_if
         $_kp = readmem($_pid, $_addr_iTO, 4) - 1 //кол-во - игрок
      END_CYC
      print("-ТАБЛИЦА МОБОВ-")
 

Для ускорения хотел там, где в памяти текст, читать сразу 96 байт, а не по 2 байта выбирать.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Нужно найти по координатам ближайшего моба. На 35-50 указателей уходит 2-3 сек. А могут быть сотни, если дроп не собирать - тысячи объектов. Пока досчитаешь до конца, в  середине что-нибудь изменится.

Может ты и прав, еслиб читало сразу пачкой, это бы ускорило работу. Но мое мнение, все это время уходит на другие действия, типа чтения указателей и прочего.

Вот к примеру я попробовал только читать 50 раз по 96 байт (возможно имелось ввиду не байт а символов?) и составлять строку.
 
300-400мс, тоже не мало, согласен, но все же...
Code: (clickermann) [Select]
$pid = HGETPID($_hwnd_self)
$adr = 0x00B978BE


$t = $_ms
FOR($n=0,$n<50)  //50 раз по 96 байт
     
   $str = ""
   
   FOR($a=$adr,$a < $adr+96,2)
      $str = STRCONCAT ($str, char(READMEM($pid, $a, 2)))
   END_CYC
   
   //  print($str)   
END_CYC

print($_ms - $t)  //  300-400мс

halt



Еще, не по теме  :-X

Вижу вызываешь длл для перевода из целого в число с точкой "float_int.dll" . А тебе не кажется, что кликер посчитает "немного" быстрее чем вызов отдельного файла, ожидание ответа и прием параметра? http://crapware.aidf.org/forum/index.php?topic=3749.msg29132#msg29132  А еще если имен $_kol_name будет целая куча?

Code: (clickermann) [Select]
$float = POW(-1,int($int/2147483648)) * pow(2,int($int/8388608) - int($int/2147483648)*256-127) * (1+(($int - (int($int/8388608) - int($int/2147483648)*256)*8388608 - int($int/2147483648)*2147483648)/POW(2,23)))
Можно оптимизировать, разделить на отдельные переменные чтобы не считать лишнее, будет еще быстрее.

Но я уверен, ты видел эти расчеты, значит вызов длл всеже быстрее?  :-\

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
48 символов максимально длинное название. Каждый символ 2 байта.

Время тратится на перевод чисел с плавающей точкой в целое. Вычисление расстояния между ними. Чтение и сравнение имен.
1 Для ускорения сделаю 2 списка имен. Нужных и не нужных мобов. Который короче, тот и пойдет в работу.
2 Попробую распараллелить чтение и обработку массива на несколько потоков.
3 Твоя формула на 1мс считает быстрее DLL  (для передачи в DLL приходиться разбивать 4 байта на 2х2 байта, а внутри DLL собирать обратно).
« Last Edit: January 06, 2019, 08:51:13 AM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
2 Попробую распараллелить чтение и обработку массива на несколько потоков.
обратно).

Скорости потоки не добавляют, проверено. Все действия и вычисления между потоками выполняются по очереди, не одновременно. Как вариант - распараллелить чтение и обработку массива на несколько кликерманов.


3 Твоя формула на 1мс считает быстрее DLL  (для передачи в DLL приходиться разбивать 4 байта на 2х2 байта, а внутри DLL собирать обратно).


Я проверил, моя формула работает медленнее чем вызов длл :o  :-\ . НО это ничтожные 0.2 мс формулой, и 0.15 мс вызовом длл  ;D. Проверял на прогонах по 1000 переводов из int во float.

И всеже формулой в твоем варианте выйдет быстрее, так как не нужно два раза читать память по 2 байта, а за один раз прочитать 4 и сразу пересчитать в нужное с точкой.

Кстати c "float_int.dll" пришлось повозиться, так как он не принимал большие числа. Только со временем понял что на выходе то может выйти настолько большое число, которое просто не влезет в возвращаемую $_return1 (4 байта)   :D.



Еще варианты:

Сохранить в файл дамп нужного куска памяти, и далее работать с этим файлом  - КМ v4.14 - FREADDATA. Неуверен, что так будет быстрее  :D

Стопроцентный вариант, не в обиду кликерману  :-X : переписать все эти чтения памяти и вычисления полностью в длл. Вроде там ничего сложного нет, почти копипаст. Время выполнения уменьшится до пары миллисекунд  ;).

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Если бы Johnny тип передаваемых данных поднял до int64, а на вход и выход массивы. Тогда можно все в DLL считать. А в нынешнем варианте, вход переменные через запятую, выход 4 байта и все.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Если бы Johnny тип передаваемых данных поднял до int64, а на вход и выход массивы. Тогда можно все в DLL считать. А в нынешнем варианте, вход переменные через запятую, выход 4 байта и все.
Вообще, int64 и кликер не поддерживает  :(. Скорее всего при больших числах в нем идет тип float 4 байтный (мне так кажется...).
Покажу на примере:
Code: (clickermann) [Select]
$b = 72000000000000000 //возьмем какоето число, больше 32 бит.

FOR($a=0,$a<100)
    print($b + $a)
    wait(1)
END_CYC

halt

лог:
Code: (текст) [Select]
15:57:02 72000000000000000
15:57:03 72000000000000000
15:57:04 72000000000000000
15:57:05 72000000000000000
15:57:06 72000000000000000
15:57:07 72000000000000008
15:57:08 72000000000000008
15:57:09 72000000000000008
15:57:10 72000000000000008
15:57:11 72000000000000008
15:57:12 72000000000000008
15:57:13 72000000000000008
15:57:14 72000000000000016
15:57:15 72000000000000016
15:57:16 72000000000000016
15:57:17 72000000000000016
15:57:18 72000000000000016
15:57:19 72000000000000016

Поэтому с передачей туда сюда int64 пока можно подождать. А вот массивы передавать, это тема, поддерживаю  ;).

Но пока нет такой возможности, можно воспользоваться передачей инфы через файл - ини или тхт, не важно.  Работает безотказно и быстро.
« Last Edit: January 06, 2019, 08:37:53 PM by dramster »

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Сейчас в CALL используется тип Integer 4 байта, диапазон от -2 147 483 648 до 2 147 483 647
А мне нужен минимум Longword 4 байта, диапазон от 0 до 4 294 967 295
Int64 - 8 байт или Real - 6 байт - это я с запасом мечтал.

Соответственно что бы проходили числа больше 2 147 483 647 или передаем 2x2 байта и в DLL объединяем обратно в 4 байта, или пересчитываем с учетом минуса.
« Last Edit: January 06, 2019, 04:35:42 PM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Ну так это же уже решалось ранее. Просто переделываем отрицательное число в беззнаковое. И наоборот в отрицательное если оно больше 2147483647
Code: (clickermann) [Select]
//перевод в беззнаковое число, если оно отрицательное.
IF($int < 0)
   $int = $int + 4294967296
END_IF

//И наоборот, если оно больше 2147483647 в отрицательное
IF($int > 2147483647)
   $int = $int - 4294967296
END_IF

Както так, вроде не ошибся...

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
В обоих случаях лишние расчеты.

Я прикинул, пожалуй вычисления ближайшего моба можно запихнуть в DLL. На выходе получить указатель на начало таблицы User. А остальные данные читать из Кликермана.