Рейтинг - 4.3 (3)

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

Очень часто при проектировании больших скриптов возникает проблема с хранением каких-либо значений в 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!


Теги: буфер, выделение памяти
Вход на сайт

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

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

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