Версия: 0.5/3.19.8.1
Автор: simast
Ссылка:
Этот аддон добавляет поддержку Javascript для аддонов и миссий. Язык Javascript поддерживается очень (очень) быстрым движком Google's V8. V8 использует ECMAScript, как указано в ECMA-262, 5-й редакции.
Это превью релиз.
Я предлагаю вам проверить его, выполнить несколько тестов на производительность и просто сообщать о любых обнаруженных проблемах. Не все запланированные функции еще реализованы (см. TODO раздел). Я не подписал аддон ключами для сетевой игры, однако, это только предварительный релиз, предназначенный для тестирования со стороны клиента.
Этот аддон с открытым исходным кодом под лицензией GPL 3.
Обратите внимание на следующие ограничения:
Вы не можете использовать и вызывать SQF команды из контекста Javascript. Это ограничение интерфейса/API callExtension.
Выделенные Linux сервера на данный момент не поддерживаются (ссылаясь на Wiki, callExtension не поддерживает библиотеки Linux (.so). Я с удовольствием сделаю нативный порт на Linux, если BIS'ы добавят необходимую поддержку в callExtension).
Возвращаемое значение JS_fnc_exec именнт жестко лимитированный буфер (максимум 10Кб) - ограничение интерфейса callExtension. У вас могут возникнуть проблемы с получением длинных строк или массивов из Javascript. Технически, я думаю что знаю как обойти это ограничение и сделать его прозрачным, так что это ограничение временное и будет снято в ближайших обновлениях. На данный момент, если вы достигните лимита размер буфера - SQF выдаст "[OOB]" исключение, так что вы сможете обработать его SQF кодом.
Так как вы не можете напрямую вызывать SQF команды из Javascript - основная идея этого аддона - это использовать разгрузочные комплексные алгоритмы и вычисления Javascript, которые требуют быстрых выполнений и не зависят напрямую от ARMA/SQF. Также вы получите следующие нативные возможности Javascript:
- Прототип объектно-ориентированного программирования
- Регулярные выражения
- Поддержка JSON
- Быстрые математические, строковые операции и операции с массивами
- Поддержку дат
TODO
Создать обход ограничению размера буфера при получении значений
Встроить JS_fnc_terminate и JS_fnc_done
Добавить из Javascript функции sleep() и uiSleep() (для использования с JS_fnc_spawn).
Добавить глобальные свойства/действия как псевдоним для глобальных объектов Javascript.
Добавить функцию log() для использования ARMA RPT файла напрямую из JS.
Определять когда ARMA в режиме паузы (останавливать фоновые скрипты и использовать v8::V8::IdleNotification()).
Рассмотреть возможность предоставления отдельных макросов/предварительной обработки на основе API
Снизить зависимость моста SQF => JS
Рассмотреть возможность добавления двух дополнительных фунций: JS_fnc_compile и JS_fnc_run для работы напрямую с V8 и позволить пропускать повторяющиеся компиляции.
Проверить все два раза и сделать финальный проверку любых проблем, связанных с безопасностью.
SQF Функции (API)
С этим аддоном доступны следующие функции:
JS_fnc_exec - Выполняет JS и возвращает результат.
JS_fnc_spawn - Выполняет код JS параллельно (не блокирующий режим, отдельный поток)
JS_fnc_terminate - Прервать (отменить) вызванный JS скрипт (пока не готово).
JS_fnc_done - Проверить выполнен ли вызванный JS скрипт (пока не готово).
JS_fnc_version - Получить версии аддона / JS.
Пожалуйста обратите внимание на примеры ниже. Детализированная документация по функциям все еще в процессе написания.
Версии "exec" и "spawn" отличаются. "exec" версия выполняет Javascript код и возвращает результат в SQF в блокирующем режиме, когда "spawn" возвращает немедленно и запустит Javascript код параллельно, в отдельном потоке. Прерывание параллельного скрипта пока не встроено.
[spoiler2=FAQ, примеры (англ яз)]
How are Javascript errors handled?
If your Javascript code has compile errors and you do not handle runtime errors yourself using Javascript exception mechanism – the Javascript engine will throw an unhandled exception. Once the unhandled exception is catched by this addon – it will be forwarded to SQF using SQF exception handling mechanism. Thus, you can catch Javascript errors in SQF with:
try { "JS code with some errors" call JS_fnc_exec; } catch { hint _exception; // [line 1] SyntaxError: Unexpected identifier: "JS code with some errors" };Note that if you do not use SQF exception mechanism to catch Javascript errors – the ARMA engine will show a very obscure black script error box in the middle of the screen every time a Javascript error is detected.
Can I execute a Javascript file instead of a code string?
Yes, using the SQF loadFile command:
// Load and execute "script.js" file loadFile "script.js" call JS_fnc_exec;What data type is returned from JS_fnc_exec call?
The results returned from JS_fnc_exec call are transparently serialized to SQF data types using the following scheme:
Javascript Number => SQF "SCALAR" type
Javascript Boolean => SQF "BOOLEAN" type
Javascript Array => SQF "ARRAY" type (including nesting)
Javascript null or undefined => SQF "VOID" type (nil)
Javascript String => SQF "STRING" type
Javascript Object with .toString() implementation => SQF "STRING" type
Anything else => SQF "VOID" type (nil)
Can this work with Arma 2?
Yes, with Arma 2: OA 1.61+ patch.
What about Unicode (UTF- strings?
Both SQF and Javascript are UTF-8 native. You can throw at Javascript UTF-8 strings (and run string operations there) and get back valid UTF-8 results to SQF.
Although be aware that SQF escapes quotes in strings using double quotes ("") while Javascript does that with escape character (\").
Examples
To improve the readability I will define and use a very simple pre-processor macro for JS_fnc_exec (NOTE: This is not part of addon/API, you may want to define some similar macro for your addons and missions):
#define JS(CODE) (##CODE## call JS_fnc_exec)Thus, some examples:
Simple Javascript statements and math:
_result = JS("2 + (2 / 2)"); // _result == 3 // typeName _result == "SCALAR"SQF and Javascript can then be mixed together:
if (JS("false") || {JS("4 > 2")}) then { // true, SQF lazy evaluation works just fine };Assign and access global Javascript variables:
JS("test = 123"); _test = JS("test"); // _test == 123[CODE] Call a built-in Javascript function: [CODE]_randomNumber = JS("Math.random()"); _year = JS("(new Date()).getFullYear()"); // "2013"[/CODE] Call your custom function with arguments: [CODE]_result = JS(format ["myFunction(%1)", _number]); _result = JS(format ["myFunction('%1')", _string]);[/CODE] Regular exp[b][/b]ressions: [CODE]_email = "my@email.com"; _emailValid = JS(format["/\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}/.test('%1')", _email]); // _emailValid == true[/CODE] [/spoiler2] [b]Производительность:[/b] Я буду воздерживаться от осуществления какого-либо серьезного тестирования производительности и сравнения до релиза 1.0. Но если вы заинтересованы в некоторых предварительных испытаниях, я хочу подчеркнуть тот факт, что SQF скрипты обрезаны (привязаны к фреймам), а Javascript не имеет этого ограничения. Это отчетливо видно в следующем примере объединения строк: [CODE] _string = "one two three four five"; // SQF version: _result = [_string, " "] call BIS_fnc_splitString; // Javascript version: _result = format ['"%1".split(" ")', _string] call JS_fnc_exec;Javascript версия работает в 15 раз быстрее (на моей машине) по сравнению с SQF функцией (даже с дополнительным использованием команды форматирования и интерфейсом callExtension).