Уроки моддинга
GTA Script GeneratorЗадать вопрос
  • О сайте
    • Проекту помогали
  • GTA SA, VC, III (PC, Classic)
    • Раздел 01. Основы
      • Общие сведения об уроках и минимальный набор программ
      • Установка Sanny Builder. Базовые настройки
      • Синтаксис, комментарии, опкоды, команды. Ключевые слова
      • Типы данных. Литералы. Константы
      • Типы проектов
      • Переменные. Операторы
      • 00012. Редактирование main.scm. Переменные (Часть 3)
      • 000175. Трюк с локальными массивами
      • 00073. Переменные, как члены класса. Коментарии в поиске опкодов. Макросы
      • 00017. Условия в Sanny Builder (Часть 1)
      • 00018. Условия в Sanny Builder (Часть 2)
      • 00019. Условия в Sanny Builder (Часть 3)
      • 000181. Условия в Sanny Builder (Часть 4)
      • 00045. Циклы (Часть 1 - while)
      • 00047. Циклы ( Часть 2 - for )
      • 00049. Циклы ( Часть 3 - repeat ). Вложенные циклы
      • 00087. Таблицы переходов
      • 00059. Подключение текстовых файлов, scm-функции
      • 000155. Использование SCM-функций (опкод 0AB1)
      • 000162. Используем scm-функции в качестве проверок
      • Координаты. Угол. Получение координат и угла Z
      • 000154. Вся правда о wait 0
    • Раздел 02. CLEO
      • Текст
        • 000158. Динамическая GXT-таблица или виртуальные GXT-записи
        • 00033. Работа с текстом
      • Игрок
        • 00021. Одежда СЖ
      • Транспорт
        • 00026. Создание транспорта
        • 000115. Работа с грузовиками и прицепами
        • 000172. Эктра-части автомобилей
        • 00042. Всё о поездах
        • 00080. Тюнинг транспорта, работа с компонентами тюнинга
        • 00029. Транспорт и команды, свойственны ему
        • 00046. Плавающие и лётные средства передвижения
        • 00082. Работа с частями автомобиля
      • Актёры
        • 000152. Заставляем актёра говорить. Аудио-таблицы
        • 000177. Трюк со специальными актёрами
        • 00020. Типы пешеходов, номера банд и отношение между ними
        • 00024. Модель. Создание актёра
        • 00028. Актёры и команды, свойственны им. Команды для игрока
        • 00056. Специальные актёры
        • 00060. События актёров
        • 00084. Модели поведения актёров
      • Объекты
        • 00030. Объекты и команды, свойственны им
        • 00025. Создание объекта
        • 000142. Метание объектов
      • 00027. Пикапы
      • 00031. Маркеры и сферы
      • 000122. Типы чекпоинтов, маркеров. Детальный обзор
      • 00055. Cleo. Основные понятия, отличия от main'а, простые примеры
      • 00061. Cleo-миссии
      • 00064. Работа со стартерами ( Cleo - Часть 1 )
      • 00065. Работа со стартерами ( Cleo - Часть 2 )
      • 00083. Запуск другого потока с Cleo-скрипта
      • 00079. Немного о глобальных CLEO-переменных
      • 00066. Работа со стартерами ( Дополнительные условия )
      • 000137. Группы в GTA San Andreas
      • 00098. Последовательность в анимации
      • 000120. Пути пешеходов и анимационные пути
      • 000178. RRR-файлы в GTA SA. Как их делать и использовать-
      • 000180. Длинные последовательности в анимации
      • 00022. Типы зон. Аудио-зоны
      • 00023. Работа с клавишами. Делаем сохранение
      • 00037. Анимация. Основные команды и примеры их использования
      • 00041. Работа с интерьерами
      • 00036. Катсцены и всё, что необходимо для примитивного видеоролика
      • 000174. Снова статистика игрока
      • 00040. Как создать свой чит-
      • 00090. Работа с гаражами
      • 000176. Выделение памяти
      • 00076. Статистика игрока
      • 00094. Пропуск видеороликов
      • 00072. Работа со светом. Прожектор
      • 00092. Работа с файлами ( форматированное чтение )
      • 00093. Работа с файлами ( Дозапись )
      • 00071. Визуальные эффекты в GTA San Andreas
      • 00069. Взрывы и всё, что связано с огнём.
      • 00086. Движения объектов и эффектов
      • 00068. Использование RC
      • 00067. Использование турелей
      • 00057. Работа с INI-файлами ( запись и считывание )
      • 00044. Работа с панелями ( таблицами )
      • 00043. Работа с аудио
      • 00038. Рисование на экране (Часть 1 - Текст)
      • 00039. Рисование на экране (Часть 2 - Текстуры)
    • Раздел 03. MAIN.SCM
      • 0009. Редактирование main.scm. Потоки и опкоды (Часть 1)
      • 00014. Редактирование main.scm. Потоки и опкоды (Часть 2)
      • 00013. Редактирование main.scm. Потоки и опкоды (Часть 3)
      • 00062. Работа со стартерами ( MAIN.SCM - Часть 1 )
      • 00063. Работа со стартерами ( MAIN.SCM - Часть 2 )
      • 00054. Внешние скрипты в main.scm
      • 00050. Статус-тексты
      • 00053. Таймеры
      • 00035. Делаем простую миссию
    • Раздел 04. Разное
      • 00088. Интересные опкоды (Часть 1)
      • 00089. Интересные опкоды (Часть 2)
      • Интересное в скриптинге
      • 000167. Интересное в скриптинге. Часть 2
      • 00081. Защита скриптов, снятие слабой защиты
      • 000157. Защита скриптов,снятие её + Подробнее об $NOSOURCE
      • 000121. Варианты использования main.scm
      • 000179. Избавляемся от "ёлочек"
      • 000171. Контроль за перемещениями мыши
      • 000182. Колода карт в GTA San Andreas
      • Работа с магазинами
      • 00091. Создания собственных классов и кейвордов
      • 00085. Работа с битами переменных
      • 00051. Работа с HEX. HEX-буфер
      • 00097. Написания DLL библиотек и использование их с скриптах
    • Раздел 05. Игровая память
      • 00058. Работа с игровой памятью (Часть 1- статические адреса)
      • 00074. Динамические адреса памяти. ( Часть 1 - структура актёра )
      • 00075. Динамические адреса памяти. ( Часть 2 - структура автомобиля )
      • 00077. Динамические адреса памяти. ( Часть 3 - структура объекта )
      • 00096. Игровая память. Динамические адреса (структура weapon.dat)
    • Раздел 06. Алгоритмы и примеры
      • 000153. Пример полноценной миссии "Ограбление"
      • 00095. Как сделать нервометр-
      • 00052. Пример полноценной миссии "Взрывчатка"
      • 000114. Делаем спидометр!
      • 000161. Очень длинные миссии в main.scm
      • 000112. Делаем графическое меню
      • 000113. Делаем гоночную миссию ( SARMC v0.9 )
      • 000133. Делаем диалоги в миссиях
      • 00032. Делаем простой скрипт (приходим к точке и убиваем нужную цель)
    • Раздел 07. Plugin SDK (SA)
      • Простейший плагин
      • Работа с массивами объектов
      • Рисуем
      • Короны
      • Класс шрифта (CFont)
    • Раздел 08. Руководство по программам
      • Руководство по использованию программы GTA-SA Crazy IMG Editor
      • Руководство по использованию программы Ped Editor
      • Руководство по использованию программы Rus2gxtCoder
      • Руководство по использованию программы FXT Editor
      • Руководство по использованию программы GTA Animation Manager
      • Руководство по использованию программы TXD Workshop
      • Руководство по использованию программы GTA GXT Editor
      • Руководство по использованию Map Editor
      • Руководство по использованию программы MapCleaner
  • GTA 4 (PC)
    • Раздел 01. ScriptHookDotNet
      • Всё, что необходимо перед началом скриптинга GTA 4
      • Создание проекта и его открытие
      • Наш первый скрипт. Необходимые условия его написания
      • 000102. Метки и прыжки
      • 00034. Что такое Blip- Основные комадны
      • 000107. Обзор класса GAME
      • 000108. Обзор класса PLAYER(Часть 1)
      • 000109. Обзор класса PLAYER(Часть 2)
      • 000110. Обзор класса PLAYER(Часть 3)
      • 000111. Vector - Что это такое и с чем его едят
      • 000116. Обзор класса World
      • 000117. Обзор класса Model
      • 000118. Обзор класса Vehicles
      • 000119. Обзор класса Ped
      • 000126. Pickup в GTA 4
      • 000127. Обзор класса Group
      • 000141. Списки в c#. Запуск нескольких скритов в GTA 4
  • Программирование
    • C#
      • 000103. Типы данных в C#. Базовые операции над ними.
      • 000104. Блочные конструкции. Условия
      • 000105. Блочные конструкции. Циклы
      • 000106. Массивы и структуры
      • 000123. Блочные конструкции. Перечисления
      • 000124. Блочные конструкции. Оператор управдения swith
      • 000125. Блочные конструкции. Цикл foreach
      • 000128. Как делать функции c#- Часть 1
      • 000129. Как делать функции c#- Часть 2
      • 000130. Альтернативные условия
      • 000131. Как делать функции c#- Часть 3
      • 000132. ООП в c# Часть 1
      • 000135. ООП в c# Часть 2 - Полиморфизм
      • 000136. Как делать функции c#- Часть 4
      • 000138. Детальнее о static
      • 000139. Блочные конструкции. Исключения
      • 000140. Делегаты и события в c#
      • 000143. Знакомство с формами
      • 000144. Панель элементов
      • 000149. Кнопки, Текст-боксы и метки
      • 000151. Запуск другой формы из основной, ListBox, MenuStrip
      • 000160. Сериализация и десериализация XML в c#
      • 000163. Консоль. Основные команды
      • 000165. Цикл foreach для своих классов
      • 000168. Перегрузка операторов в c#
      • 000169. Анонимные и динамические типы в c#
      • 000170. Анонимные функции и лямбда-выражения в c#
      • 000173. C# введение в Linq
      • 00048. Детальнее о ref, out и checked
      • 000150. Подключаем dll-библиотеку, работа с файлами
    • C++
      • Выбор среды компилирования, типы данных, первая программа
      • Математика, адреса данных
  • Полезные ссылки
    • Уроки от Vital (видео)
    • База опкодов (SBL)
    • Сайт Sanny Builder
    • Сайт CLEO
  • На удаление
    • Раздел 99. Старые уроки
      • 00010. Управление Sanny Builder и её особенности
      • 0000. Всё, что необходимо перед началом скриптинга
      • 000156. Вступление в скриптинг GTA 3
Powered by GitBook
On this page

Was this helpful?

  1. GTA SA, VC, III (PC, Classic)
  2. Раздел 02. CLEO

000176. Выделение памяти

Всем привет! В этом уроке мы ознакомимся с функцией выделения памяти и рассмотрим подробный пример работы этой фишки.

Иногда при проектировании больших скриптов возникают проблемы с хранением каких-либо значений в CLEO-скриптах:

  • Количество локальных переменных мало;

  • Глобальные переменные не рекомендовано использовать в CLEO;

  • Глобальные CLEO-переменные могут привести к конфликтам между скриптами;

Проблемы очевидны и решить их можно несколькими способами. Сегодня мы рассмотрим способ с выделением динамической памяти.

Допустим, у нас стоит задача: создать 100 актёров. Их нужно где-то хранить, и буфер является очень привлекательным вариантом. Рассмотрим опкоды, для работы с ними:

0AC8: 0@ = allocate_memory_size 120
0AC9: free_allocated_memory 0@

Первый опкод выделяет память под буфер, где 120 — это размер (в байтах), а 0@ — переменная, которая будет хранить указатель на начало области памяти (он же совпадает с началом буфера). Второй опкод освобождает выделенную память.

Возникает вопрос: как узнать размер выделяемой памяти, чтобы нам хватило места для записи этих актёров? Поскольку переменные для создания/записи актёров являются ссылками, то размер одного сегмента этой памяти будут равняться 4 байтам, а общий размер выделяемой памяти — 100 × 4 = 400 байт.

Для того, чтобы получить 1 элемент этого буфера, легче всего сделать несколько SCM-функций, которые делали бы навигацию по этой области памяти. Первый участок кода будет выделять память под актёров, а второй — очистка выделенной памяти:

goto @SKIP_FUNCTIONS

:CREATE_ARRAY
0A90: 2@ = 4 * 0@ // 4 * size
0AC8: 1@ = allocate_memory_size 2@
0AB2: ret 1 1@

:DESTROY_ARRAY
0AC9: free_allocated_memory 0@
0AB2: ret 0

:SKIP_FUNCTIONS

Я назвал SCM-функции "создать массив" и "удалить массив" согласно принципам, по которым они работают. Теперь добавим возможность читать/записывать в ячейку памяти нужное значение по индексу. Индекс будет определятся как Номер × размер, размер ссылки естественно 4 байта:

:SET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8C: write_memory 4@ size 4 value 2@ virtual_protect 0
0AB2: ret 0

:GET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8D: 2@ = read_memory 4@ size 4 virtual_protect 0
0AB2: ret 1 2@

Поскольку у нас идёт работа с памятью, мы обязательно применяем опкоды 0A8C и 0A8D для чтения и записи её участка. Адрес чтения мы получили за формулой: Начало буфера + ( размер ссылки × индекс ). Поэтому наши SCM-функции будут обязательно принимать ссылку на выделенный буфер:

0AB1: call_scm_func @CREATE_ARRAY 1 num_items 100 store_to 0@
0AB1: call_scm_func @DESTROY_ARRAY 1 array 0@
0AB1: call_scm_func @SET_ARRAY_ITEM 3 array 0@ index 0 value 0@
0AB1: call_scm_func @GET_ARRAY_ITEM 2 array 0@ index 0 value 0@

Итак, запишем в наш массив 100 случайных актёра, разместив их у Гроув Стрит:

{$CLEO}
0000:

goto @SKIP_FUNCTIONS

:CREATE_ARRAY
0A90: 2@ = 4 * 0@ // 4 * size
0AC8: 1@ = allocate_memory_size 2@
0AB2: ret 1 1@

:DESTROY_ARRAY
0AC9: free_allocated_memory 0@
0AB2: ret 0

:SET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8C: write_memory 4@ size 4 value 2@ virtual_protect 0
0AB2: ret 0

:GET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8D: 2@ = read_memory 4@ size 4 virtual_protect 0
0AB2: ret 1 2@

:SKIP_FUNCTIONS

{ !!! НАШ КОД !!! }

0AB1: call_scm_func @CREATE_ARRAY 1 num_items 100 store_to 0@
3@ = 2500.0

for 2@ = 0 to 100 step 1
 0376: 1@ = create_random_actor_at 3@ -1659.0 12.3437
 0AB1: call_scm_func @SET_ARRAY_ITEM 3 array 0@ index 2@ value 1@
 3@ -= 1.0
 wait 0
end

0A93: end_custom_thread

Результат:

Как видим, в скрипте использовалась всего 1 переменная 1@ и мы не потеряли полный доступ ко всем остальным актёрам. Давайте теперь удалим созданных актёров и посмотрим работают ли наши функции удаления и очищения памяти:

{$CLEO}
0000:

goto @SKIP_FUNCTIONS

:CREATE_ARRAY
0A90: 2@ = 4 * 0@ // 4 * size
0AC8: 1@ = allocate_memory_size 2@
0AB2: ret 1 1@

:DESTROY_ARRAY
0AC9: free_allocated_memory 0@
0AB2: ret 0

:SET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8C: write_memory 4@ size 4 value 2@ virtual_protect 0
0AB2: ret 0

:GET_ARRAY_ITEM
0A90: 3@ = 4 * 1@ // 4 * size
0A8E: 4@ = 0@ + 3@ // Buffer + offset
0A8D: 2@ = read_memory 4@ size 4 virtual_protect 0
0AB2: ret 1 2@

:SKIP_FUNCTIONS
0AB1: call_scm_func @CREATE_ARRAY 1 num_items 100 store_to 0@
3@ = 2500.0

for 2@ = 0 to 100 step 1
 0376: 1@ = create_random_actor_at 3@ -1659.0 12.3437
 0AB1: call_scm_func @SET_ARRAY_ITEM 3 array 0@ index 2@ value 1@
 3@ -= 1.0
 wait 0
end

{ !!! НАШ НОВЫЙ КОД !!! }

for 2@ = 0 to 100 step 1
 0AB1: call_scm_func @GET_ARRAY_ITEM 2 array 0@ index 2@ value 1@
 if 
 056D: actor 1@ defined
 then
 01C2: remove_references_to_actor 1@ 
 009B: destroy_actor 1@
 end
 wait 0
end 
 
0AB1: call_scm_func @DESTROY_ARRAY 1 array 0@ 

0A93: end_custom_thread

Результат:

Улица снова пуста! Интересно понаблюдать за самим процессом создания/удаления этих актёров: видно сколько примерно времени занимает одна итерация цикла.

Думаю, многие заметили, что в цикл я добавил нетипичную для него задержку в 0 милисекунд. В нашем случае без задержки игра вылетит, что конечно не радует. Надеюсь, что этот пример пригодится вашим проектам, где есть смысл хранить данные именно таким способом.

Чтобы не превышать лимиты, не создавайте слишком много сущностей за один раз!

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

В main.scm этот способ нужно использовать с осторожностью, но там ситуация с переменными более благосклонна к нам.

Кроме актёров, таким вот образом можно записать и другие сущности, а также целые и/или вещественные числа. Также нет привязки к конкретному типу данных: мы можем в разные ячейки записать разные значения. Главное не забыть что и куда было записано :)

На этом, пожалуй, всё. С Вами был wmysterio!

Previous00090. Работа с гаражамиNext00076. Статистика игрока

Last updated 2 years ago

Was this helpful?

100 актёров на Гроу
Актёров уже нет Гроу