Added invoke_plan, removed viewer

This commit is contained in:
2021-02-16 13:31:34 -05:00
parent eefe1bd58a
commit 1a6366e164
11 changed files with 128 additions and 110 deletions

View File

@@ -15,7 +15,6 @@ CPP_FILES=\
cpp/animqueue.cpp\ cpp/animqueue.cpp\
cpp/source.cpp\ cpp/source.cpp\
cpp/world.cpp\ cpp/world.cpp\
cpp/viewer.cpp\
cpp/textgame.cpp\ cpp/textgame.cpp\
cpp/main.cpp cpp/main.cpp

View File

@@ -2,10 +2,10 @@
LuaDefineType(Gui); 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; GuiElt elt;
elt.type_ = GuiElt::TYPE_MENU_ITEM; elt.type_ = GuiElt::TYPE_MENU_ITEM;
elt.id_ = id; elt.action_ = action;
elt.label_ = label; elt.label_ = label;
elts_.push_back(elt); elts_.push_back(elt);
} }
@@ -18,10 +18,11 @@ LuaDefine(gui_create, "c") {
} }
LuaDefine(gui_menu_item, "c") { LuaDefine(gui_menu_item, "c") {
LuaArg lgui, lid; LuaArg lgui, laction, llabel;
LuaStack LS(L, lgui, lid); LuaStack LS(L, lgui, laction, llabel);
Gui *gui = LS.ckuserdata<Gui>(lgui); Gui *gui = LS.ckuserdata<Gui>(lgui);
std::string id = LS.ckstring(lid); std::string action = LS.ckstring(laction);
gui->add_menu_item(id, id); std::string label = LS.ckstring(llabel);
gui->menu_item(action, label);
return LS.result(); return LS.result();
} }

View File

@@ -13,14 +13,14 @@ public:
}; };
private: private:
Type type_; Type type_;
std::string id_; std::string action_;
std::string label_; std::string label_;
GuiElt() {} GuiElt() {}
public: public:
~GuiElt() {} ~GuiElt() {}
Type type() const { return type_; } 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_; } const std::string &label() const { return label_; }
}; };
@@ -32,7 +32,7 @@ private:
public: public:
const EltVec &elts() const { return elts_; } const EltVec &elts() const { return elts_; }
void clear() { elts_.clear(); } 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 #endif // GUI_HPP

View File

@@ -1,24 +1,24 @@
//////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// LUASNAP // LUASNAP
// //
// A lua interpreter that can be checkpointed (snapshotted). // A lua interpreter that can be checkpointed (snapshotted). This makes it
// This makes it possible to roll the entire interpreter back // possible to roll the entire interpreter back to a previously-snapshotted
// to a previously-snapshotted state. // state.
// //
// To accomplish this, we take advantage of the 'allocf' parameter // To accomplish this, we take advantage of the 'allocf' parameter to
// to lua_newstate. This lets us hook the lua allocator, which // lua_newstate. This lets us hook the lua allocator, which in turn lets us
// in turn lets us find every block of memory currently in use by // find every block of memory currently in use by lua. To snapshot, we 'memcpy'
// lua. To snapshot, we 'memcpy' every block of memory // every block of memory that lua is using into a buffer. To rollback, we just
// that lua is using into a buffer. To rollback, we just 'memcpy' // 'memcpy' the data back.
// the data back.
// //
// The current implementation is a proof-of-concept. It's quite // The current implementation is a proof-of-concept. It's quite wasteful of
// wasteful of memory, roughly doubling the amount of RAM that // memory, roughly doubling the amount of RAM that LUA uses. It's also not
// LUA uses. But it does demonstrate that this method of snapshot // super-fast, since it allocates tons of tiny blocks. But it totally
// and rollback is feasible. // works, so it demonstrate that this method of snapshot and rollback is
// feasible.
// //
//////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef LUASNAP_HPP #ifndef LUASNAP_HPP
#define LUASNAP_HPP #define LUASNAP_HPP

View File

@@ -9,7 +9,7 @@
#include "luastack.hpp" #include "luastack.hpp"
#include "util.hpp" #include "util.hpp"
#include "gui.hpp" #include "gui.hpp"
#include "viewer.hpp" #include "world.hpp"
#include "traceback.hpp" #include "traceback.hpp"
#include "textgame.hpp" #include "textgame.hpp"
#include "luaconsole.hpp" #include "luaconsole.hpp"
@@ -44,7 +44,7 @@ static void l_message(const char *msg)
} }
void TextGame::do_lua(const std::string &exp) { 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"); int status = luaL_loadbuffer(L, exp.c_str(), exp.size(), "=stdin");
assert(status == LUA_OK); assert(status == LUA_OK);
globalL = L; globalL = L;
@@ -81,8 +81,8 @@ void TextGame::do_view_command(const StringVec &cmd) {
std::cerr << "v command (view) takes no arguments" << std::endl; std::cerr << "v command (view) takes no arguments" << std::endl;
return; return;
} }
for (int64_t id : viewer_.get_near()) { for (int64_t id : world_->get_near(1, 100)) {
const Tangible *tan = viewer_.tangible_get(id); const Tangible *tan = world_->tangible_get(id);
const AnimQueue &aq = tan->anim_queue_; const AnimQueue &aq = tan->anim_queue_;
std::cerr << id << ": " << aq.get_graphic() << " " << aq.get_plane() << " " << aq.get_xyz() << std::endl; 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; std::cerr << "m command (menu) expects a tangible ID or defaults to 1" << std::endl;
return; return;
} }
gui_id_ = id; gui_place_ = id;
viewer_.update_gui(id, &gui_); world_->update_gui(1, id, &gui_);
int index = 0; int index = 0;
for (const GuiElt &elt : gui_.elts()) { for (const GuiElt &elt : gui_.elts()) {
std::cerr << index << " " << elt.label() << std::endl; 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; std::cerr << "No menu item #" << index << std::endl;
return; 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) { 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; std::cerr << "s command (snapshot) takes no arguments" << std::endl;
return; return;
} }
viewer_.snapshot(); world_->snapshot();
} }
void TextGame::do_rollback_command(const StringVec &cmd) { 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; std::cerr << "r command (rollback) takes no arguments" << std::endl;
return; return;
} }
viewer_.rollback(); world_->rollback();
} }
void TextGame::do_quit_command(const StringVec &cmd) { void TextGame::do_quit_command(const StringVec &cmd) {
@@ -161,6 +163,8 @@ void TextGame::do_command(const StringVec &words) {
void TextGame::run() void TextGame::run()
{ {
world_.reset(new World);
world_->init_standalone();
console_.clear(); console_.clear();
while (true) { while (true) {
console_.add_stdin(); console_.add_stdin();

View File

@@ -2,16 +2,17 @@
#ifndef TEXTGAME_HPP #ifndef TEXTGAME_HPP
#define TEXTGAME_HPP #define TEXTGAME_HPP
#include "viewer.hpp"
#include "luaconsole.hpp" #include "luaconsole.hpp"
#include "world.hpp"
#include <memory>
class TextGame { class TextGame {
private: private:
using StringVec = LuaConsole::StringVec; using StringVec = LuaConsole::StringVec;
Viewer viewer_; std::unique_ptr<World> world_;
LuaConsole console_; LuaConsole console_;
Gui gui_; Gui gui_;
int64_t gui_id_; int64_t gui_place_;
void do_view_command(const StringVec &cmd); void do_view_command(const StringVec &cmd);
void do_menu_command(const StringVec &cmd); void do_menu_command(const StringVec &cmd);

View File

@@ -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);
}

View File

@@ -1,46 +0,0 @@
#ifndef VIEWER_HPP
#define VIEWER_HPP
#include "world.hpp"
#include "animqueue.hpp"
#include "gui.hpp"
#include <vector>
#include <string>
#include <memory>
class Viewer {
private:
std::unique_ptr<World> 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<int64_t> 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

View File

@@ -140,8 +140,8 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
gui->clear(); gui->clear();
lua_State *L = state(); lua_State *L = state();
LuaVar actor, place, ugui, func, tangibles; LuaVar actor, place, ugui, func, tangibles, mt, index;
LuaStack LS(L, actor, place, ugui, func, tangibles); LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index);
// Get the actor and place. // Get the actor and place.
LS.rawget(tangibles, LuaRegistry, "tangibles"); 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. // Get the interface closure.
// Use of 'gettable' instead of 'rawget' is deliberate. LS.getmetatable(mt, place);
LS.gettable(func, place, "interface"); 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)) { if (!LS.isfunction(func)) {
LS.result(); LS.result();
return; return;
@@ -183,6 +192,66 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
LS.result(); 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<Gui>(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") { LuaDefine(tangible_get, "c") {
LuaArg id; LuaArg id;
LuaRet database; LuaRet database;

View File

@@ -112,12 +112,21 @@ public:
// //
void update_gui(int64_t actor_id, int64_t place_id, Gui *gui); 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 // fetch
// //
// Given a lua state, fetch the world model associated with // Given a lua state, fetch the world model associated with
// that lua state. // that lua state.
// //
static World *fetch(lua_State *L); static World *fetch(lua_State *L);
// Snapshot and rollback - temporary.
//
void snapshot() { lua_snap_.snapshot(); }
void rollback() { lua_snap_.rollback(); }
}; };
#endif // WORLD_HPP #endif // WORLD_HPP

View File

@@ -1,10 +1,10 @@
maketangible('player') maketangible('player')
function player.interface(actor, place, gui) function player.interface(actor, place, gui)
gui:menu_item("North") gui:menu_item("north", "Go North")
gui:menu_item("South") gui:menu_item("south", "Go South")
gui:menu_item("East") gui:menu_item("east", "Go East")
gui:menu_item("West") gui:menu_item("west", "Go West")
end end
function player.action.north(actor, place, gui) function player.action.north(actor, place, gui)