GTA: Modification Area

A website for the GTA modding scene

Search
 
 

Display results as :
 


Rechercher Advanced Search

Latest topics
» Big-game starts raising Schneider's profile
Sun Mar 04, 2012 2:28 am by lavivi

» [Help] cleo created lighting
Thu Oct 14, 2010 1:03 am by findmy012

» Mission Question
Thu Oct 14, 2010 1:02 am by findmy012

» [IV] Spoiler Script
Thu Oct 14, 2010 1:02 am by findmy012

» Mission mod [help]
Sat Sep 18, 2010 5:50 pm by jayd00

» Bc7 Mod Help
Fri Aug 20, 2010 11:19 am by pengpeng

» Found a bug
Fri Dec 18, 2009 4:22 am by _CJ360_

» [IV] Novitec Rosso 599 GTB
Tue Nov 17, 2009 4:22 pm by Kotton

» Hello/Guidance Request
Mon Oct 12, 2009 6:45 am by Adler

Navigation
 Portal
 Index
 Memberlist
 Profile
 FAQ
 Search
Affiliates
image

Image

Image

Image

Image

Image

Image

Image

Image

Image

image

Image

steve-m.com

Image


----- Русский -----

Если ваш сайт содержит большую коллекцию SCM/CLEO-скриптов (больше 16), напишите на мой e-mail, и я добавлю его в список. Приветствуются скрипты, которые не встречаются на других сайтах ... Спасибо. ))))


----- English -----

If your website has a big enough collection of SCM/CLEO scripts (more than 16) notify me by e-mail
, and I will add it to the list. The unique scripts are preferable ... Thank you. ))))

Log in

I forgot my password



December 2016
MonTueWedThuFriSatSun
   1234
567891011
12131415161718
19202122232425
262728293031 

Calendar Calendar


You are not connected. Please login or register

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

View previous topic View next topic Go down  Message [Page 1 of 1]

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



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


Code:

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


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

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

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


Code:

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



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


Code:

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:


Code:

$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
Домашнее задание: проверьте это


Code:

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). А значит теоретически мы может получить доступ к любой единице памяти игры.

Так и есть.


Code:

$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:


Code:

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


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

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


Code:

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


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

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

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



Code:


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.

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

View user profile http://gtamodding.com

View previous topic View next topic Back to top  Message [Page 1 of 1]

Permissions in this forum:
You cannot reply to topics in this forum