ScriptVM - реализация встраиваемого скрипт-языка
Часто требуется возможность изменения логики без пересборки основного проекта - для этого логика должна быть представлена в виде внешнего контента, который подгружается из локальных файлов или по сети. Так часто хранят графы диалогов, развития событий визуальных новелл, каких-то конфигурационных файлов и т.д. Представление подобных данных в виде визуального графа может быть наглядным, но требует реализации визуального редактора с постоянной актуализацией под меняющиеся требования, что часто избыточно и трудоемко в поддержке. В качестве альтернативы обычно используется встраиваемый скрипт-язык, позволяющий писать логику поведения в виде упрощенного кода, который потом будет интерпретирован основным приложением.
Готовые решения
Для подобных задач уже существуют готовые решения, самые известные из них это Lua
и AngelScript
. Эти проекты проверены временем и предоставляют богатый функционал, который… практически всегда избыточен, когда стоит задача не написать всю логику приложения на скрипт-языке, а дать минимальную возможность что-то настраивать и при этом быть гибче, чем просто набор строк в конфигурационном файле.
ScriptVM
Так появился ScriptVM
- интерпретатор простого скрипт-языка, реализация которого занимает порядка 1к строк на C#
и без проблем может быть портирована на другие языки безо всяких зависимостей.
Особенности
Скрипт-язык представляет собой набор именованных функций с опциональными параметрами, умеет крутить циклы, понимает условное ветвление, умеет в переменные 2 типов (“строка” и “число”) и вызывать другие именованные функции. И это все, что он умеет. Нет штатной математики, работы со строками, нет скобок приоритетов из-за отсутствия инфиксных операторов - реализация максимально проста и весь требуемый функционал предлагается реализовывать в виде именнованных функций из основного приложения (далее - Хост
), в которое встраивается скрипт-язык.
Синтаксис
Синтаксис максимально упрощен - никаких точек с запятой и лишних скобок, на каждой строке может быть только одно выражение:
1 | # Поддерживаются однострочные комментарии до конца строки, начинающиеся со знака решетки. |
Хост-функции
Скрипт-язык ничего не умеет по умолчанию, это по сути полностью изолированная песочница, в которую можно добавлять хост-функции из основного приложения для расширения функционала. Каждая функция принимает список аргументов и должна вернуть результат с текстом ошибки. Например, если мы хотим дать возможность складывать в скрипте два числа:
1 | // Описание хост-функции. |
После этого в скрипт-коде ее можно сразу использовать:
1 | main() { |
Интеграция в редакторы
Для ScriptVM
реализовано расширение для vscode
, предоставляющее подсветку синтаксиса, работу с комментариями, всплывающие подсказки по базовым ключевым словам и шаблоны кода для функций, условий и циклов.
Пример применения
Допустим, мы хотим реализовать логику поведения для книги-игры (или визуальной новеллы), где каждая локация представляет собой “страницу”. Мы хотим добавить интерактивности и иметь возможность работать с инвентарем, а так же менять варианты ответов игрока в зависимости наличия предметов в карманах.
Требования к функционалу скрипта
- Мы должны мочь задавать основной текст, описывающий локацию.
- Мы должны мочь добавлять варианты ответов игрока (действия).
- Мы должны мочь добавлять и убирать предметы в/из карманы игрока.
Реализация
Набросаем тестовое событие, на основне которого были сформулированы требования:
1 | # Стартовая локация. |
Каждая “страница” является функцией с уникальным именем, первая “страница” пусть будет называться “entry”.
Реализуем обвязку для “книги” на стороне хоста:
1 | public class Book { |
И псевдокод инициализации, загрузки и обработки логики “книги”:
1 | var book = new Book (); |
Заключение
Это все легко расширяется под любой функционал путем добавления новых хост-функций и может использоваться в качестве конфигуратора настроек, кат-сцен, инициализации окружения, настройки сторонней логики в моддинге хост-приложения и других ситуациях, когда не хочется писать разнообразные редакторы или парсеры для кастомных конфигураций.
Актуальные версии пакетов доступны в закрытом discord-сервере для vk/boosty-подписчиков.