Приветствую!
Ковыряю LUA, хочется в скрипте на LUA сделать подобное:
function call_object_method(obj)
obj.MyMethod("Hello from LUA!");
end
Имею солидный опыт использования ActiveScript в программах на С++, там подобные вещи делаются реализацией интерфейса IDispatch для объекта, и в методе Invoke уже можно разбирать, какой метод вызван и действовать соответственно.
Какими путями сделать подобное в LUA? Сразу скажу, что регистрировать глобальный объект в LUA не хочется, т.к. некошерно это. На мой взгляд гораздо правильней иметь функцию (например, по обсчету состояния NPC), в которую будет передаваться экземпляр класса NPC, а из скрипта уже будут дергаться его методы при необходимости.
Сильно подозреваю, что реализация данного вопроса как-то связана с метатаблицами, однако многочасовое копание в документации пока понимания не принесло. Помогите плз наступить на правильные грабли
З.Ы. Использовать tolua и luabind не предлагать, т.к. цель стоит совершенно очевидная — разобраться в кишочках того, как это все должно правильно работать. Заранее благодарен.
Здравствуйте, Flamer, Вы писали:
F>Ковыряю LUA, хочется в скрипте на LUA сделать подобное:
F>F>function call_object_method(obj)
F> obj.MyMethod("Hello from LUA!");
F>end
F>
Это не проблема, только синтакс вызова метода в луа: obj
:MyMethod("...")
F>Имею солидный опыт использования ActiveScript в программах на С++, там подобные вещи делаются реализацией интерфейса IDispatch для объекта, и в методе Invoke уже можно разбирать, какой метод вызван и действовать соответственно.
F>Какими путями сделать подобное в LUA? Сразу скажу, что регистрировать глобальный объект в LUA не хочется, т.к. некошерно это. На мой взгляд гораздо правильней иметь функцию (например, по обсчету состояния NPC), в которую будет передаваться экземпляр класса NPC, а из скрипта уже будут дергаться его методы при необходимости.
Для начала прочитайте
Programming in Lua — ch.28: User-Defined Types in C (имейте в виду, что код 5.0.x)
Самый хороший и полный обзор метов связывания(от авторов луа):
Game Programming Games 6: Binding C/C++ objects to Lua by W. Celes, Luiz H. de Figueiredo, R. Ierusalismchy
Упрощенный пример кода можно посмотреть тут.
Где взять GPG6? :)
Здравствуйте, z00n, Вы писали:
Z>Это не проблема, только синтакс вызова метода в луа: obj:MyMethod("...")
Спасибо за ответ, дело в том, что с LUA пока опыта мало. Единственное, чего пока добился — это криво регистрировать объект как имеющий методы. Ниже небольшой пример того, что есть, но он не совсем правильно работает. Итак:
Скрипт LUA:
function object_test()
alert(obj.GetMessage());
end
Мой дикий класс для динамического связывания (там костыли, просьба воспринимать это как тест):
class CLuaObjectBinder
{
private:
typedef struct
{
CLuaObjectBinder* _this;
std::string MethodName;
} CThisData;
std::vector<CThisData> m_Methods; // methods to bind
std::string m_ObjectName; // name of bindable object
typedef struct _SUserData{CLuaObjectBinder* object;} SUserData;
static int closure(lua_State* state)
{
// получаем метатаблицу для объекта
luaL_getmetatable(state, "obj"); // костыль !!!!
CThisData* data = (CThisData* )lua_touserdata(state, lua_upvalueindex(1));
return data->_this->OnMethod(state,data->MethodName);
}
public:
void AddMethod(const std::string& name)
{
CThisData dt;
dt._this = this;
dt.MethodName = name;
m_Methods.push_back(dt);
};
int OnMethod(lua_State* state, const std::string& methodName)
{
std::string str = "Method name called: ";
str += methodName;
MessageBox(NULL,str.c_str(),"In C++",MB_OK);
if(methodName == "GetMessage")
{
luaPushParam(state,"returned from dynamic binder!");
return 1;
}
return 0;
}
void Bind(lua_State* state, const char* funcName)
{
lua_newtable(state);
int methods = lua_gettop(state);
luaL_newmetatable(state, m_ObjectName.c_str());
int metatable = lua_gettop(state);
lua_pushstring(state, m_ObjectName.c_str());
lua_pushvalue(state, methods);
lua_settable(state, LUA_GLOBALSINDEX);
lua_pushstring(state, "__metatable");
lua_pushvalue(state, methods);
lua_settable(state, metatable);
lua_pushstring(state, "__index");
lua_pushvalue(state, methods);
lua_settable(state, metatable);
// регистрируем методы
for(std::vector<CThisData>::iterator it = m_Methods.begin();it != m_Methods.end(); ++it)
{
lua_pushstring(state, (*it).MethodName.c_str());
lua_pushlightuserdata(state, (void* )&(*it));
lua_pushcclosure(state, closure, 1);
lua_settable(state, methods);
}
lua_pop(state, 2);
// get function pointer
lua_getfield(state, LUA_GLOBALSINDEX, funcName);
// call function
lua_call(state,0,0);
}
private:
CLuaObjectBinder(const CLuaObjectBinder& rhs);
CLuaObjectBinder operator=(const CLuaObjectBinder& rhs);
public:
CLuaObjectBinder(const char* name)
{
m_ObjectName = name;
};
~CLuaObjectBinder()
{
};
};
Как это работает:
CLuaObjectBinder binder("obj");
binder.AddMethod("GetMessage");
binder.Bind(luaHandle,"object_test");
Из кода видно, что теперь в функции object_test можно обращаться к объекту obj по имени, и даже вызывать его методы. Но хочется-то передавать экземпляр этого объекта в функцию, т.е.:
function object_test(obj)
alert(obj.GetMessage());
end
В лоб этого сделать не получается, видимо недопонимаю архитектуры. Буду рад любым мыслям по поводу. Полпути уже пройдено, осталось вторую половину домучить.
Так что вопрос стоит так: как сказать LUA, что параметр, передаваемый в функцию — это объект со своей уже настроенной таблицей методов? Чтобы LUA знал, что есть такие методы у объекта, и брал их из метатаблицы. Я так подозреваю, что теоретически это можно сделать следующим образом: создать новую таблицу, положить туда все методы, кинуть все это в стек, затем кинуть какой-либо объект, который будет привязан к этой таблице. Проблема начинается со слов "какой-либо объект".
Ы?
З.Ы. Сорри за многабукаф.