Оглавление

Вызов скриптовой функции

Подготовка контента и вызов функции

Обычно скиптовая функция в процессе работы проходит следующие шаги:
  1. Подготовка контекста
  2. Установка агрументов функции
  3. Запуск функции
  4. Получение возвращаемых значений

Код для этого может выглядеть примерно так:

// Получаем экземпляр скриптового контекста.
asIScriptContext *ctx = engine->CreateContext();

// Получение id функции из модуля. Данную величину рекомендуется сохранить,
// если планируется вызывать функцию много раз.
int funcId = engine->GetModule(module_name)->GetFunctionIdByDecl(function_declaration);

// Подготавливаем стек
ctx->Prepare(funcId);

// Устанавливаем аргументы функции
ctx->SetArgDWord(...);

int r = ctx->Execute();
if( r == asEXECUTION_FINISHED )
{
  // Получаем возвращаемые значение в случае успешного завершения работы функции
  asDWORD ret = ctx->GetReturnDWord();
}

// Очищаем контекст
ctx->Release();

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

Возвращаемое значение достается функцией GetReturnValue(), но только в случае если скрипт завершился нормально, т.е. Execute() вернула asEXECUTION_FINISHED.

Передача и получение примитивов

При запуске скриптов, которые имеют входные параметры, их необходимо установить после Prepare() и перед Execute(). Устанавливаются аргументы через SetArg:
int SetArgDWord(int arg, asDWORD value);
int SetArgQWord(int arg, asQWORD value);
int SetArgFloat(int arg, float value);
int SetArgDouble(int arg, double value);

Где arg - номер аргумента, первый - 0, второй - 1, и так далее. value - значение аргумента. Метод задает тип параметра, для примитивных типов вы можете использовать любой из них. Если параметр - ссылка на примитивный тип, используйте SetArgDWord() и передайте указатель на значение. Для непримитивных типов используйте SetArgObject(), который будет описан ниже.

// Контекст подготовлен для скриптовой функции следующего вида
// int function(int, double, int&in)

// Указываем параметры, начиная с первого
ctx->SetArgDWord(0, 1);
ctx->SetArgDouble(1, 3.141592);
int val;
ctx->SetArgDWord(2, (asDWORD)&val);

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

asDWORD GetReturnDWord();
asQWORD GetReturnQWord();
float   GetReturnFloat();
double  GetReturnDouble();

Помните, что вы должны быть уверены в валидности возвращаемых значений, например если выполнение скрипта вызвало ошибки, возвращаемые значения валидными не будут. Проверить валидность можно с помошью Execute() и GetState(), которые должны возвращать asEXECUTION_FINISHED.

Передача и получение объектов

Передача обьектов в скрипт похожа на передачу примитивных типов. Для этого используется SetArgObject():
int SetArgObject(int arg, void *object);

arg - число аргументов. object - указатель на объект.

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

// Хотим передать обьект в функцию
CObject obj;

// Передаем обьект в функцию
ctx->SetArgObject(0, &obj);

Получаем обьект из функции используя GetReturnObject():

void *GetReturnObject();

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

// Обьект который, в который мы сохраним возвращаемое значение
CObject obj;

// Запускаем функцию
int r = ctx->Execute();
if( r == asEXECUTION_FINISHED )
{
  // Получаем указатель на возвращаемый обьект и копируем его в свой
  obj = *(CObject*)ctx->GetReturnObject();
}

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

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

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

Пример:

void PrintExceptionInfo(asIScriptContext *ctx)
{
  asIScriptEngine *engine = ctx->GetEngine();

  // Определяем причину ошибки
  printf("desc: %s\n", ctx->GetExceptionString());

  // Определяем функцию с ошибкой
  int funcId = ctx->GetExceptionFunction();
  const asIScriptFunction *function = engine->GetFunctionDescriptorById(funcId);
  printf("func: %s\n", function->GetDeclaration());
  printf("modl: %s\n", function->GetModuleName());
  printf("sect: %s\n", function->GetScriptSectionName());
  
  // Определяем номер строки с ошибкой
  printf("line: %d\n", ctx->GetExceptionLineNumber());
}

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


Перевод - arroy.one@gmail.com. При копировании материалов указывайте ссылку на источник.