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

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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -2,16 +2,17 @@
#ifndef TEXTGAME_HPP
#define TEXTGAME_HPP
#include "viewer.hpp"
#include "luaconsole.hpp"
#include "world.hpp"
#include <memory>
class TextGame {
private:
using StringVec = LuaConsole::StringVec;
Viewer viewer_;
std::unique_ptr<World> 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);

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();
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<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") {
LuaArg id;
LuaRet database;

View File

@@ -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