Van Damm
wait... what?
offline
Опыт:
22,268Активность: |
ExecuteFunc
1. Что такое ExecuteFunc?ExecuteFunc – это просто native-функция, но она - одна из самых полезных.
Она берёт аргументом имя функции и запускает её в другом потоке. Это значит что запущенная функция может использовать ожидания без прерывания потока вызова, и, так как она запомнит ответы на события, это позволяет вам использовать ожидания при вызовах ForGroup и TimerStart, к примеру. Более того, это – единственный способ получить форвардные ссылки в JASS.
2. Какие функции я могу использовать с ней?Вы можете использовать ExecuteFunc с любыми функциями без аргументов (takes nothing), функция может быть постоянной и даже может возвращать значение, но вы не сможете его прочитать.
Как сказано выше, native-функция ExecuteFunc позволяет форвардные ссылки, поэтому код вызываемой функции может находиться ниже её вызова через ExecuteFunc. 3. Как в точности мне её вызывать?Вызвать ExecuteFunc очень легко, если вы знаете JASS. Вы просто вызываете её с именем нужной функции в качестве строкового аргумента. Аргумент – имя функции чувствителен к регистру и должен быть правильно написан, в другом случае это приведёт к крушению. Вы можете использовать такие вещи, как конкатенация (сляиние строк), главное – быть уверенным, что строка верная. Вызов ExecuteFunc не приведёт к крушению, если в качестве аргумента использовать null или “” (пустая строка).
Вы можете передать ей имя функции, содержащее вызов в качестве аргумента, но будьте уверены, что вы используете ожидания, или что-то для предотврашения создания бесконечного цикла без пауз, что может привести к крушению.
4. Хочу примеров!Базовый пример вызова:
Когда выполняется функция Hello, покажется текст:
Причина, по которой "хай" отображается раньше, чем "превед" – то, что вызов ExecuteFunc в функции Hello расположен над вызовом функции BJDebugMsg. Это также пример форвардных ссылок с использованием ExecuteFunc.
Функцию Hi можно было без проблем заменить этой функцией:
Ранее я говорил об ожидании при использовании ForGroup. Пример:
Обычно вызов TriggerSleepAction остановит выполнение ForGroup, но не здесь, так как ожидания находятся в функции Enum2, которая запускается в параллельном потоке через ExecuteFunc.
Это также показывает, что ответы на события, типа GetEnumUnit отлично работают с ExecuteFunc. 5. Есть ли проблемы, связанные с использованием ExecuteFunc?Да. Она вызовет крушение карты в игре, если аргумент – имя функции не является действительным именем функции, но это не случится, если пользователь знает, что делает.
Другая проблема случается, когда вы используете функцию обфускации кода программ для защиты карты типа Heavy Locker или Extprotect, которая даёт функциям случайные имена. Так как они не изменяют содержимое строк, имеющих такое же имя, как и функция, это приведёт к крушениям при вызове ExecuteFunc.
В этом случае решением может быть Vexorian’s Map Optimizer, если вы используете строки напрямую (без слияния или вещей такого же типа). Другим решением будет избегать использования этих программ, или хотя бы избегать использования их методов обфускации.
Это перевод статьи Blade.dk с сайта WC3Jass.com
Перевод был сделан мной ещё три года назад, пока сейчас не попросили выложить его как статью ^^
Также имеется альтернативный перевод от товарища NCrashed.
» Читать
Примечание переводчикаДанная статья является свободным переводом оригинала (автор Blade.dk) . Материал этой статьи очень полезен для новичков в jass'е. Главная мысль статьи: вы сможете организовывать задержку в пике юнитов ForGroup (да и в любых call-back функциях) и в действиях таймеров.
Содержание
Что делает ExecuteFunc?Это простая нативка, которая зашита в движок игры, но она является одной из самых полезных. Она берет строку, имя функции, в качестве аргумента и запускает ее в другом потоке. Замечательное свойство ExecuteFunc в том, что она запоминает все локальные переменные от событий(GetEnumUnit(),GetTriggerUnit() и тп).
Это означает, что вызываемая таким образом функция может использовать задержку (TriggerSleepAction или PolledWait) без прерывания текущего потока. Таким образом можно устроить задержку в ForGroup и действиях таймеров. И это единственный способ в jass вызвать функцию до ее объявления. Какие функции можно использовать с ней?Лучше использовать функции, которые ничего не возвращают и ничего не берут, конечно, можно вызвать функцию, которая берет аргумент, но вы не сможете забрать результат выполнения функции (return something), единственный способ забрать это значение – передать его через глобальную переменную.
Как сказано выше, с помощью ExecuteFunc можно вызвать функцию еще до ее объявления в коде. Еще немаловажный момент: использовать можно только постоянные функции, то есть у вас не получиться вызвать таким образом функцию, сохраненную в переменную типа code, прописав как аргумент имя этой переменной. Как ее правильно вызвать?Если вы знаете, как вызывать функции в jass, то это не составит проблем. Просто берем имя нужной функции в кавычках и вставляем внутрь ExecuteFunc.
Имя функции чувствительно к регистру! Если вместо DoNothing написать donothing, то игра вылетит с фаталом. Игра не вылетит, если вместо аргумента поставить пустую строку "".
Также можно использовать операцию сложения строк:
Также можно организовать рекурсию, вызывая в функции ее же через ExecuteFunc. Только надо следить, чтобы был выход из этого бесконечного цикла самовызова. (прим. переводчика: А оно вам надо? Рекурсия в jass организуется и обычным самовызовом, и, вообще, рекурсию надо избегать из-за ее неэффективности)
Примеры использованияСамое простое:
В результате вызова функции Hello на экран будет выведено:
Это отличный пример вызова функции до ее описания.
Без проблем можно функцию Hi заменить на:
""constant function Hi takes nothing returns string return "Это глупо, но работает." endfunction
function Enum2 takes nothing returns nothing
local unit e = GetEnumUnit() Сохранение взятого юнита в локальную переменную call TriggerSleepAction(5) Ждем 5 секунд call KillUnit(e) Убиваем юнита set e = null Обнуляем переменную, чтобы не возникло утечки endfunction function Enum takes nothing returns nothing
call ExecuteFunc("Enum2") Вызываем Enum2, чтобы могли использовать задержку endfunction ...
call ForGroup(someGroup, function Enum) Через 5 секунд все юниты из группы умрут ... ""
Без нашей хитрой уловки TriggerSleepAction вызвало бы прерывание выполнения функции. Но задержка у нас в Enum2, которая запускается через ExecuteFunc в другом потоке.
Проблемы и способы их решенияЕсли неправильно использовать ExecuteFunc, то вызвать фатал легче простого, но это не произойдет, если вы будете осознавать что делаете.
Другая проблема связана с протектом карт с помощью, например, Heavylocker's или Extprotect's с включенной функцией “запутывания кода” или просто шифрованием имен функций. В итоге имена функций меняются, а строка аргумента ExecuteFunc нет. Это приводит к фаталам. Решений проблемы несколько:
Отредактировано Van Damm, 08.11.2009 в 23:27. |
01.11.2009, 00:10 | #1
+1/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Hellfim
Новичок
offline
Опыт:
79,700Активность: |
На самом деле смешно звучит =) Почерпнул обход слипов в энуме, я нуб, раньше этого не знал -.- |
01.11.2009, 01:09 | #2
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NCrashed
offline
Опыт:
13,553Активность: |
Статья очень полезна на практике, но перевод немножко дубоватый, некоторые чисто английские формулировки можно было переделать на наш могучий. Например: "Другая проблема случается" на "Другая проблема связана с" |
01.11.2009, 01:11 | #3
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
DragonSpirit
у - уходи
offline
Опыт:
22,625Активность: |
Статья хорошая,но местами грубо переведено =\ |
01.11.2009, 01:17 | #4
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NCrashed
offline
Опыт:
13,553Активность: |
Примечание переводчикаДанная статья является свободным переводом оригинала (автор Blade.dk) . Материал этой статьи очень полезен для новичков в jass'е. Главная мысль статьи: вы сможете организовывать задержку в пике юнитов ForGroup (да и в любых call-back функциях) и в действиях таймеров. Содержание
Что делает ExecuteFunc?Это простая нативка, которая зашита в движок игры, но она является одной из самых полезных. Она берет строку, имя функции, в качестве аргумента и запускает ее в другом потоке. Замечательное свойство ExecuteFunc в том, что она запоминает все локальные переменные от событий(GetEnumUnit(),GetTriggerUnit() и тп). Это означает, что вызываемая таким образом функция может использовать задержку (TriggerSleepAction или PolledWait) без прерывания текущего потока. Таким образом можно устроить задержку в ForGroup и действиях таймеров. И это единственный способ в jass вызвать функцию до ее объявления. Какие функции можно использовать с ней?Лучше использовать функции, которые ничего не возвращают и ничего не берут, конечно, можно вызвать функцию, которая берет аргумент, но вы не сможете забрать результат выполнения функции (return something), единственный способ забрать это значение – передать его через глобальную переменную. Как сказано выше, с помощью ExecuteFunc можно вызвать функцию еще до ее объявления в коде. Еще немаловажный момент: использовать можно только постоянные функции, то есть у вас не получиться вызвать таким образом функцию, сохраненную в переменную типа code, прописав как аргумент имя этой переменной. Как ее правильно вызвать?Если вы знаете, как вызывать функции в jass, то это не составит проблем. Просто берем имя нужной функции в кавычках и вставляем внутрь ExecuteFunc. Код:
Имя функции чувствительно к регистру! Если вместо DoNothing написать donothing, то игра вылетит с фаталом. Игра не вылетит, если вместо аргумента поставить пустую строку "". Также можно использовать операцию сложения строк: Код:
Также можно организовать рекурсию, вызывая в функции ее же через ExecuteFunc. Только надо следить, чтобы был выход из этого бесконечного цикла самовызова. (прим. переводчика: А оно вам надо? Рекурсия в jass организуется и обычным самовызовом, и, вообще, рекурсию надо избегать из-за ее неэффективности) Примеры использованияСамое простое: Код:
В результате вызова функции Hello на экран будет выведено: Hi Hello Это отличный пример вызова функции до ее описания. Без проблем можно функцию Hi заменить на: Код:
Функция ничего не выведет, и забрать строку вы не сможете. Пример организации задержки в пике: Код:
Без нашей хитрой уловки TriggerSleepAction вызвало бы прерывание выполнения функции. Но задержка у нас в Enum2, которая запускается через ExecuteFunc в другом потоке. Проблемы и способы их решенияЕсли неправильно использовать ExecuteFunc, то вызвать фатал легче простого, но это не произойдет, если вы будете осознавать что делаете. Другая проблема связана с протектом карт с помощью, например, Heavylocker's или Extprotect's с включенной функцией “запутывания кода” или просто шифрованием имен функций. В итоге имена функций меняются, а строка аргумента ExecuteFunc нет. Это приводит к фаталам. Решений проблемы несколько:
Надеюсь, статья помогла кому-нибудь. - Blade.dk Отредактировано NCrashed, 01.11.2009 в 02:16. |
01.11.2009, 02:09 | #5
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Rewenger
The culprit will not die
offline
Опыт:
35,873Активность: |
Вах ты, теперь я могу юзать слип в енуме. Огромное спасибо за статью. NCrashed, а зачем 2-я статья, да ещё и с большим количеством букв?.. |
01.11.2009, 06:24 | #6
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
_Red
offline
Опыт:
4,095Активность: |
норм стастья, спасибо! Rewenger, вторая статья - это типо он перевел лутче |
01.11.2009, 07:32 | #7
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NCrashed
offline
Опыт:
13,553Активность: |
Информации больше и перевод сделал хорошо. Не пропадать теперь статье, тем более все не знали по сабжу. Самое интересное, что в вызванной функции работают GetEnumUnit(), GetTriggeringTrigger() и остальные
|
01.11.2009, 09:58 | #8
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
FunkieFoO
offline
Опыт:
7,159Активность: |
Зачот аффтар +1, норм статья, не знал что ф-ию можно вызвать до ее обьявления... ЗЫ а если я буду вызывать ф-ию таким образом из др. ф-ии. то та ф-ия из которой я ее вызывал примет параметры вызываемой ф-ии? я так все пнял? |
01.11.2009, 10:52 | #9
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NCrashed
offline
Опыт:
13,553Активность: |
Она примет значения всех локальных переменных от событий GetEnumUnit, GetTriggeringSomething и тп |
01.11.2009, 11:47 | #10
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Toadcop
offline
Опыт:
54,313Активность: |
Цитата:
о рили ? О_О + самое важное Слипы древние зло... и их не стоит использовать ибо получить десинк легче простого в более сложных картах. что я бы заметил. 1) очень удобно и универсально 2) почти всегда стоит делать проверку на null (строки) если действие не статичное 3) медлено. в моих (неоднократных) тестах это было ~ 27x (неких едениц времени но важно соотношение) чтение с переменой ~0.6х чтение из кеша если значения статик (не перменые) ~4.5x call SetUnitPosition ~250x вызов триггера через TriggerEvaluate ~12.5x т.е. TriggerEvaluate самый быстрый способ запустить "произвольную функцыю" но он вроде не создаёт поток. хотя на практике с этим у меня некогда проблем небыло. но всё же для не чястых запусков произвольной функции ExecuteFunc круче, точней удобней и универсальней. где важна производительность надо юзать как выше писал TriggerEvaluate |
|
01.11.2009, 13:34 | #11
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NCrashed
offline
Опыт:
13,553Активность: |
Еще он может быть полезен для разбиения циклов на несколько частей, чтобы вар не убивал поток. |
01.11.2009, 13:40 | #12
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Van Damm
wait... what?
offline
Опыт:
22,268Активность: |
мне было лень сейчас перечитывать и править =) |
01.11.2009, 15:09 | #13
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
adic3x
offline
Опыт:
108,439Активность: |
создает, но минус в том, что триггер надо инитить или переписать код под несколько ифов и обычный калл/инлайн - будет быстрее |
02.11.2009, 14:16 | #14
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Toadcop
offline
Опыт:
54,313Активность: |
Цитата:
это если известны функцыи которые могут быть запущены... |
|
02.11.2009, 14:30 | #15
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
adic3x
offline
Опыт:
108,439Активность: |
в триггер евалуате они тоже дб известны (и добавленны как условия к соотв. триггерам) |
02.11.2009, 14:35 | #16
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
alexkill
offline
Опыт:
19,072Активность: |
в целом статья хорошая, собрано воедино то, что часто обсуждалось на форуме,
кстати, об ожидании при использовании ForGroup() я еще год назад писал: |
02.11.2009, 16:23 | #17
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Van Damm
wait... what?
offline
Опыт:
22,268Активность: |
alexkill, посмотри на дату моего оригинального поста =)
|
05.11.2009, 00:57 | #18
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
XOR
offline
Опыт:
38,159Активность: |
Статья тру, имхо нужно версию NCrashed a залить под кат в первый пост |
05.11.2009, 15:25 | #19
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Van Damm
wait... what?
offline
Опыт:
22,268Активность: |
|
08.11.2009, 23:27 | #20
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|