Пишу игру, в ней будут объекты. Для создания объекта у меня есть LUA скрипт, который вызывается сразу при создании объекта и формирует наш объект так, как требуется; возможно, вызывая в процессе какие то другие функции, функции из движка и т. д, не суть. На входе эта луа функция принимает аргумент - таблицу, содержащую данные произвольной топологии. Эта таблица содержит дополнительные данные, для создания объекта. Также движок должен позволять луа скриптам создавать другие объекты, передавая при этом произвольные параметры через таблицу. Алгоритм такой:
1) идёт итерация игрового цикла, выполняется какой-то скрипт, которому приспичило создать объект
Код
function someLuaFunction() local position = {6, 3, 2} Core.EntitiesManager.createEntity("testCube", position) end
здесь первый параметр - имя создаваемого объекта, второй - та самая таблица произвольной топологии, для разных объектов может иметь разный вид. Для простоты примера пусть будет тупо позиция.
2) вызывается функция из С++ (Core.EntitiesManager.createEntity), которая создаёт пустой объект, затем по имени объекта ищет подходящий скрипт для создания объекта с соответствующим именем, ищет в нём функцию onCreate и вызывает, ПЕРЕДАВ В НЕЁ идишник объекта И полученную таблицу. Упрощённо говоря:
Код
void EntitiesManager::createEntity( lua_State* params) { object = new чото там int id = objBuffer.push_back(object); luabridge::luaRef ref = достать из params первый аргумент - строку: имя объекта и найти по этому имени подходящий скрипт для создания // Как достать второй аргумент - таблицу из params и послать её на вход onCreate()? ref (id, ..); }
3) функция onCreate из нужного скрипта вызывается, имея на входе идишник и таблицу
Код
function testCube.onCreate(id, position) Core.EntitiesManager.setObjPosition(id, position); Core.ThrowError("луа психанул и кинул исключение без веской причины, наслаждайтесь"); end
Собсно вопрос - как реализовать пункт 2) Тобишь, как достать из lua_State аргумент-таблицу произвольной топологии и ничего в ней не меняя послать в функцию в луа в качестве аргумента
Перегуглил весь гугел - ничего не нашёл, а свободного времени мало чтобы досконально во всём разбираться...
Добавлено (05 Декабря 2018, 01:25) --------------------------------------------- Можно конечно обойти проблему так: 1) просим движок создать объект и возвратить идишник 2) НАПРЯМУЮ вызываем скрипт создания нужного объекта в луа
Но: 1) Это злостный костыль 2) это 2 строки луа кода вместо одной. (ну, тут можно обернуть в отдельную функцию) 3) всё равно хочется узнать ответ на вопрос в топе ибо могут в дальнейшем возникнуть похожие ситуации - всё время костылить чтоль?
Впрочем, работать такой подход будет чуть быстрее
Добавлено (05 Декабря 2018, 23:54) --------------------------------------------- Нашёл ответ на свой вопрос сам: пришлось всё-таки разбираться и ковыряться в луа стеке.
Итак: Вот пример функции, которая решила создать объект
Код
a = function () if zz == nil then local h = Core.Vector2(400.0, 300.0); zz = Core.EntitiesManager.createEntity("testEntity", h); end end
создаём юзердату-позицию, вызываем Core.EntitiesManager.createEntity, которая возвращает юзердату-идишник.
Вот сбайнденная Core.EntitiesManager.createEntity в движке:
Код
int createEntity(lua_State* state) { lua_settop(state, 2); // Получаем тока 2 аргумента - имя объекта и таблица, остальное убиваем из стека const char* objName = luaL_checkstring(state, 1); // Достаём первый аргумент - имя объекта lua_remove(state, 1); // Убираем первый аргумент чтоб не мешался. Теперь в стеке только таблица StorageId id = context.entitiesManager().createEntity(objName, state); // Создаём объект luabridge::push(state, id); // Возвращаем идишник объекта (то что в луа скрипте присваивается переменной zz ) return 1; // Указываем, что вернули одно значение }
А вот как выглядит непосредственно функция создания объекта
Код
void Entity::runCreateScript(StorageId id, lua_State* state) { context.entitiesManager().getObjectsDataRef()[id.uid] = luabridge::newTable(context.sharedVariables().runtimeState); if (idOnCreate_ >= 0){ if (!state){ refs_[idOnCreate_](id); } else{ // Интересующий код начинается здесь // Сейчас в стеке лежит только таблица refs_[idOnCreate_].push(state); // Пихаем в стек функцию testEntity.onCreate // Сейчас в стеке лежит таблица, затем функция luabridge::push(state, id); // Пихаем в стек идишник // Сейчас в стеке лежит таблица, затем функция, затем идишник lua_insert(state, 1); // перемещаем идишник в начало стека // Сейчас в стеке лежит идишник, затем таблица, затем функция lua_insert(state, 1); // перемещаем функцию в начало стека // Сейчас в стеке лежит функция, затем идишник, затем таблица
int code = lua_pcall(state, 2, 0, 0); // вызываем функцию, передав идишник и таблицу if (code != 0){ const char* error = luaL_checkstring(state, -1); throwString("Entity::runCreateScript %s", error); } } } }
Вот так выглядит код вызванного testEntity.onCreate
Код
testEntity.onCreate = function(id, pos) Core.Messaging.printMessage("ggg "..pos.x, "error"); end