diff --git a/src/script/component.h b/src/script/component.h index 43376798..9987dc6f 100644 --- a/src/script/component.h +++ b/src/script/component.h @@ -52,6 +52,8 @@ template class ComponentHandler lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaNewIndex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, luaPairs); + lua_setfield(L, -2, "__pairs"); lua_pushcfunction(L, [](lua_State* L) { if (!array_count_func) luaL_error(L, "Tried to get length of component %s that has no array", component_name); auto ptr = luaToComponent(L, -1); @@ -93,6 +95,27 @@ template class ComponentHandler return 0; }); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, [](lua_State* L) { + IndexedComponent* icptr = static_cast(lua_touserdata(L, -1)); + if (!icptr) return 0; + if (!icptr->entity) return 0; + auto ptr = icptr->entity.template getComponent(); + if (!ptr) return 0; + if (array_count_func(*ptr) <= icptr->index) return luaL_error(L, "Index out of range for pairs on component %s", component_name); + + lua_newtable(L); + int tbl = lua_gettop(L); + for (auto mem : indexed_members) { + mem.second.getter(L, ptr, icptr->index); + lua_setfield(L, tbl, mem.first.c_str()); + } + lua_settop(L, tbl); + lua_getglobal(L, "next"); + lua_rotate(L, 2, -1); + lua_pushnil(L); + return 3; // next, tbl, nil + }); + lua_setfield(L, -2, "__pairs"); lua_pushstring(L, "sandboxed"); lua_setfield(L, -2, "__metatable"); lua_pop(L, 1); @@ -163,6 +186,39 @@ template class ComponentHandler return 0; } + static int luaPairs(lua_State* L) { + auto eptr = lua_touserdata(L, -1); + if (!eptr) return 0; + auto e = *static_cast(eptr); + if (!e) return 0; + auto ptr = e.getComponent(); + if (!ptr) return 0; + + lua_newtable(L); + int tbl = lua_gettop(L); + if (array_count_func) { + int count = array_count_func(*ptr); + for (int i = 0; i < count; i++) { + auto ic = static_cast(lua_newuserdata(L, sizeof(IndexedComponent))); + ic->entity = e; + ic->index = i; + luaL_getmetatable(L, array_metatable_name.c_str()); + lua_setmetatable(L, -2); + lua_seti(L, tbl, i + 1); + } + } + for (auto mem : members) { + mem.second.getter(L, ptr); + lua_setfield(L, tbl, mem.first.c_str()); + } + + lua_settop(L, tbl); + lua_getglobal(L, "next"); + lua_rotate(L, 2, -1); + lua_pushnil(L); + return 3; // next, tbl, nil + } + static T* luaToComponent(lua_State* L, int index) { auto eptr = lua_touserdata(L, index); if (!eptr) return nullptr; @@ -236,4 +292,4 @@ template class ComponentHandler } -#endif//SP_SCRIPT_ENVIRONMENT \ No newline at end of file +#endif//SP_SCRIPT_ENVIRONMENT diff --git a/src/script/environment.cpp b/src/script/environment.cpp index 5e58484e..0e605524 100644 --- a/src/script/environment.cpp +++ b/src/script/environment.cpp @@ -137,6 +137,47 @@ static int luaEntityNewIndex(lua_State* L) { return 0; } +static int luaEntityPairsNext(lua_State* L) { + lua_settop(L, 2); // ensure we have a (possibly nil) key, as we may have been called with just (entity) + + auto e = Convert::fromLua(L, 1); + if (!e) return 0; + + if (lua_type(L, 2) == LUA_TNIL) { + // nil => first call; return components first + lua_pop(L, 1); + lua_pushstring(L, "components"); + *static_cast(lua_newuserdata(L, sizeof(ecs::Entity))) = e; + luaL_getmetatable(L, "entity_components"); + lua_setmetatable(L, -2); + return 2; + } + if (lua_type(L, 2) == LUA_TSTRING && !strcmp(lua_tostring(L, 2), "components")) { + // second call, give lua_next a nil to get the first LTC key. + // from the third call onwards, we'll pass the previous key directly to lua_next. + lua_pop(L, 1); + lua_pushnil(L); + } + + auto ltc = e.getComponent(); + if (!ltc) return 0; + + lua_rawgetp(L, LUA_REGISTRYINDEX, ltc); + lua_rotate(L, 2, -1); + + return lua_next(L, -2) ? 2 : 0; +} + +static int luaEntityPairs(lua_State* L) { + auto e = Convert::fromLua(L, 1); + if (!e) return 0; + + lua_pushcfunction(L, luaEntityPairsNext); + lua_pushvalue(L, -2); + lua_pushnil(L); + return 3; +} + static int luaEntityComponentsIndex(lua_State* L) { auto eptr = lua_touserdata(L, -2); if (!eptr) return 0; @@ -165,6 +206,29 @@ static int luaEntityComponentsNewIndex(lua_State* L) { return luaL_error(L, "Tried to set non-exsisting component %s", key); } +static int luaEntityComponentsPairs(lua_State* L) { + auto eptr = lua_touserdata(L, -1); + if (!eptr) return 0; + auto e = *static_cast(eptr); + if (!e) return 0; + + lua_newtable(L); + int tbl = lua_gettop(L); + + for (auto entry : ComponentRegistry::components) { + int n = entry.second.getter(L, e, entry.first.c_str()); + if (n == 1) { + lua_setfield(L, tbl, entry.first.c_str()); + } + } + + lua_settop(L, tbl); + lua_getglobal(L, "next"); + lua_rotate(L, 2, -1); + lua_pushnil(L); + return 3; // next, tbl, nil +} + static int luaEntityEqual(lua_State* L) { auto e1 = Convert::fromLua(L, -2); if (!e1) return 0; @@ -209,6 +273,8 @@ lua_State* Environment::getLuaState() lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaEntityNewIndex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, luaEntityPairs); + lua_setfield(L, -2, "__pairs"); lua_pushcfunction(L, luaEntityEqual); lua_setfield(L, -2, "__eq"); lua_pushstring(L, "sandboxed"); @@ -221,6 +287,8 @@ lua_State* Environment::getLuaState() lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaEntityComponentsNewIndex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, luaEntityComponentsPairs); + lua_setfield(L, -2, "__pairs"); lua_pushstring(L, "sandboxed"); lua_setfield(L, -2, "__metatable"); lua_pop(L, 1);