IgdrasilJavaScriptScripting - JavaScript для Igdrasil Engine

IgdrasilJavaScriptScripting — это реализация системы скриптинга на основе JavaScript через библиотеку ClearScript V8. Предоставляет полную поддержку современного JavaScript (ES6+) для Igdrasil Engine.

Основные возможности

✅ Современный JavaScript (ES6+)
✅ Интеграция через ClearScript V8
✅ Поддержка ES6 модулей (import/export)
✅ Поддержка Promise и async/await
✅ Модульная система
✅ Асинхронное выполнение скриптов
✅ Компиляция скриптов для повторного использования
✅ Двусторонняя передача данных между C# и JavaScript
✅ Поддержка C# классов и перечислений в JavaScript
✅ Встроенная отладка через Chrome DevTools

Быстрый старт

using IgdrasilEngine.Engine.Scripting.JS;

// Создать движок
var engine = new JavaScriptEngine("MyGame");

// Выполнить скрипт
var result = engine.Evaluate("2 + 2");
Console.WriteLine(result); // 4

// Работа с переменными
engine.SetValue("playerHealth", 100);
var health = engine.GetValue<int>("playerHealth");

Архитектура

IgdrasilJavaScriptScripting
├── JavaScriptEngine - Основной движок скриптов
├── JavaScriptExecutable - Скомпилированный JS-скрипт
├── JavaScriptModuleInterface - Регистрация функций/классов
└── PropertyBagTree - Дерево объектов для модулей

Конструкторы JavaScriptEngine

// Базовый
var engine = new JavaScriptEngine("MyGame");

// С ограничениями ресурсов
var constraints = new V8RuntimeConstraints
{
    MaxNewSpaceSize = 16,
    MaxOldSpaceSize = 512
};
var engine = new JavaScriptEngine("MyGame", constraints);

// С флагами
var flags = V8ScriptEngineFlags.EnableDebugging | 
            V8ScriptEngineFlags.EnableRemoteDebugging;
var engine = new JavaScriptEngine("MyGame", flags, debugPort: 9222);

// Полный контроль
var engine = new JavaScriptEngine("MyGame", constraints, flags, debugPort: 9222);

Отладка

// Включить отладку на порту 9222
var engine = new JavaScriptEngine(
    "MyGame", 
    V8ScriptEngineFlags.EnableDebugging | V8ScriptEngineFlags.EnableRemoteDebugging,
    debugPort: 9222
);

// Проверить, включена ли отладка
if (engine.IsDebug)
{
    Console.WriteLine("Откройте chrome://inspect в Chrome");
}

Chrome DevTools

  1. Запустите движок с отладкой
  2. Откройте Chrome и перейдите на chrome://inspect
  3. Найдите ваш процесс в списке Remote Target
  4. Нажмите "inspect" для открытия DevTools

Возвращаемые значения

JavaScript возвращает одно значение, поэтому все методы возвращают object:

// Примитивы
var num = engine.Evaluate("42");
var str = engine.Evaluate("'hello'");
var flag = engine.Evaluate("true");

// Объекты и массивы
var obj = engine.Evaluate("({ x: 10, y: 20 })");
var arr = engine.Evaluate("[1, 2, 3]");

// Приведение типов
var number = engine.GetValue<int>("myNumber");
var text = engine.GetValue<string>("myString");

Типы данных

C# → JavaScript

C# JavaScript
int, long, float, double number
string string
bool boolean
null null
Dictionary<,> Object
List<>, Array Array
C# класс Object (host object)
Delegate, Action, Func function

JavaScript → C#

// Числа
var num = engine.GetValue<double>("myNumber");

// Строки
var str = engine.GetValue<string>("myString");

// Булевы значения
var flag = engine.GetValue<bool>("myFlag");

// Объекты
var obj = engine.GetValue<dynamic>("myObject");
Console.WriteLine(obj.property);

// Массивы
var arr = engine.GetValue<object[]>("myArray");

ES6 Модули

Регистрация модуля

public class MathModule : Module<JavaScriptModuleInterface>
{
    public override string Name => "mymath";
    
    public override void Initialize(JavaScriptModuleInterface moduleInterface)
    {
        moduleInterface.RegisterFunction("square", (double x) => x * x);
        moduleInterface.RegisterValue("PI", Math.PI);
    }
}

// Использование
engine.RegisterModule(new MathModule());

Использование в JavaScript

import mymath from 'mymath';

console.log(mymath.square(5));  // 25
console.log(mymath.PI);         // 3.14159...

// Деструктуризация
import { square, PI } from 'mymath';
console.log(square(5));

Современный JavaScript

Arrow Functions

const double = x => x * 2;
const add = (a, b) => a + b;

console.log(double(5));  // 10
console.log(add(3, 7));  // 10

Template Literals

const name = 'Player';
const level = 10;
const message = `${name} reached level ${level}!`;
console.log(message);

Destructuring

const player = { name: 'Hero', health: 100, mana: 50 };
const { name, health } = player;

const items = ['sword', 'shield', 'potion'];
const [weapon, armor] = items;

Spread Operator

const base = { health: 100, mana: 50 };
const player = { ...base, name: 'Hero', level: 10 };

const numbers = [1, 2, 3];
const all = [...numbers, 4, 5, 6];

Classes

class Player {
    constructor(name, health) {
        this.name = name;
        this.health = health;
    }
    
    attack(target) {
        console.log(`${this.name} attacks ${target}`);
    }
}

const player = new Player('Hero', 100);
player.attack('Dragon');

Async/Await

async function loadData() {
    const response = await fetch('data.json');
    const data = await response.json();
    return data;
}

loadData().then(data => console.log(data));

Компиляция скриптов

// Скомпилировать скрипт
var script = engine.Compile("x * x");

// Установить параметры
script.SetValue("x", 5);

// Выполнить много раз
for (int i = 0; i < 1000; i++)
{
    script.SetValue("x", i);
    var result = script.Evaluate();
    Console.WriteLine(result);
}

Обработка ошибок

using IgdrasilEngine.Engine.Scripting.Exceptions;

try
{
    engine.Execute("invalid javascript code");
}
catch (ScriptCompilationException ex)
{
    Console.WriteLine($"Синтаксическая ошибка: {ex.Message}");
    Console.WriteLine($"Строка: {ex.LineNumber}");
}

try
{
    engine.Execute("throw new Error('Something went wrong')");
}
catch (ScriptExecutionException ex)
{
    Console.WriteLine($"Ошибка выполнения: {ex.Message}");
    Console.WriteLine($"Stack Trace:\n{engine.StackTrace}");
}

Работа с Promise

// Создание Promise
const promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Done!'), 1000);
});

promise.then(result => console.log(result));

// Async/Await
async function asyncOperation() {
    try {
        const result = await promise;
        console.log(result);
    } catch (error) {
        console.error(error);
    }
}

Интеграция C# классов

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }
    
    public void Attack(string target)
    {
        Console.WriteLine($"{Name} attacks {target}");
    }
}

var module = new Module<JavaScriptModuleInterface>
{
    Name = "game",
    Initialize = mi =>
    {
        mi.RegisterClass("Player", typeof(Player));
        mi.RegisterFunction("createPlayer", (string name, int health) =>
            new Player { Name = name, Health = health });
    }
};

engine.RegisterModule(module);

В JavaScript:

import { Player, createPlayer } from 'game';

const player = createPlayer("Hero", 100);
player.Name = "Super Hero";
player.Attack("Dragon");
console.log(player.Health);

Global Object

Доступ к глобальному объекту JavaScript:

// Установить глобальную функцию
engine.Global.myFunction = new Action<string>(msg => Console.WriteLine(msg));

// Установить глобальный объект
engine.Global.config = new { debug = true, version = "1.0" };

// Получить значение
var debug = engine.Global.config.debug;

DocumentSettings

// Настройка доступа к файлам
engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableAllLoading;
engine.DocumentSettings.SearchPath = "./scripts;./modules";

// Загрузка внешних скриптов
engine.Execute(new DocumentInfo { Category = ModuleCategory.Standard }, 
    "import utils from 'utils.js'");

Производительность

Рекомендации

  1. Компилируйте часто используемые скрипты - избегайте повторной компиляции
  2. Используйте const/let вместо var - лучше для оптимизации V8
  3. Кешируйте обращения к host objects - они дороже обычных объектов
  4. Используйте TypedArray для больших массивов чисел

Ограничения ресурсов

var constraints = new V8RuntimeConstraints
{
    MaxNewSpaceSize = 16,        // MB для нового поколения
    MaxOldSpaceSize = 512,       // MB для старого поколения
    MaxExecutableSize = 128      // MB для исполняемого кода
};

var engine = new JavaScriptEngine("MyGame", constraints);

Безопасность

Ограничение доступа к файлам

engine.DocumentSettings.AccessFlags = DocumentAccessFlags.None; // Запретить загрузку файлов

Таймауты выполнения

// Установить лимит CPU
engine.CpuProfileSampleInterval = 1; // ms

// Прервать долгое выполнение
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await engine.EvaluateAsync("while(true) {}", cts.Token);

Ограничения

Ссылки


Проект: Igdrasil Engine
Автор: Alexander Izmailov
Собственность: Igdrasil Project
Версия: 1.0
Лицензия: Proprietary License

© 2026 Alexander Izmailov. Все права защищены.
Этот программный продукт является собственностью студии Igdrasil Project.