Script engine.cpp

Материал из MODFAQ.RU — моддинг игр серии S.T.A.L.K.E.R., The Elder Scrolls и Fallout
Перейти к: навигация, поиск

Скриптовые «вылеты»

Общее решение

Решение подобных ошибок[1] - задача нетривиальная. Поэтому их исправлением следует заниматься только тем, кто обладает хотя бы базовыми знаниями скриптинга.

1 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...\gamedata\scripts\xr_danger.script:116: attempt to index field 'ignore_types' (a nil value)

Ошибка[2]

Попытка взять значение из переменной ignore_types (может быть любая другая). Движок игры ожидал, что это таблица, а оказалось nil.

Подсказка скриптеру

Необходимо изменить код таким образом, чтобы там где ожидается таблица, была таблица или чтобы из nil не пытались прочесть какие-то значения.
Конкретно в данном случае скрипт записывает настройки игнорирования опасности в таблицу db.storage[npc:id()].danger.ignore_types, а пытается проверять по несуществующей таблице db.storage[npc:id()].ignore_types.

2 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...\gamedata\scripts\.script:34: attempt to call method 'section' (a nil value)

Ошибка

У какого-то объекта пытались вызвать метод section (название метода может быть любым другим). Обнаружилось, что у этого объекта, такого метода не существует.

Подсказка скриптеру

Возможные варианты:

  1. Это был объект не того класса, как предполагалось (клиентский вместо серверного, или наоборот, или другие классы).
  2. Возможно была опечатка в названии метода, и он просто называется не так.
  3. Возможно невнимательно был изучен данный класс, и у него просто нет и не должно быть такого метода.

Например, это можно проверить конструкциями наподобие этой:

if obj.section and type(obj.section) == 'function' then obj:section() end

Т.е. до вызова метода, проверить, что у объекта существует такое поле, и имеет тип function, т.е. его возможно вызвать. Но следует понимать что не стоит обвешивать такими проверками все подряд вызовы везде. Куча проверок займет много времени и вызовет тормоза. Это годится лишь для отладки - узнали есть ли метод или нет. Если нет, значит и не надо пытаться его вызывать, а если есть, то можно вызывать без всяких проверок.

3 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...w of chernobyl\gamedata\scripts\<имя файла>.script:<номер строки>: attempt to perform arithmetic on a nil value

Ошибка

Попытка выполнения арифметической операции над nil.

Подсказка скриптеру

Чтобы исправить ошибку, сначала необходимо её найти. Обратите внимание на <номер строки>, попытка выполнения арифметической оперции над nil происходит именно в ней. Ещё могут быть указаны имена переменных, это так же является подсказкой.

4 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...\gamedata\scripts\<имя файла>.script:<номер строки>: attempt to compare number with nil

Ошибка

Попытка сравнения числа с nil

Подсказка скриптеру

Чтобы исправить ошибку, сначала необходимо её найти. Обратите внимание на <номер строки>, попытка сравнения числа с nil происходит именно в ней. Ещё могут быть указаны имена переменных, это так же является подсказкой.

5 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...\gamedata\scripts\<имя файла>.script:<номер строки>: attempt to perform arithmetic on field '?' (a nil value)

Ошибка

Аналог вылетов из вариантов 3 и 4. Попытки арифметических действий над nil, просто этот nil не имеет собственного имени и является элементом таблицы.

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

Подсказка скриптеру

Чтобы исправить ошибку, сначала необходимо её найти. Здесь, либо данные читаются не оттуда, откуда должны, либо где-то должны были их туда записать, но не записали.

6 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: error in error handling

Ошибка

Причину вылета назвать достаточно трудно, вероятно это что-то глубоко движковое. Такой вылет может вызывать передача клиентcкого объекта в функцию switch_offline, но не только это.

Подсказка скриптеру

В случае передачи клиентского объекта - устранить ошибку. Но определить причину в большинстве случаев крайне проблематично - попробуйте загрузить последнее сохранение.

Можно предположить, что подобный вылет может возникать в ряде случаев, когда в движковые методы, ожидающие объект определенного класса, передается объект не того класса, который они ожидают. Если предположение верно - проверить правильность данных, передаваемых таким движковым методам.

7 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: attempt to call a nil value

Ошибка

Происходит при попытке вызвать конструктор класса, которого не существует или локальную функцию, которой не существует.

Подсказка скриптеру

Возможные варианты:

  1. В имени конструктора/функции допущена опечатка, и он просто не так называется.
  2. Вызываемое не является конструктором, функцией, или просто не существует.

8 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : D:\xray-svn\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: C stack overflow

Ошибка

Обратите также внимание на текст выше строки FATAL ERROR из лога.

Строка Arguments в разных случаях может отличаться. Причина подобных вылетов - передача некорректных значений функциям игры.

А общий смысл - попытка сделать что-то, чего делать нельзя в принципе, т.е. невозможное (как деление на ноль, например).

Суть ошибки в том, что какая-то функция вызвана огромное число раз подряд, вместо одного. Функции иногда вызываются рекурсивно, в цикле, но всегда это имеет ограниченные и разумные пределы. В данном случае, вылет из-за того что эти пределы исчезли.

Решение

Если проблема возникла однократно - загрузите последнее сохранение.

В самом деле помогает, т.к. периодически такие ситуации возникают случайным образом даже с оригинальными GSC-скриптами.

Подсказка скриптеру

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

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

Наглядный пример:

function actor_item_take(obj, item)
 --log("events.actor_item_take")

Тут закомментирован вызов лога, а когда был не закомментирован - в лог сообщалось о каждом вызове этой функции. Так это и делается.

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

Примечание:

Иногда та же самая ошибка, т.е. та же самая причина, может приводить к другому вылету - Ran out of memory. Это когда вызываемые функции успевают "сожрать" всю память раньше, чем "сожрут" весь стек.

9 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: No such operator defined

Ошибка

Попытка использовать для какого-то объекта, несуществующий метод. Зачастую путаница с серверными и клиентскими методами.

Подсказка скриптеру

См. вариант 2, там было про отсутствующий метод section, здесь имя метода не указано, но смысл тот же. Как правило, объект не того класса, или не существующий у данного класса метод, или попытка вызвать как метод то, что им не является.

10 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line        : 73
Description    : 
Arguments    : LUA error: ...\gamedata\scripts\<имя файла>.script:<номер строки>: unfinished capture

Ошибка

Единственная известная причина данного вылета, это попытка использовать для функции string.find в качестве шаблона "волшебный символ" открывающуюся круглую скобку, т.е. попытка найти скобку таким образом:

local p = string.find(str, "(")

Подсказка скриптеру

Для поиска открывающейся круглой скобки используйте параметр plain(local p) для данной функции со значением true, он выключает возможность поиска по шаблону и в таком случае производится поиск подстроки как есть:

local p = string.find(str, "(", 1, true)

11 вариант

Expression    : fatal error
Function      : CScriptEngine::lua_error
File          : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp
Line          : 73
Description   : 
Arguments     : LUA error: ...ing\s.t.a.l.k.e.r\gamedata\scripts\inv_system.script:1674: attempt to call function 'GetCommand_TakeSlot' (a nil value)

Ошибка

Казалось бы, причина ясна - вызов функции, которой не существует. Однако функция есть, и называется именно так, и с ней все в порядке. Как и с самим файлом скрипта тоже - в нем нет синтаксических ошибок, движок игры не ругается на него самого, заявляя что он a nil value

Причина оказалась вот в чем - в начале скрипта, есть таблица, такого вида:

tbl = {
    string_key1 = number,
    string_key2 = number,
...

А далее есть еще одна таблица - вот такого вида:

tb_funcs = {
        [tbl.string_key1] = function(args...)
            ...
        end,
...

Т.е. значения ее - функции, а ключами являются значения из первой таблицы.

Ну так вот, в первой таблице изменили имя одного из ключей. А во второй - забыли это сделать. Получилось что во второй таблице, одна из функций находится по ключу, который вообще-то равен nil.

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

Подсказка скриптеру

Вывод - когда делаете в таблицах ключи вида массив/модуль/значение - убедитесь что это значение не равно nil, а то движок игры об этом нормально не скажет.

12 вариант

Тип №1

Expression : fatal error 
Function : CScriptEngine::lua_error 
File : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp 
Line : 73 
Description : <no expression> 
Arguments : LUA error: ...e.r_Закоулки правды\gamedata\scripts\uyman358.script:947: attempt to call field 'get_anomaly_data' (a nil value) 

Ошибка[3][4]

Для новичков: скрипт (в данном случае: uyman358.script) не может вызвать указанную в строке (в данном случае: 947) функцию (в данном случае: 'get_anomaly_data').

Для опытных: попытка вызова указанной функции (в данном случае: 'get_anomaly_data'). Движок игры ожидал, что это таблица, а оказалось nil.

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

Подсказка скриптеру

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

Для опытных: необходимо изменить код таким образом, чтобы там где ожидается функция, была функция или чтобы из nil не пытались прочесть какие-то значения.

Тип №2

Expression : fatal error 
Function : CScriptEngine::lua_error 
File : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp 
Line : 73 
Description : <no expression> 
Arguments : LUA error: ....- Народная Солянка\gamedata\scripts\xr_logic.script:1490: attempt to call field '?' (a nil value)

Ошибка[5]

Тут должно было быть имя функции или переменной, но его нет (в данном случае: '?'). Это значит, что ее, например, вызвали по числовому индексу из таблицы или еще как-то, причины могут быть разные.

А общий смысл - то, с чем пытались совершить указанное действие, не имеет имени.

Например, у типа 1:

uyman358.script:947: attempt to call field 'get_anomaly_data' (a nil value)

Указано имя get_anomaly_data. Ошибка произошла при попытке действия с именно этой переменной, ее имя указывается всегда, когда движок может указать имя с которым произошла ошибка. Но нередко бывает, что у переменной нет имени. Вот тогда он и пишет '?'

13 вариант

Expression    : fatal error
Function      : CScriptEngine::lua_error
File          : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line          : 73
Description   : <no expression>
Arguments     : LUA error: ...ow of chernobyl\gamedata\scripts\bind_stalker.script:341: attempt to call global 'give_info' (a nil value)

Ошибка

В файле _g.script не найдена указанная глобальная функция (в данном случае: give_info)

Решение

Проверить правильность имени функции, а также её наличие в _g.script.

14 вариант

Expression    : fatal error
Function      : CScriptEngine::lua_error
File          : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line          : 73
Description   : <no expression>
Arguments     : LUA error: not enough memory

Ошибка[6][7][8]

LuaJIT может использовать память только в младших 2 Гб, а в крупных модах туда складываются крупные текстуры, крупные локации и все остальное такое же крупное. В итоге через какое-то время младшие 2 Гб оказываются забиты и, хотя памяти еще полно, LuaJIT выделить для себя память не может.

Решение[9]

  • Попробуйте загрузить последние сохранения или уйти на другую локацию.
    В некоторых случаях это помогает из-за того, что при старте LuaJIT успевает отхватить себе память раньше, чем ее захватят текстуры, и какое-то время LuaJIT еще проработает.

или

  • Используйте 64-битный движок OGSR Engine.
    Он выделяет для LuaJIT память заранее. По нынешним меркам ему нужны сущие крохи - порядка сотни мегабайт.


Expression : fatal error
Function : CScriptEngine::lua_error
File : E:\priquel\sources\engine\xrServerEntities\script_engine.cpp
Line : 180
Description : <no expression>
Arguments : LUA error: not enough memory

Ошибка[10][11][12]

Версия игры отличается, см. строчку File: (в данном случае: ЧН)

Решение

Использовать надо движок X-Ray Engine by Abramcumner

15 вариант

Expression    : fatal error
Function    : CScriptEngine::lua_error
File        : D:\xray-svn\xr_3da\xrGame\script_engine.cpp
Line        : 74
Description    : <no expression>
Arguments    : LUA error: ...\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value)
Expression : fatal error
Function : CScriptEngine::lua_error
File : E:\priquel\sources\engine\xrServerEntities\script_engine.cpp
Line : 180
Description : <no expression>
Arguments : LUA error: d:\games\s.t.a.l.k.e.r\cs\gamedata\scripts\_g.script:975: bad argument #2 to 'format' (string expected, got nil)

Ошибка[13]

Для новичков: какой-то скрипт, не может вызвать какую-то функцию, из-за того что вызов функции написан неправильно, а именно, отсутствует имя функции. Должно быть так имя_скрипта.имя_функции_в_скрипте, а оно вот так имя_скрипта..

Для опытных: имя скрипта (в данном случае: _g), номер строки (в данном случае: 20) и номер аргумента после симмвола # (в данном случае: 2) — могут быть другими. Ошибка заключается в том, что функция string.format (может быть и другая) ожидала получить во втором аргументе в указанной строке файла - строку, а получила nil.

Подсказка скриптеру

Для новичков: проверяйте, что изменяли в скриптах последний раз, а именно — правильность вызова функции (наличие имени функции после имени скрипта).

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


Источники