diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index 011052ba..8e79ee13 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -153,19 +153,55 @@ lua_State *LuaStack::newthread(LuaSlot target) const { return result; } +void LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const { + lua_checkstack(L_, 20); + LuaVar globtab, cname; + LuaStack LS(L_, globtab, cname); + + // Convert class name to a table. + if (LS.isstring(classname)) { + if (LS.rawequal(classname, "_G")) { + luaL_error(L_, "_G is explicitly not allowed as a class name"); + } + LS.getglobaltable(globtab); + LS.rawget(classtab, globtab, classname); + if (!LS.istable(classtab)) { + luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); + } + LS.rawget(cname, classtab, "__class"); + if (!LS.rawequal(cname, classname)) { + luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); + } + } else { + LS.set(classtab, classname); + if (!LS.istable(classtab)) { + luaL_error(L_, "parameter must be a class"); + } + LS.rawget(cname, classtab, "__class"); + if (!LS.isstring(cname)) { + luaL_error(L_, "table is not a class"); + } + } + + // OK, we're done. + LS.result(); +} + void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const { lua_checkstack(L_, 20); LuaVar globtab; LuaStack LS(L_, globtab); // Validate the class name. - LS.checkstring(classname); + if (!LS.isstring(classname)) { + luaL_error(L_, "Not a class name: %s", lua_tostring(L_, classname)); + } if (LS.rawequal(classname, "_G")) { luaL_error(L_, "_G is explicitly not allowed as a class name"); } // Fetch the global environment from the registry. - LS.rawget(globtab, LuaRegistry, LUA_RIDX_GLOBALS); + LS.getglobaltable(globtab); // Get the classtab from the global environment. // Create it if it doesn't exist. @@ -201,6 +237,17 @@ void LuaStack::makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const { } } +void LuaStack::cleartable(LuaSlot tab) const { + checktable(tab); + lua_pushnil(L_); + while (lua_next(L_, tab.index()) != 0) { + lua_pop(L_, 1); // Pop the old value. + lua_pushvalue(L_, -1); // Clone the key + lua_pushnil(L_); // Push the new value. + lua_settable(L_, tab.index()); + } +} + void LuaStack::check_nret(int xnret, int otop, int nret) const { int ntop = lua_gettop(L_); if ((nret != xnret)||(ntop != otop + xnret)) { diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index b3edcdab..ab980462 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -392,12 +392,14 @@ public: void newtable(LuaSlot target) const; lua_State *newthread(LuaSlot target) const; - void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const; void getglobaltable(LuaSlot gltab) const; + void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const; + void cleartable(LuaSlot tab) const; int next(LuaSlot tab, LuaSlot key, LuaSlot value) const; void makeclass(LuaSlot tab, LuaSlot name) const; + void getclass(LuaSlot tab, LuaSlot name) const; void makeclass(LuaSlot tab, const char *name) const { push_any_value(name); diff --git a/luprex/core/cpp/table.cpp b/luprex/core/cpp/table.cpp index a1183180..4534afce 100644 --- a/luprex/core/cpp/table.cpp +++ b/luprex/core/cpp/table.cpp @@ -125,16 +125,7 @@ LuaDefine(table_count, "c") { LuaDefine(table_clear, "c") { LuaArg tab; LuaStack LS(L, tab); - - LS.checktable(tab); - lua_pushnil(L); - while (lua_next(L, tab.index()) != 0) { - lua_pop(L, 1); // Pop the old value. - lua_pushvalue(L, -1); // Clone the key - lua_pushnil(L); // Push the new value. - lua_settable(L, tab.index()); - } - + LS.cleartable(tab); return LS.result(); } diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index b6afd556..fae66db9 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -6,9 +6,21 @@ #include "traceback.hpp" #include -Tangible::Tangible(World *w, int64_t id) : world_(w), id_player_pool_(&w->id_global_pool_) { - plane_item_.set_id(id); - w->plane_map_.track(&plane_item_); +void World::store_global_pointer(lua_State *L, World *v) { + lua_pushstring(L, "world"); + lua_pushlightuserdata(L, v); + lua_rawset(L, LUA_REGISTRYINDEX); +} + +World *World::fetch_global_pointer(lua_State *L) { + lua_pushstring(L, "world"); + lua_rawget(L, LUA_REGISTRYINDEX); + World *result = (World *)lua_touserdata(L, -1); + if (result == nullptr) { + luaL_error(L, "No world pointer stored."); + } + lua_pop(L, 1); + return result; } World::~World() { @@ -39,6 +51,11 @@ World::World() { assert (lua_gettop(state()) == 0); } +Tangible::Tangible(World *w, int64_t id) : world_(w), id_player_pool_(&w->id_global_pool_) { + plane_item_.set_id(id); + w->plane_map_.track(&plane_item_); +} + void Tangible::update_plane_item() { util::XYZ xyz = anim_queue_.get_xyz(); std::string plane = anim_queue_.get_plane(); @@ -116,6 +133,33 @@ Tangible *World::tangible_get(lua_State *L, int idx) { return result; } +void World::tangible_delete(lua_State *L, int64_t id) { + LuaVar tangibles, database; + LuaStack LS(L, tangibles, database); + + // Fetch the C++ side of the tangible. + auto iter = tangibles_.find(id); + if (iter == tangibles_.end()) { + luaL_error(L, "Not a tangible: %lld", id); + } + + // Fetch the lua side of the tangible. + LS.rawget(tangibles, LuaRegistry, "tangibles"); + LS.rawget(database, tangibles, id); + assert(LS.istable(database)); + + // Clear out the database. + LS.clearmetatable(database); + LS.cleartable(database); + + // Remove the lua portion from the table. + LS.rawset(tangibles, id, LuaNil); + + // Remove the C++ portion from the table. + tangibles_.erase(iter); + LS.result(); +} + std::vector World::get_near(int64_t player_id, float radius) { Tangible *player = tangible_get(player_id); @@ -159,23 +203,6 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { return t.get(); } -void World::store_global_pointer(lua_State *L, World *v) { - lua_pushstring(L, "world"); - lua_pushlightuserdata(L, v); - lua_rawset(L, LUA_REGISTRYINDEX); -} - -World *World::fetch_global_pointer(lua_State *L) { - lua_pushstring(L, "world"); - lua_rawget(L, LUA_REGISTRYINDEX); - World *result = (World *)lua_touserdata(L, -1); - if (result == nullptr) { - luaL_error(L, "No world pointer stored."); - } - lua_pop(L, 1); - return result; -} - void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { gui->clear(); lua_State *L = state(); @@ -439,6 +466,16 @@ LuaDefine(tangible_plane, "c") { return LS.result(); } +LuaDefine(tangible_graphic, "c") { + LuaArg tanobj; + LuaRet graphic; + LuaStack LS(L, tanobj, graphic); + World *w = World::fetch_global_pointer(L); + Tangible *tan = w->tangible_get(L, tanobj.index()); + LS.set(graphic, tan->anim_queue_.get_graphic()); + return LS.result(); +} + LuaDefine(tangible_animate, "c") { LuaArg tanobj, config; LuaStack LS(L, tanobj, config); @@ -450,6 +487,27 @@ LuaDefine(tangible_animate, "c") { return LS.result(); } +LuaDefine(tangible_setclass, "c") { + LuaArg tanobj, classname; + LuaVar classtab, mt; + LuaStack LS(L, tanobj, classname, classtab, mt); + World *w = World::fetch_global_pointer(L); + w->tangible_get(L, tanobj.index()); + LS.getclass(classtab, classname); + LS.getmetatable(mt, tanobj); + LS.rawset(mt, "__index", classtab); + return LS.result(); +} + +LuaDefine(tangible_delete, "c") { + LuaArg tanobj; + LuaStack LS(L, tanobj); + World *w = World::fetch_global_pointer(L); + Tangible *tan = w->tangible_get(L, tanobj.index()); + w->tangible_delete(L, tan->id()); + return LS.result(); +} + LuaDefine(tangible_make, "c") { World::fetch_global_pointer(L)->tangible_make(L, 0, true); return 1; diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 4315e435..e0ac182a 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -67,6 +67,7 @@ public: // Get the ID // int64_t id() { return plane_item_.id(); } + void be_a_player(); void update_plane_item(); }; @@ -99,6 +100,7 @@ public: StreamBuffer snapshot_; void run_scheduled_threads(int64_t clk); + static void store_global_pointer(lua_State *L, World *w); public: // Constructor. // @@ -149,13 +151,11 @@ public: // a lua error is generated. // Tangible *tangible_get(lua_State *L, int idx); - - // Delete a tangible with the specified ID. - // - // If the tangible doesn't exist, does nothing. - // - void tangible_del(int64_t id); + // Delete the specified tangible. + // + void tangible_delete(lua_State *L, int64_t id); + // Probe the 'interface' function of the specified sprite. // void update_gui(int64_t actor_id, int64_t place_id, Gui *gui); @@ -166,12 +166,11 @@ public: // void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const GuiResult &gres); - // fetch + // fetch_global_pointer // // Given a lua state, fetch the world model associated with // that lua state. // - static void store_global_pointer(lua_State *L, World *w); static World *fetch_global_pointer(lua_State *L); // Serialize and deserialize.