#1 03-12-2006 10:58

Sanchez
Registered: 18-08-2006
Posts: 280

О статье: Меняем игровую память через SCM (San Andreas)

Домашнее задание: проверьте это

054C: use_GXT_table 'POOL' 
01E3: text_1number_styled 'NUM' &0 5000 ms 1  // ~1~

У меня первые четыре байта другие. Это постоянное число или нет?

sb_hw.png

sb_gp.jpg

А про поезд подробнее можно?

 for 0@ = -382229 to -382216
   wait 0 
   &0(0@,1i) = #STREAKC        
 end

Почему используются отрицательные числа?

в San Andreas есть адрес 0x8D44F8.

Почему же в коде этот адрес не встречается?

Last edited by Sanchez (11-03-2007 11:10)

Offline

#2 03-12-2006 12:03

Seemann
Registered: 07-08-2006
Posts: 2,090

Re: О статье: Меняем игровую память через SCM (San Andreas)

2Sanchez

У меня первые четыре байта другие. Это постоянное число или нет?

Нет. Я потому и написал в конце xxxx, чтобы показать, что число может меняться. В общем ты и сам можешь понять это. На твоем прекрасном скриншоте из HWS ясно видно откуда это число берется. Это самый первый опкод в main.scm.

0200 - это опкод 0002 (если выделить его, HWS покажет цифру 2 внизу), 01 - тип параметра - метка. Эти 3 байта всегда постоянны. Четвертый байт - это первый из 4 байтов метки (все метки имеют длину 4 байта). 78060000 - это метка перехода к следующему сегменту: defined models. В MB эти метки отображаются в начале файла: jump @SecondSegment, jump @ThirdSegment и т.д. SB эти метки добавляет автоматически.

Так вот, эта первая метка будет зависеть от размера 1-го сегмента, сегмента переменных. Чем больше у тебя переменных, тем больше сегмент, тем больше значение метки, поэтому числа могут варьироваться на разных майнах.

А про поезд подробнее можно?

Можно, только давай не будем все мешать в кучу. Задай вопрос в соответствующей теме, для этого она и создана.

Offline

#3 10-01-2007 07:33

Seemann
Registered: 07-08-2006
Posts: 2,090

Re: О статье: Меняем игровую память через SCM (San Andreas)

Пока разделы сайта не работают, опубликую здесь

Меняем игровую память через SCM (San Andreas)


1.
Всем известно, что San Andreas поддерживает массивы в SCM.
В общем виде массивы представлены так:

(array name)(index name),(size)(type)

Имя массива и индекса - это переменные, содержащие значения, которые определяют место начала массива (array name) и смещение от этого начала (или номер ячейки в массиве) на определенное число байтов (index name).

Так вот, например, $array($index,11i) будет указывать на определенную ячейку памяти, которая рассчитывается следующим образом:

берется имя (подробнее в разделе DMA) переменной $array, к ней прибавляется значение переменной $index, умноженное на размер одной ячейки.
Например, для типа i (integer) размер одной ячейки равен 4 байтам.

i,f : 4 байта
s   : 8 байтов
v   : 16 байтов

Таким образом, общая формула такова:

cA = aN + (iN * t)
cA  адрес ячейки
aN $array
iN значение $index
t размер ячейки для данного типа

2.
Значение cA (адрес ячейки) - это смещение в main.scm относительно его начала. Все глобальные переменные и глобальные массивы хранятся в теле main.scm в блоке, который идет в самом начале файла (так называемый первый сегмент). Если вы откроете main.scm в хекс-редакторе, вы увидите, что в начале идет очень много нулей. Вот здесь потом и прописываются значения переменных.

Допустим, aN равно $8, iN равно 10, а тип массива Integer, т.е. t равно 4. Тогда cA равно 48. Тогда $array($index,11i) прочитает 4 байта из первого сегмента, начиная с 48-го байта от начала.

3.
DMA. DMA расшифровывается как Direct Memory Access (прямой доступ к памяти). Относительно скриптинга в GTA, речь идет об использовании прямого доступа к конкретной ячейке памяти. Реализуется эта технология путем указания числового имени для глобальной переменной. Например, $100 всегда указывает на сотую ячейку памяти (или четырехсотый байт, т.к. одна ячейка равна 4 байтам) относительно начала первого сегмента SCM.

А вот куда будет указывать $var (например), вы заранее знать не можете, т.к. память для переменных с текстовыми именами распределяется уже компилятором.
Правда здесь есть два исключения:
- Вы можете указать компилятору конкретную ячейку памяти для глобальной переменной командой Alloc.
- Переменные из файла CustomVariables.ini всегда имеют опреденную ячейку.

Трансформируем наш пример в DMA:

$9 = 1
$10($9,11i)

$10 это имя массива, которое определяет его позицию в первом сегменте (40-й байт). $9 равно 1 поэтому cA = 40+1*4 = 44. $10($9,11i) читает и пишет значения в диапазоне [44..47] байты SCM.

Домашнее задание: докажите, что если $9 равно 0, то $10($9,11i) тоже самое что $10.


4.
aDMA. aDMA расшифровывается как Advanced DMA или продвинутый доступ к памяти.
Технология DMA имеет три ограничения:
- нельзя использовать имена $0 и $1, так как они выходят за пределы первого сегмента SCM.
- использование DMA-переменных влияет на размер первого сегмента, а значит и всего файла. Например, если вы используете в скрипте переменную $10000, то размер первого сегмента увеличится до катастрофического значения в ~40 килобайт, даже если у вас во всем файле лишь десяток переменных.
- DMA использует шаг в 4 байта, и вы не имеете доступа к адресам, которые не делятся нацело на 4. Например, вы не можете прочитать [11..14] байты, а только [8..11] - $2 или [12..15] - $3.

aDMA лишен этих недостатков. Вы можете использовать любые значения, кроме отрицательных. Реализуется aDMA через тип данных &. Используется шаг в один байт
Так, переменная &11 будет читать [11..14] байты, &9999999 – [9999999.. 1000002] и т.д.

&0 прочитает первые 4 байта SCM, которые равны 2147xxxxxx
Домашнее задание: проверьте это

054C: use_GXT_table 'POOL' 
01E3: text_1number_styled 'NUM' &0 5000 ms 1  // ~1~

Самое важное, что aDMA не влияет на размер первого сегмента, и вы можете читать/менять значение за его пределами (например код второго сегмента - моделей).

Однако и DMA и aDMA ограничены в размере: максимальные значения для них равны $16383, &65536 соответственно. Поэтому доступный диапазон для таких переменных равен 65536.

5.
Возвращаемся к массивам. Как я уже говорил, для расчета конечной ячейки памяти к имени массива (оффсету) прибавляется содержимое индекса * 4. Теперь попробуем поразмыслить, ведь содержимое переменной не ограничено никакими лимитами (кроме естественно предела в 4,294,967,295 для всех 32-битных приложений, к коим относится и
GTA). А значит теоретически мы может получить доступ к любой единице памяти игры.

Так и есть.

$index = 10 000 000
$10($index,1i) = 1

Этот код запишет 1 в cA = 40+10 000 000*4 = 40000040..3 байт.

Вроде все верно. Одна есть одна деталь: игровой движок рассчитывает конечный адрес cA, исходя из того, что адресация происходит внутри SCM, а значит это смещение будет не абсолютным, а относительным (от начала main.scm в памяти игры).

Так в чем проблема, спросите вы, нужно лишь учесть этот смещение и все. Да, так и есть.
Глобальный адрес main.scm в памяти игры равен: 0xA49960. Именно это значение прибавляется для получения адреса. Поэтому отняв его от значения iN и разделив число на 4 (смотри формулу) мы получим «магическое» значение iN, которое и будет потом, при обработке его игрой указывать на нужную нам ячейку.

Преобразуем формулу с учетом адреса SCM:

cA = 0xA49960 + aN + (iN * t)

Из нее легко видно, что нужно сделать чтобы cA был равен нужному нам адресу.
Есть последняя деталь. Чтобы не возиться с учетом aN, мы устанавливаем его равным 0. Делается это при помощи aDMA, о чем я писал выше.

Конечный код преобразования глобального адреса в «магическое» число:

:MemoryRead32
  0@ -= 0xA49960
  0@ /= 4
  008B: 1@ = &0(0@,1i)
return

Эта функция возвращает в переменной 1@ значение памяти по адресу, переданному в 0@.

Например, есть адрес 0xB7CE50 – текущее количество денег игрока (другие адреса)

Прочитаем сколько денег на счету у игрока:

0@ = 0xB7CE50
gosub @MemoryRead32
054C: use_GXT_table 'POOL' 
01E3: text_1number_styled 'NUM' 1@ 5000 ms 1  // ~1~

...
:MemoryRead32
  0@ -= 0xA49960
  0@ /= 4
  008B: 1@ = &0(0@,1i)
return

Код для записи в память разных значений вы можете прочитать в моем посте на GTAForums.com.

И напоследок.
Не все адреса одинаково полезны.. тьфу, доступны. При попытке изменить/прочитать некоторые из них вы можете получить ошибку с вылетом игры. Будьте осторожны.

Offline

Board footer

Powered by FluxBB