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

Очень часто при проектировании больших скриптов возникает проблема с хранением каких-либо значений в Cleo-скриптах. Количество локальных переменных мало, глобальные переменные не рекомендовано использовать в Cleo, глобальные Cleo-переменные могут привести к конфликтам скриптов. Проблема очевидна и решить её можно несколькими способами. Сегодня мы рассмотрим способ с выделением динамической памяти.

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

Код
0AC8: 0@ = allocate_memory_size 120
0AC9: free_allocated_memory 0@

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

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

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

Код
goto @CREATE_ARRAY_END
:CREATE_ARRAY
0A90: 2@ = 4 * 0@ // 4 * size
0AC8: 1@ = allocate_memory_size 2@
0AB2: ret 1 1@
:CREATE_ARRAY_END

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

Я назвал SCM-функцию как "создать массив" и "удалить массив", поскольку этот код работает за походим принципом. Теперь добавим возможность читать/записывать в ячейку памяти ссылку на актёра по индексу. Индекс будет определятся как НОМЕР * РАЗМЕР, размер педа естественно 4 байта:

Код
goto @SET_PED_TO_ARRAY_END
:SET_PED_TO_ARRAY
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
:SET_PED_TO_ARRAY_END


goto @GET_PED_TO_ARRAY_END
:GET_PED_TO_ARRAY
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@
:GET_PED_TO_ARRAY_END

Поскольку у нас идёт работа с памятью, мы обязательно применяем опкоды 0A8C и 0A8D для чтения и записи её участка. Адрес чтения мы получили за формулой: НАЧАЛО БУФЕРА + ( РАЗМЕР ПЕДА * ИНДЕКС ). По-этому наши SCM-функции будут обязательно принимать ссылку на выделенный буфер:

Код
0AB1: call_scm_func @CREATE_ARRAY 1 size 100 handle_to 0@
0AB1: call_scm_func @DESTROY_ARRAY 1 0@
0AB1: call_scm_func @SET_PED_TO_ARRAY 3 array 0@ index 0 set_actor 0@
0AB1: call_scm_func @GET_PED_TO_ARRAY 2 array 0@ index 0 get_actor 0@

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

Код
{$CLEO}
0000:

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

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

goto @SET_PED_TO_ARRAY_END
:SET_PED_TO_ARRAY
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
:SET_PED_TO_ARRAY_END

goto @GET_PED_TO_ARRAY_END
:GET_PED_TO_ARRAY
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@
:GET_PED_TO_ARRAY_END

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

0AB1: call_scm_func @CREATE_ARRAY 1 size 100 handle_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_PED_TO_ARRAY 3 array 0@ index 2@ set_actor 1@
  3@ -= 1.0
  wait 0
end
   
0A93: end_custom_thread

Результат:

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

Код
{$CLEO}
0000:

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

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

goto @SET_PED_TO_ARRAY_END
:SET_PED_TO_ARRAY
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
:SET_PED_TO_ARRAY_END

goto @GET_PED_TO_ARRAY_END
:GET_PED_TO_ARRAY
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@
:GET_PED_TO_ARRAY_END

0AB1: call_scm_func @CREATE_ARRAY 1 size 100 handle_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_PED_TO_ARRAY 3 array 0@ index 2@ set_actor 1@
  3@ -= 1.0
  wait 0
end
   
{ !!! НАШ НОВЫЙ КОД !!! }

for 2@ = 0 to 100 step 1
  0AB1: call_scm_func @GET_PED_TO_ARRAY 2 array 0@ index 2@ get_actor 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 0@  
0A93: end_custom_thread

Результат:

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

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

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

Вход на сайт

Поиск
Категории раздела
Мини-чат
Пожалуйста, все вопросы по скриптингу задавать на форуме!
Наш опрос
Что скажете о GTA V?
Всего ответов: 51
Активность на сайте
Пожертвования
Кошельки WebMoney:
U859420971000
R407741810602
Z331072372430
E314272616890
Друзья сайта
Полезные ресурсы
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Сегодня нас посетили:
wmysterio
Реклама