# 00058. Работа с игровой памятью (Часть 1- статические адреса)

Работа с игровой памятью (Часть 1: статические адреса)|В этом уроке мы будет разбираться со статическими адресами памяти.|wmysterio|wmysterio||||Работа с памятью одна из самых интересных, так как есть возможность творить с ней что угодно. Нужно помнить, что для работы с памятью требуется наличия оригинального exe-шника версии 1.0 US ( [скачать](https://github.com/wmysterio/scm-scripting-lessons/blob/main/load/gta_sa/raznoe/originalnyj_exe_gta_san_andreas_us_1_0/73-1-0-13/README.md) ). Также нужно знать адреса памяти, чтобы можно было их редактировать. Я лично и сам даже части адресов не знаю, поэтому обращаюсь к брошюрке, где написано большинство адресов.

Адреса делятся на две большие группы: статические и динамические. Статические адреса можно редактировать когда угодно, а вот динамические имеют структуры, то есть нам нужно узнавать адреса и делать некие смещения. Рассмотрим опкоды для работы с адресами. Их всего два:

```
0A8C: write_memory 0xC0BC15 size 4 value 1 virtual_protect 1 // запись
0A8D: 0@ = read_memory 0xC0BC15 size 4 virtual_protect 1 // чтение
```

Здесь:\
0xC0BC15 - адрес памяти\
4 - размер данных, которые нужно записать или прочитать\
1 - флаг снятия защиты

Для примера, возьмем текстовый файл. Представьте, что это память. В файле есть целая куча строк - это будут адреса. В каждой строчке что то записано - это будет значение. Смещение - это переход между строками, то есть установка курсора на нужное место. "0xC0BC15" - это номер строки. Это число, записанное в шестнадцатеричном виде. Если выделить его в SB и нажать горячие клавиши CTRL`+<kbd>H`, то этот загадочный набор будет читабельным для нас - "12631061". Но указывают обычно в шестнадцатеричной системе счисления. **value** - это значение, то есть то, что содержит строка. Сами значения имеют тип, которые определят размер ( в байтах ) для записи или чтение, указанных в опкодах, как "size". Вот таблица известных мне типов и их размер:

| Таблица 1           |                 |
| ------------------- | --------------- |
| Тип ( type )        | Размер ( size ) |
| int32, float, dword | 4               |
| int16, word         | 2               |
| byte, bool          | 1               |

Осталось рассмотреть последний параметр "virtual\_protect". Это своего рода флаг снятия защиты от записи в память. Если поставить "1" - защита снимается, "0" - остается как есть. Вот список статических адресов: [статические адреса памяти](https://github.com/wmysterio/scm-scripting-lessons/blob/main/dir/gta_sa/statichnye_adresa_pamjati/1-1-0-26/README.md).

Я например нашел подходящий адрес: "0xB7CEE4" - вкл/выкл бесконечный бег. Тип значения, которое он может принимать - булево ( **bool** ), значит размер ( **size** ) должен быть "1" ( см. Таблица 1 ). Раз это булевой тип, значит значения могут быть либо "0", либо "1". Выбираем 1 ( включить ). Таким образом, мы получили:

```
0A8C: write_memory 0xB7CEE4 size 1 value {ON} 1 virtual_protect 1 // включить режим
0A8C: write_memory 0xB7CEE4 size 1 value {OFF} 0 virtual_protect 1 // выключить режим
```

Давайте протестируем дробные числа. Адрес в памяти: "0xB7CB64", тип значения - **float**, размер ( **size** ) - "4" байта. Этот адрес отвечает за скорость игры. Давайте изменим её:

```
0A8C: write_memory 0xB7CB64 size 4 value 8.0 virtual_protect 1 // новая скорость
0A8C: write_memory 0xB7CB64 size 4 value 1.0 virtual_protect 1 // стандартная скорость
```

Естественно, в место значений можно использовать переменные. Запись мы рассмотрели. Давайте попробуем считать значение, что находится по адресу. Для примера возьмём тот же адрес скорости игры:

```
0A8D: 0@ = read_memory 0xB7CB64 size 4 virtual_protect 1 // В переменной 0@ будет текущая скорость игры
```

Теперь давайте напишем скрипт, который при нажатии клавиши 4\` включался/выключался бесконечный бег и изменялась скорость игры:

```
{$CLEO}
0000:

var
0@: integer = 0
end

while true
wait 0
 if AND
 0@ == 0
 0AB0: key_pressed 52
 then
 0A8C: write_memory 0xB7CEE4 size 1 value 1 virtual_protect 1
 0A8C: write_memory 0xB7CB64 size 4 value 8.0 virtual_protect 1
 0ACE: show_formatted_text_box "ON"
 0@ = 1
 wait 500
 end
 if AND
 0@ == 1
 0AB0: key_pressed 52
 then
 0A8C: write_memory 0xB7CEE4 size 1 value 0 virtual_protect 1
 0A8C: write_memory 0xB7CB64 size 4 value 1.0 virtual_protect 1 
 0ACE: show_formatted_text_box "OFF"
 0@ = 0
 wait 500
 end
end
```

Обратите внимание на цикл **while true**. Если есть такая запись, значит цикл будет выполняться бесконечно ( точнее не будет завершаться, пока его не прервут ). Его очень часто используют в скриптеры и, надеюсь, в скорем будущем и вы тоже присоединитесь ;)

Тест в игре показал, что всё работает как ожидалось. На следующих уроках о адресах памяти мы рассмотрим динамические адреса.|3462|1|0||rabota\_s\_igrovoj\_pamjatju\_chast\_1\_statichnye\_adresa|1499597654


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lessons.sannybuilder.com/00100/00500/00058.-rabota-s-igrovoi-pamyatyu-chast-1-staticheskie-adresa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
