XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
DioD

offline
Опыт: 45,134
Активность:
Создание MUI без использования ретурн бага
Как пример я возьму то что написал для этой цели уже давно, хотя баги могут быть, так что если вдуг что-то всплывёт пишите письма.

Как вам должно быть известно на данный момент для создания стэка объектов, мы привыкли называть это SCV хотя это вовсе не так, кеш это хеш таблица по которой движок варкравта осуществяет поиск каждый раз при обращении к нему, чем больше данных сохранено тем больше времени это займёт.

Это создаёт очень серьёзную проблему невозможности высвобождать записи из кеша при потере объекта - хоста на который эти данные были записаны, таким образом все данные что были сохранены в кеш и не очищены вовремя остануться там навсегда, вызывая всё большую и большую задержку в обращении к кешу в дальнейшем.

Вторая проблема это обработка тех самых объектов типа handle что были удалены при работе вне кеша, в таком случае движок выделит хэндл другому объекту хотя в кеше остались данные записаные для совсем другого объекта, это как правило вызывает остановку ввыполнении какого либо действия, или нарушает ход действия совсем других событий, что так-же является неприятным.

Третья, незначительная проблема это строки что остаются в памяти навсегда и замедляют обработку кеша и не только его со временем.

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

Как пример такого выделения данных я могу предложить код выделения ячейки от SDARS.

Код:
//                                                                                               //
function SDARS_New takes integer Offset returns integer                                          //
    local integer OffS_I_1 = Offset                                                              //
    local integer Slot_I_1 = 0                                                                   //
    local integer Valu_I_1 = 256                                                                 //
    //                                                                                           //
    if Offset > 31 then                                                                          //
        set OffS_I_1 = 31                                                                        //
    endif                                                                                        //
    //                                                                                           //
    if Offset < 0 then                                                                           //
        set OffS_I_1 = 0                                                                         //
    endif                                                                                        //
    //                                                                                           //
    set Slot_I_1 = 256*OffS_I_1                                                                  //
    set Valu_I_1 = Slot_I_1 + 255                                                                //
    //                                                                                           //
    if udg_LH_LogicUse[OffS_I_1] == 0 and OffS_I_1 != 0 then                                     //
        set udg_LH_LogicUse[OffS_I_1] = Slot_I_1                                                 //
    else                                                                                         //
        set Slot_I_1 = udg_LH_LogicUse[OffS_I_1]                                                 //
    endif                                                                                        //
    //                                                                                           //
    loop                                                                                         //
        exitwhen udg_LH_Events[Slot_I_1] == null or Slot_I_1 > Valu_I_1                          //
        set Slot_I_1 = Slot_I_1 + 1                                                              //
    endloop                                                                                      //
    //                                                                                           //
    set udg_LH_LogicUse[OffS_I_1] = Slot_I_1 + 1                                                 //
    //                                                                                           //
    if udg_LH_LogicUse[OffS_I_1] > Valu_I_1 then                                                 //
        set udg_LH_LogicUse[OffS_I_1] = 256*OffS_I_1                                             //
    endif                                                                                        //
    //                                                                                           //
    return Slot_I_1                                                                              //
endfunction                                                                                      //
//                                                                                               //


Структура что получается при использовании этого механизма выделения это двумерный массив 32*256

первый подмассив имеет границы 0-255 второй 256-511

смещение по 256 определяется так называемым OffSet значением что сдвигает область по объёму массива, но это не мешает вам изменить размерность и получить например
64 офсета по 128 значений или 16 по 512

это зависит от того какую вы цель преследуете, если по мне то 128 объектов вполне достаточно для выполнения любой операции.

Для упрощения получения свободной ячейкивводиться логическая перменная что определяет выделение ячейки строго по порядку, от сюда и название StaticDataArrays

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

второй цикл создан искючительнодля проверки не занял ли слот чем либо, слот занимается исключительно триггером, таким образом проверить используется ли он невозможно впринципе, так как ведущее логическое число отсчитывает порядок ситуация при которой ячейка становиться занятой есть ошибка где-то в коде, так как цели для которых используется тот или иной массив различны, например для одного спелла вы можете использовать один диапозон для другого другой, найти ошибкуц не составит труда, достаточно добавить дебаг сообщение или что-тов этом роде и всё будет отлично.

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

Итак о перменных что были задействованы внутри функции.
Код:
local integer OffS_I_1 = Offset определяет оффсет
    local integer Slot_I_1 = 0 изначально определяло шаг оффсета для создания 3d массива но после я отказался отэтой идеи, такчто данная переменная не определяет ничего изначально, но будет использована в дальшейшем.
    local integer Valu_I_1 = 256 Определяет размер оффсета


заголовок как вы видите вполне простой, первоеприсвоение создано для того что-бы не путаться, впринципе оно не нужно вовсе.

Код:
set Slot_I_1 = 256*OffS_I_1          определяет нижнюю границу оффсета
    set Valu_I_1 = Slot_I_1 + 255        определяет верхнюю границу оффсета

далее идут манипуляции с основным логическим числом что отвечает за порядок выделения следующей доступной ячейки.

как вы можете видеть тут же идут проверки на допустимость этого самого числа,
если оффсет не равен нулю и логическое число равно нулю присваевается нижняя граница оффсета, это говорит о том что это первый запуск для этого оффсета и логическое число еще не инициализировано, если число уже инициализировано нижней границей выделения нового числа становиться оно

    if udg_LH_LogicUse[OffS_I_1] == 0 and OffS_I_1 != 0 then                                   
        set udg_LH_LogicUse[OffS_I_1] = Slot_I_1                                                
    else                                                                                         
        set Slot_I_1 = udg_LH_LogicUse[OffS_I_1]                                                 
    endif


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

    loop
        exitwhen udg_LH_Events[Slot_I_1] == null or Slot_I_1 > Valu_I_1
        set Slot_I_1 = Slot_I_1 + 1
    endloop

Так как для логического числа нужен первый свободный слотегоимеетсмысл сохранить сразу же не думая долго, и не трогать номер слота для выделения вовсе, если этого не делать можно будет убить массив, так-же если передвинуть ячейку вручную вне зону текущего оффсета
    set udg_LH_LogicUse[OffS_I_1] = Slot_I_1 + 1

вот и всё мы получили необходимое число в массиве остались лишь формальности, а именнопроверка на соответствие логического числа тому что нам нужно, можновынести это действие в начало, но тогда вы лишите себя возможности контролировать массив вручную, как бы это не звучало вы можете администрировать массивы в течении игры если умеете это делать, модифицировать содержимое ячеек и так далее, что при использовании кеша затруднительно так как вам надо знать два ключа.
    if udg_LH_LogicUse[OffS_I_1] > Valu_I_1 then
        set udg_LH_LogicUse[OffS_I_1] = 256*OffS_I_1
    endif
Воти все, если логическое число выпало за пределы оффсета сбрасываем его на нижнюю границу получая её из количества элементов в оффсете.
Да, количество элементов сохранено в нескольких местах, так что вам при изменении механизма придётся проверить весь код, хотя это не составит для вас особого труда особенно если вы поняли что я хотел донести до вас в этом краткой обзоре возможности создания MUI конструкций без использования ретурн бага.

Как вы должны были заинтересоваться яописал только метод выделения места под данные, кстати это место выделяется ислючительно на массив тригеров и это действие вынесено только исходя из необходимости иногда контролировать автоматическиесистемы вручную.

ну и конечно нам стоит вернуть заветное число в кодгде мы его решили использовать

    return Slot_I_1


итак часть два, получение информации измассивов....

Код:
//                                                                                               //
function SDARS_Get takes integer OffSet returns integer                                          //
    local integer Slot_I_1 = 256*OffSet                                                          //
    local trigger Trig_T_1 = GetTriggeringTrigger()                                              //
    //                                                                                           //
    loop                                                                                         //
        exitwhen udg_LH_Events[Slot_I_1] == Trig_T_1 or Slot_I_1 >= 256*OffSet+255               //
        set Slot_I_1 = Slot_I_1 + 1                                                              //
    endloop                                                                                      //
    //                                                                                           //
    set Trig_T_1 = null                                                                          //
    return Slot_I_1                                                                              //
endfunction                                                                                      //
//                                                                                               //


Вторая часть механизма оперирования массивов, получение данных из массива.
Так как ретурн баг мы неиспользуем остаётся только перебор.

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

оффсет передаётся вручную увы вы не сможете контролировать сразу весь массив целиком,но вот 256 ячеек запомнить вполне можно, особенно если вы ловите глюки.

после передачи оффсета происходит определение рамок оффсета и начинается поиск триггера из которого эта функция запущена, если объекта нету вы получите верхнюю границу массива, это моя недоработка так что вам будет чем занятьсяна досуге, попробуйте ёё исправить.

Еще в алгоритм поиска не включено логическое число что должно определять первый занятый слот, а не первый свободный как в функции выше, исходя из нескольких простых определений вы сможете исправить эту особенность поиска данных по массиву.

1) выделеный объект всегда будет занят, функций отмотки просто нет, если слот в массиве выделен он будет занят в любом случае, хотя функцию отмотки можно собрать, она будет опасна по определению таккак может отмотать не то что надо.
2) после получения объекта не обязательно что он будет удалён, но обязательно что онвсё еще существует, это вторая функция SDARS , как вам должно быть известно RS это система что прекомпилировала данные перед обработкой, тут так-же, вскоре а вернее если будет времяяпокажу как это работает, хотя это будет просто кошмарно смотреться
3) нци последнее правило, удалёный объект больше несуществует его ячейку нельзя использовать но можно занять вновь.

кстати о очищении массивов, тут тоже есть функция...
Код:
//                                                                                               //
function SDARS_Drop takes integer Slot_I_1 returns nothing                                       //
    //                                                                                           //
    if udg_LH_Events  [Slot_I_1] != null then                                                    //
        call TriggerRemoveAction(udg_LH_Events[Slot_I_1],udg_LH_Actions[Slot_I_1])               //
        call DestroyTrigger(udg_LH_Events[Slot_I_1])                                             //
        set udg_LH_Events  [Slot_I_1] = null                                                     //
        set udg_LH_Actions [Slot_I_1] = null                                                     //
    endif                                                                                        //
    //                                                                                           //
    if udg_LH_Effects [Slot_I_1] != null then                                                    //
        call DestroyEffect(udg_LH_Effects[Slot_I_1])                                             //
        set udg_LH_Effects [Slot_I_1] = null                                                     //
    endif                                                                                        //
    //                                                                                           //
    set udg_LH_Trees   [Slot_I_1] = null                                                         //
    set udg_LH_Logic   [Slot_I_1] = false                                                        //
    set udg_LH_Units   [Slot_I_1] = null                                                         //
endfunction                                                                                      //
//                                                                                               //
//                                                                                               //
function SDARS_Start takes integer Slot , real Time , code Func returns nothing                  //
    set udg_LH_Events[Slot] = CreateTrigger()                                                    //
    set udg_LH_Actions[Slot]= TriggerAddAction(udg_LH_Events [Slot],Func)                        //
    call TriggerRegisterTimerEvent(udg_LH_Events [Slot],Time,true)                               //
endfunction                                                                                      //
//                                                                                               //


Функция очищения никогда не осуществляется автоматически и не перематывает какие либо числа, так как ошибочный вызов её 2-3 раза подряд мог убить весь массив.

Ну и основная функция это убийство указаной ячейки во всех доступных массивах, если вы будете использовать 3d массив 2*32*128, то надо будет убивать сразу по две ячейки, хотя это неважно.

последняя функция просто регестрирует триггер как таймер, сохраняя его действие для защиты от утечки.

ну а теперь краткая инструкция по 3д массиву.
Пишу как пример, работать это не будет, просто посмотрите алгоритм
Код:
function SDARS_Alloc takes integer X, integer Y, integer Z returns integer
local integer AllocByZ = Z
local integer AllocByX = X
local integer AllocByY = Y
local integer UP       = 0
local integer DAWN     = 0
local integer FINAL    = 0

if Z > 1 then
set Z = 1
elseif Z < 0 then
set Z = 0
endif

if X > 31 then
set X = 31
elseif X < 0 then
set X = 0
endif

if Y > 127 then
set Y = 127
elseif Y < 0 then
set Y = 0
endif

set DAWN  = 128*X
set UP    = 128*X + 127 
set FINAL = GetRandomInt(DAWN,UP)+((8192/2)*Z)

return FINAL

endfunction


Как вы можете видеть нет ничего сложно в выделении 2х 3х и даже 4х мерных массивов, можно сделать неограниченое число измерений и использовать их.

В этом отношении кеш сильно проигрывает так как использование математических законов на строках тупо.
Старый 11.11.2006, 12:38
NETRAT

offline
Опыт: 83,712
Активность:
Там не намного больше времени уходит. Поиск бинарный, поэтому количество итераций при поиске равно log(2,COUNT), а это не так существенно
Да и потом, кеш (в нормальных картах) каждый раз на загрузки флешится, либо весь, либо выборочно
Цитата:
Вторая проблема это обработка тех самых объектов типа handle что были удалены при работе вне кеша
О чем это ты?

Насколько я понял, это реализация принципа кеша на массивах, оптимизированная в некоторых местах

Вспоминается как Алексей предлагал для увеличения скорости работы с массивами выбирать несколько случайных элементов перед вставкой =)
Старый 11.11.2006, 14:37
DioD

offline
Опыт: 45,134
Активность:
не поняли фишки немножко
  1. это не использует ретурн баг, то есть все объекты храняться так как они были представлены движком, то есть встроеный мэнеджер памяти никогда не теряет объект из своей области видимости, которая ограничивается кешем, так как там хранятся уже не прямые ссылки.
  2. вторая проблема связана с невозможностью оперирования объектами из кеша как объектами впринципе, вся система построена на алгоритмах по которым мыслю я сам, тоесть мне легко анализировать информацию в массивах, так как RS компонент что не был включен так как не доделан именно этим и занимается.
Массив интегеров что хранит в себе номера свободных ячеек в первых 4000 слотов и занятых во второй 4000 слотов, таким образом ячейки массива становятся группой различных объектов и не пересекают друг друга.
про рандом число, так вот оно реализовано на RS компоненте, и выбор будет происходить из гарантировано свободных ячеек, тоесть рандом никогда невыпадет на занятую ячейку.
Основная сложностьв том что я по такому алгоритму мыслить не могу, и немогу представить себе структуру полностью, что тормозит развитие этой системы.
  1. нет ретурн бага
  2. нету глюков
  3. нету строк
Старый 11.11.2006, 14:51
NETRAT

offline
Опыт: 83,712
Активность:
теперь мне понятно, надо более внимательно вчитаться в код
я уже не раз обьяснял почему в общем случае рандом в таких системах - полный бред =)
Старый 11.11.2006, 14:59
DioD

offline
Опыт: 45,134
Активность:
рандом конечно бред ноесли очень хочется пожалуста, лучше делать через таблицу
массивы
  1. хранит информацию
  2. хранит контрольные значения, разный хлам нолики и еденички и другую служебную информацию
  3. хринит в последовательной группе номера всех занятых ячеек для поиска и всех свободных, тоже для поиска но уже не объектов а свободных ячеек.
ну можно взять пример например такой работы
|00000000000000000000000000000000000000000000000000|
сектор что содержит свободные ячейки
|11111111100000000000000000000000000000000000000000|
позанимали ячеек например, так вот сектор сдвинется наколичество занятых ячеек а номера занятых будут добавлены во второй сектор
|00000000000000000000000000000000000000000|
свободные
|1111111111|
занятые
как мы видиму нас есть занятые ячейкииесть свободные
так вот объекты мы будем искать в одном местеа ячейки в другом
таким образом количество поисков будет резко сокращено
единственная проблема это высвобождение ячеек после того как они были заняты, если делать это автоматом получаетсянемножко бред, если в ручную,то ошибка пользователя убъёт массив
итак впримере у нас освободилась ячейка 6 из массива 3-12 размеры массивов храняться в служебном массиве, так что можноанализировать использование
000|1111101111|000
вот у нас такой вот сектор, и мы это знаем, для освобождения ячейки нам надо
  1. передвинуть последний слот на место освободившегося
таким образом мы уменьшим размер массива на еденичку
и добавить этот номерв массив свободных ячеек
так какситуация 3-12 недостижима при автоконтроле она приобразуется в
1-10 а после в 1-9
таким образом мы дефрагментировали объём данныхи нам не нужно использовать рандом поиск вовсе, так как у нас все значения строго зафиксированы в некой группе, отсюда и название.
Старый 11.11.2006, 15:38
Iron
Листовой
offline
Опыт: 24,427
Активность:
DioD, а чем тебе не нравится обычная система пробегания циклом по массиву с выискиванием свободной ячейки? При максимальном размере массива в 8192 это не такая уж и долгая операция. + мы получаем гибкую систему в которой у нас нет ограничения на 4000 обьектов, а могут быть задействованы все 8192.

Или я чего-то недопонимаю? Тогда plz обьясни.
Старый 14.11.2006, 22:43
DioD

offline
Опыт: 45,134
Активность:
SDARSv2 снимает все ограничения по перебору ибо он больше не нужен вовсе, забудьте это слово. перебор нужен только для получения неименованых объектов из массива, да и то перебор в этом случае будет минимален.

SDARSv3 предпологает 64*64*2 тоесть 3 измерения, еще можно
16*16*16*16

но это маловажно так как представить себе 4 измерения человек не может и пользоваться этой модификацией так-же не сможет.

2 измерения это оффсет и модуль
3 измерения это оффсет модуль и "клон раздел"
4 измерения это оффсет, модуль клон раздел в каждом оффсете и общий клон раздел

тоесть занимая скажем оффсет 1 модуль 1 мы получаем доступ еще к двум местам для сложения данных

минус этой системы статичность, как работают динамические массивы можно увидеть в теме с тест версиями, первая работа внутри вторая работа извне.

http://xgm.guru/forum/showthread.php?t=7705

могу конечно описывать долго но это проще понять самому, особенно если учесть что в этой теме есть инфа по алгоритму
Старый 15.11.2006, 06:53
remal
нечто
offline
Опыт: 2,087
Активность:
используйте кучу и будет вас счатье. перебор сосёт.
Старый 20.11.2006, 02:49
DioD

offline
Опыт: 45,134
Активность:
вот ты мне объясни как в кеше вар ищёт данные? не перебор хочешь сказать?
Старый 20.11.2006, 12:35
remal
нечто
offline
Опыт: 2,087
Активность:
Цитата:
Сообщение от DioD
вот ты мне объясни как в кеше вар ищёт данные? не перебор хочешь сказать?

нет, конечно! я уже задолбался писать людям типа тебя и тоадкопа, чтобы почитали книжки по алгоритмам.
Старый 20.11.2006, 23:22
NETRAT

offline
Опыт: 83,712
Активность:
нет, не перебор. оптимальный метод для таких вещей - хеш функция, но это слишком сложно (функцию сложно хорошую задать, а универсальную вообще невозможно), поэтому используется хеш-таблица. У хеш-таблицы есть индексное поле, индексируется оно почти наверняка бинарным деревом (см. std.map). То есть если перебор хеш таблицы - N итераций, то бинарный поиск - это log(2,N). Насколько мне известно, лучше алгоритма пока не придумано

NETRAT добавил:
То есть при условии грамотной реализации, любые извращения на эту тему остаются всего лишь извращениями. Правда, насколько мне удалось познакомиться с методами близзов, я не исключаю что написана эта система была не так как нам хотелось бы(и не так как нам было бы удобнее и быстрее)
Старый 21.11.2006, 05:11
Toadcop

offline
Опыт: 54,313
Активность:
DioD в конечном случаи важна производительность и если она быстрей кеша то можно это юзать иначе не имеет никакого смысла... и поверь сравнительно кеш не такой уж и медленый.

Цитата:
я уже задолбался писать людям типа тебя и тоадкопа, чтобы почитали книжки по алгоритмам.
- в таком случаи ничего нового не придумают если все будут оринтироватьса уже по созданым алгоритмам...

Toadcop добавил:
а чё карты примера нету ?
Старый 21.11.2006, 15:46
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 11:56.