From 1a6366e164b563223e46c9e81bdad0543b14c39e Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Tue, 16 Feb 2021 13:31:34 -0500 Subject: [PATCH] Added invoke_plan, removed viewer --- luprex/core/Makefile | 1 - luprex/core/cpp/gui.cpp | 13 +++--- luprex/core/cpp/gui.hpp | 6 +-- luprex/core/cpp/luasnap.hpp | 30 +++++++------- luprex/core/cpp/textgame.cpp | 22 ++++++----- luprex/core/cpp/textgame.hpp | 7 ++-- luprex/core/cpp/viewer.cpp | 19 --------- luprex/core/cpp/viewer.hpp | 46 --------------------- luprex/core/cpp/world.cpp | 77 ++++++++++++++++++++++++++++++++++-- luprex/core/cpp/world.hpp | 9 +++++ luprex/core/lua/player.lua | 8 ++-- 11 files changed, 128 insertions(+), 110 deletions(-) delete mode 100644 luprex/core/cpp/viewer.cpp delete mode 100644 luprex/core/cpp/viewer.hpp diff --git a/luprex/core/Makefile b/luprex/core/Makefile index c03fa847..b1b28f9e 100644 --- a/luprex/core/Makefile +++ b/luprex/core/Makefile @@ -15,7 +15,6 @@ CPP_FILES=\ cpp/animqueue.cpp\ cpp/source.cpp\ cpp/world.cpp\ - cpp/viewer.cpp\ cpp/textgame.cpp\ cpp/main.cpp diff --git a/luprex/core/cpp/gui.cpp b/luprex/core/cpp/gui.cpp index f8588ff2..44fb88a4 100644 --- a/luprex/core/cpp/gui.cpp +++ b/luprex/core/cpp/gui.cpp @@ -2,10 +2,10 @@ LuaDefineType(Gui); -void Gui::add_menu_item(const std::string &id, const std::string &label) { +void Gui::menu_item(const std::string &action, const std::string &label) { GuiElt elt; elt.type_ = GuiElt::TYPE_MENU_ITEM; - elt.id_ = id; + elt.action_ = action; elt.label_ = label; elts_.push_back(elt); } @@ -18,10 +18,11 @@ LuaDefine(gui_create, "c") { } LuaDefine(gui_menu_item, "c") { - LuaArg lgui, lid; - LuaStack LS(L, lgui, lid); + LuaArg lgui, laction, llabel; + LuaStack LS(L, lgui, laction, llabel); Gui *gui = LS.ckuserdata(lgui); - std::string id = LS.ckstring(lid); - gui->add_menu_item(id, id); + std::string action = LS.ckstring(laction); + std::string label = LS.ckstring(llabel); + gui->menu_item(action, label); return LS.result(); } diff --git a/luprex/core/cpp/gui.hpp b/luprex/core/cpp/gui.hpp index fab78180..1860971c 100644 --- a/luprex/core/cpp/gui.hpp +++ b/luprex/core/cpp/gui.hpp @@ -13,14 +13,14 @@ public: }; private: Type type_; - std::string id_; + std::string action_; std::string label_; GuiElt() {} public: ~GuiElt() {} Type type() const { return type_; } - const std::string &id() const { return id_; } + const std::string &action() const { return action_; } const std::string &label() const { return label_; } }; @@ -32,7 +32,7 @@ private: public: const EltVec &elts() const { return elts_; } void clear() { elts_.clear(); } - void add_menu_item(const std::string &id, const std::string &label); + void menu_item(const std::string &action, const std::string &label); }; #endif // GUI_HPP diff --git a/luprex/core/cpp/luasnap.hpp b/luprex/core/cpp/luasnap.hpp index 1ed28396..fef2028f 100644 --- a/luprex/core/cpp/luasnap.hpp +++ b/luprex/core/cpp/luasnap.hpp @@ -1,24 +1,24 @@ -//////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// // // LUASNAP // -// A lua interpreter that can be checkpointed (snapshotted). -// This makes it possible to roll the entire interpreter back -// to a previously-snapshotted state. +// A lua interpreter that can be checkpointed (snapshotted). This makes it +// possible to roll the entire interpreter back to a previously-snapshotted +// state. // -// To accomplish this, we take advantage of the 'allocf' parameter -// to lua_newstate. This lets us hook the lua allocator, which -// in turn lets us find every block of memory currently in use by -// lua. To snapshot, we 'memcpy' every block of memory -// that lua is using into a buffer. To rollback, we just 'memcpy' -// the data back. +// To accomplish this, we take advantage of the 'allocf' parameter to +// lua_newstate. This lets us hook the lua allocator, which in turn lets us +// find every block of memory currently in use by lua. To snapshot, we 'memcpy' +// every block of memory that lua is using into a buffer. To rollback, we just +// 'memcpy' the data back. // -// The current implementation is a proof-of-concept. It's quite -// wasteful of memory, roughly doubling the amount of RAM that -// LUA uses. But it does demonstrate that this method of snapshot -// and rollback is feasible. +// The current implementation is a proof-of-concept. It's quite wasteful of +// memory, roughly doubling the amount of RAM that LUA uses. It's also not +// super-fast, since it allocates tons of tiny blocks. But it totally +// works, so it demonstrate that this method of snapshot and rollback is +// feasible. // -//////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// #ifndef LUASNAP_HPP #define LUASNAP_HPP diff --git a/luprex/core/cpp/textgame.cpp b/luprex/core/cpp/textgame.cpp index 355d15f5..f7d14e9f 100644 --- a/luprex/core/cpp/textgame.cpp +++ b/luprex/core/cpp/textgame.cpp @@ -9,7 +9,7 @@ #include "luastack.hpp" #include "util.hpp" #include "gui.hpp" -#include "viewer.hpp" +#include "world.hpp" #include "traceback.hpp" #include "textgame.hpp" #include "luaconsole.hpp" @@ -44,7 +44,7 @@ static void l_message(const char *msg) } void TextGame::do_lua(const std::string &exp) { - lua_State *L = viewer_.state(); + lua_State *L = world_->state(); int status = luaL_loadbuffer(L, exp.c_str(), exp.size(), "=stdin"); assert(status == LUA_OK); globalL = L; @@ -81,8 +81,8 @@ void TextGame::do_view_command(const StringVec &cmd) { std::cerr << "v command (view) takes no arguments" << std::endl; return; } - for (int64_t id : viewer_.get_near()) { - const Tangible *tan = viewer_.tangible_get(id); + for (int64_t id : world_->get_near(1, 100)) { + const Tangible *tan = world_->tangible_get(id); const AnimQueue &aq = tan->anim_queue_; std::cerr << id << ": " << aq.get_graphic() << " " << aq.get_plane() << " " << aq.get_xyz() << std::endl; } @@ -98,8 +98,8 @@ void TextGame::do_menu_command(const StringVec &cmd) { std::cerr << "m command (menu) expects a tangible ID or defaults to 1" << std::endl; return; } - gui_id_ = id; - viewer_.update_gui(id, &gui_); + gui_place_ = id; + world_->update_gui(1, id, &gui_); int index = 0; for (const GuiElt &elt : gui_.elts()) { std::cerr << index << " " << elt.label() << std::endl; @@ -120,7 +120,9 @@ void TextGame::do_choose_command(const StringVec &cmd) { std::cerr << "No menu item #" << index << std::endl; return; } - std::cerr << "Choosing menu item: " << elts[index].id() << std::endl; + std::string action = elts[index].action(); + std::cerr << "Invoking plan: " << action << std::endl; + world_->invoke_plan(1, gui_place_, action, &gui_); } void TextGame::do_snapshot_command(const StringVec &cmd) { @@ -128,7 +130,7 @@ void TextGame::do_snapshot_command(const StringVec &cmd) { std::cerr << "s command (snapshot) takes no arguments" << std::endl; return; } - viewer_.snapshot(); + world_->snapshot(); } void TextGame::do_rollback_command(const StringVec &cmd) { @@ -136,7 +138,7 @@ void TextGame::do_rollback_command(const StringVec &cmd) { std::cerr << "r command (rollback) takes no arguments" << std::endl; return; } - viewer_.rollback(); + world_->rollback(); } void TextGame::do_quit_command(const StringVec &cmd) { @@ -161,6 +163,8 @@ void TextGame::do_command(const StringVec &words) { void TextGame::run() { + world_.reset(new World); + world_->init_standalone(); console_.clear(); while (true) { console_.add_stdin(); diff --git a/luprex/core/cpp/textgame.hpp b/luprex/core/cpp/textgame.hpp index 859302f8..bca24258 100644 --- a/luprex/core/cpp/textgame.hpp +++ b/luprex/core/cpp/textgame.hpp @@ -2,16 +2,17 @@ #ifndef TEXTGAME_HPP #define TEXTGAME_HPP -#include "viewer.hpp" #include "luaconsole.hpp" +#include "world.hpp" +#include class TextGame { private: using StringVec = LuaConsole::StringVec; - Viewer viewer_; + std::unique_ptr world_; LuaConsole console_; Gui gui_; - int64_t gui_id_; + int64_t gui_place_; void do_view_command(const StringVec &cmd); void do_menu_command(const StringVec &cmd); diff --git a/luprex/core/cpp/viewer.cpp b/luprex/core/cpp/viewer.cpp deleted file mode 100644 index 0be28186..00000000 --- a/luprex/core/cpp/viewer.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -#include "viewer.hpp" - -Viewer::Viewer() { - world_.reset(new World); - world_->init_standalone(); -} - -Viewer::~Viewer() { -} - -int64_t Viewer::get_player_id() { - return 1; -} - -void Viewer::update_gui(int64_t place, Gui *gui) { - world_->update_gui(get_player_id(), place, gui); -} - diff --git a/luprex/core/cpp/viewer.hpp b/luprex/core/cpp/viewer.hpp deleted file mode 100644 index 85f7c5fa..00000000 --- a/luprex/core/cpp/viewer.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef VIEWER_HPP -#define VIEWER_HPP - -#include "world.hpp" -#include "animqueue.hpp" -#include "gui.hpp" -#include -#include -#include - -class Viewer { -private: - std::unique_ptr world_; - -public: - Viewer(); - ~Viewer(); - - // Snapshot/rollback the lua state (temporary hack) - void snapshot() { world_->lua_snap_.snapshot(); } - void rollback() { world_->lua_snap_.rollback(); } - - // Get the lua state for interaction. - // - lua_State *state() { return world_->state(); } - - // Get the player ID of the current player. - // - int64_t get_player_id(); - - // Get the list of tangibles near the player. - // - std::vector get_near() { return world_->get_near(1, 100); } - - // Get the specified tangible. - // - const Tangible *tangible_get(int64_t id) { return world_->tangible_get(id); } - - // Update the GUI for the specified sprite. - // - // The gui passed in will be overwritten. - // - void update_gui(int64_t id, Gui *g); -}; - -#endif // VIEWER_HPP diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index d2f9812b..4d9543ac 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -140,8 +140,8 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { gui->clear(); lua_State *L = state(); - LuaVar actor, place, ugui, func, tangibles; - LuaStack LS(L, actor, place, ugui, func, tangibles); + LuaVar actor, place, ugui, func, tangibles, mt, index; + LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index); // Get the actor and place. LS.rawget(tangibles, LuaRegistry, "tangibles"); @@ -153,8 +153,17 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { } // Get the interface closure. - // Use of 'gettable' instead of 'rawget' is deliberate. - LS.gettable(func, place, "interface"); + LS.getmetatable(mt, place); + if (!LS.istable(mt)) { + LS.result(); + return; + } + LS.rawget(index, mt, "__index"); + if (!LS.istable(index)) { + LS.result(); + return; + } + LS.rawget(func, index, "interface"); if (!LS.isfunction(func)) { LS.result(); return; @@ -182,7 +191,67 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { // And we're done. LS.result(); } + +void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, Gui *gui) { + lua_State *L = state(); + + LuaVar actor, place, ugui, func, tangibles, mt, index, actions; + LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions); + + // Get the actor and place. + LS.rawget(tangibles, LuaRegistry, "tangibles"); + LS.rawget(actor, tangibles, actor_id); + LS.rawget(place, tangibles, place_id); + if (!LS.istable(actor) || !LS.istable(place)) { + LS.result(); + return; + } + + // Get the action closure. + LS.getmetatable(mt, place); + if (!LS.istable(mt)) { + LS.result(); + return; + } + LS.rawget(index, mt, "__index"); + if (!LS.istable(index)) { + LS.result(); + return; + } + LS.rawget(actions, index, "action"); + if (!LS.istable(actions)) { + LS.result(); + return; + } + LS.rawget(func, actions, action); + if (!LS.isfunction(func)) { + LS.result(); + return; + } + + // Construct the userdata with the GUI pointer. + LS.newpointer(ugui, gui, false); + + // Call the action function. + lua_pushvalue(L, func.index()); + lua_pushvalue(L, actor.index()); + lua_pushvalue(L, place.index()); + lua_pushvalue(L, ugui.index()); + int status = traceback_pcall(L, 3, 0); + if (status != 0) { + gui->clear(); + std::cerr << lua_tostring(L, -1); + LS.result(); + return; + } + // Nuke the userdata, in case somebody saved a pointer to it. + LS.clearuserdata(ugui); + + // And we're done. + LS.result(); +} + LuaDefine(tangible_get, "c") { LuaArg id; LuaRet database; diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 33f845fe..eb6bee96 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -112,12 +112,21 @@ public: // void update_gui(int64_t actor_id, int64_t place_id, Gui *gui); + // Invoke an action plan. + // + void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, Gui *gui); + // fetch // // Given a lua state, fetch the world model associated with // that lua state. // static World *fetch(lua_State *L); + + // Snapshot and rollback - temporary. + // + void snapshot() { lua_snap_.snapshot(); } + void rollback() { lua_snap_.rollback(); } }; #endif // WORLD_HPP diff --git a/luprex/core/lua/player.lua b/luprex/core/lua/player.lua index ebbd4881..b5d8a044 100644 --- a/luprex/core/lua/player.lua +++ b/luprex/core/lua/player.lua @@ -1,10 +1,10 @@ maketangible('player') function player.interface(actor, place, gui) - gui:menu_item("North") - gui:menu_item("South") - gui:menu_item("East") - gui:menu_item("West") + gui:menu_item("north", "Go North") + gui:menu_item("south", "Go South") + gui:menu_item("east", "Go East") + gui:menu_item("west", "Go West") end function player.action.north(actor, place, gui)