Все взаимодействие Lua и Си происходит через некий стек. Для работы с этим стеком в Lua предусмотрен ряд функций которые мы и будем использовать. Я не буду описывать подробно эти функции что они делают и зачем. Разъяснения можно найти на форумах в интернете откуда я собственно это все и брал. Итак допустим нам нужно проинициализировать для Lua объект конкретного игрока или моба. У меня в маде структура такого типа носит название CHAR_DATA. Создадим функцию для инициализации этого объекта в Lua.
void initmetach (const char* tname,lua_State *vLm,CHAR_DATA *ch) { void** ptch; //Заводим войдовский указатель ptch=(void**)lua_newuserdata(vLm, sizeof(void*)); //Резервируем под указатель память в Lua машине *ptch=ch;//Присваиваем указателю значение нашего объекта lua_newtable(vLm);//Создаем новую таблицу в Lua lua_pushstring(vLm,"__newindex"); lua_pushlightuserdata(vLm,ch); lua_pushcclosure(vLm, ch_set, 1); //Привязываем к полю __newindex функцию для установки значений объекта ch lua_rawset(vLm, -3); lua_setmetatable(vLm,-2); lua_getmetatable(vLm, -1); lua_pushstring(vLm, "__index"); lua_pushlightuserdata(vLm,ch); lua_pushcclosure(vLm, ch_get, 1); //Привязываем к полю __index фукнцию для получения значений lua_rawset(vLm, -3); lua_setmetatable(vLm, -2);//Устанавливаем метатаблицу для нашей новой таблицы lua_setglobal(vLm, tname); //Устанавливаем имя таблицы по которому она будет доступна в Lua например «ch». } |
Теперь вызвав в каком-нибудь месте эту функцию и передав ей имя для объекта в Lua – tname указатель на машину в Lua – vLm и объект персонажа – ch мы получим в lua переменную с именем ch которая связана с нашим объектом ch в Си.
В Lua это будет выглядеть например так:
local hit=ch.hit --Получаем кол-во жизни у игрока
ch.hit=hit+100 –Добавляем к текущей жизни игрока 100
Теперь о функция ch_set и ch_get. Первая из них будет у нас отвечать за присвоение значений полей объекта CHAR_DATA из Lua, а вторая для полечения значений полей CHAR_DATA в Lua.
Функция ch_set:
static int ch_set(lua_State *vLm) if(!str_prefix(var,"hit")) //Если в Lua идет обращение к полю hit тогда… (str_prefix) внутренняя функция мада |
В данной функции идет мы получаем указатель на объект нашего персонажа, получаем имя поля которому в Lua пытаются присвоить значение и затем в зависимости от имени поля мы уже производим какие-то действия.
Функция ch_get аналогична функции ch_set только так сказать с обратным знаком
static int ch_get(lua_State *vLm) { void** pch; CHAR_DATA *ch; const char *var; var= luaL_checkstring(vLm, 2); pch=(void**)lua_touserdata(vLm,1); if(pch==NULL) return 0; ch=*pch; if(!str_prefix(var,"hit")) //Если в Lua у нас запросили значение поля hit структуры ch { lua_pushnumber(vLm,ch->hit); //Пихаем в стек Lua значение поля return 1; } return 0; } |
То есть для примера процесс можно описать так:
В игре у нас срабатывает триггер на какое-либо событие. Ну например на мобе висит триггер на вход в локацию. В этом триггере при срабатывании обычно два объекта назовем их например ch и vic – ch – это моб на котором висит триггер к которому привязан скрипт который у нас будет выполняться при срабатывании триггера, а vic это объект игрока или моба который зашел в комнату таким образом в Си при подготовке выполнения скрипта тригера у нас будет:
initmetach (“ch”, vLm, ch);//Помещаем в Lua объект моба выполняющего скрипт
|
Ну а в самом Lua скрипте работаем с объектами ch и vic и их полями так как нам надо. При использовании такого механизма портирования можно передавать и работать в Lua с любыми игровыми объектами мада, что очень удобно и функционально.
Прерывание скриптов по времени.
Выполнение скриптов имеет один неприятный момент. Если вдруг в скрипте у нас ошибка не синтаксическая, а логическая и скрипт начинает например выполнять вечный цикл, то и мад соответственно у нас зависает, чтобы избежать такого развития событий в Lua предусмотрена функци lua_sethook. Функция устанавливает отладочную функцию для Lua которая выполняется при наступлении каких-либо событий. События устанавливаются побитывомыми константами типа: LUA_MASKCALL - подробности смотрите в руководстве Lua. В нашем случае установка хука имеет вид:
lua_sethook(vLm, LuaHook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT|LUA_MASKLINE, 1); |
гдек LuaHook – функция выполняющаяся при наступлении ну например вечного цикла
static void LuaHook(lua_State *vLm, lua_Debug *ar) { if(((long)time( NULL ))-script_time_start>time_out_script) { char buf[256]; sprintf(buf,"Превышен лимит времени выполнения, выполнение преврвано."); luaL_error(vLm,buf); } } |
Перед начало выполнения скрипта мы в переменную script_time_start помещаем время начала выполенения скрипта в секундах. А в консанта time_out_script содержит значение секунд которое отводится на выполнение скрипта и если у нас разница в текущем времени и времени выполнения скрипта превышает time_out_script – выполнение прерывается.