Create a coroutine to run plans

This commit is contained in:
2021-02-17 13:38:22 -05:00
parent 210644da57
commit 213bf12425
8 changed files with 122 additions and 45 deletions

View File

@@ -194,6 +194,12 @@ void LuaStack::newtable(LuaSlot target) const {
lua_replace(L_, target);
}
lua_State *LuaStack::newthread(LuaSlot target) const {
lua_State *result = lua_newthread(L_);
lua_replace(L_, target);
return result;
}
void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
checkstring(classname);

View File

@@ -425,6 +425,7 @@ public:
void checknometa(LuaSlot index) const;
void newtable(LuaSlot target) const;
lua_State *newthread(LuaSlot target) const;
void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const;

View File

@@ -4,26 +4,26 @@
#define TRACEBACK_LEVELS2 10
static int traceback_general(lua_State *L, lua_State *L1, int msgindex) {
// Call this with the error message on top of the stack.
static void traceback_general(lua_State *L, lua_State *L1, int baselevel) {
int top = lua_gettop(L);
// Convert message to a string and push the string.
if (lua_tostring(L, msgindex)) {
lua_pushvalue(L, msgindex);
} else {
luaL_callmeta(L, msgindex, "__tostring");
}
// If we didn't end up with exactly one string on
// the stack, then clear the stack and push 'unknown error'.
if ((lua_gettop(L) != top + 1) || (!lua_tostring(L, -1))) {
lua_settop(L, top);
lua_pushstring(L, "unknown error");
// Convert message to a string
if (!lua_tostring(L, top)) {
luaL_callmeta(L, top, "__tostring");
// If callmeta didn't produce exactly one string, clear the stack
// and push "unknown error"
if ((lua_gettop(L) == top + 1) && (lua_tostring(L, -1))) {
lua_remove(L, top);
} else {
lua_settop(L, top - 1);
lua_pushstring(L, "unknown error");
}
}
// Append the traceback.
lua_Debug ar;
int level = 1;
int level = baselevel;
int firstpart = 1;
while (lua_getstack(L1, level++, &ar)) {
if (level > TRACEBACK_LEVELS1 && firstpart) {
@@ -55,27 +55,25 @@ static int traceback_general(lua_State *L, lua_State *L1, int msgindex) {
lua_pushfstring(L, " in function <%s:%d>",
ar.short_src, ar.linedefined);
}
if (lua_gettop(L) - top > 5) {
lua_concat(L, lua_gettop(L) - top);
if (1 + lua_gettop(L) - top > 5) {
lua_concat(L, 1 + lua_gettop(L) - top);
}
}
}
lua_pushstring(L, "\n");
if (lua_gettop(L) - top > 1) {
lua_concat(L, lua_gettop(L) - top);
if (1 + lua_gettop(L) - top > 1) {
lua_concat(L, 1 + lua_gettop(L) - top);
}
}
int traceback_handler(lua_State *L) {
traceback_general(L, L, 1);
return 1;
}
LuaDefine(traceback_handler, "c") {
return traceback_general(L, L, lua_gettop(L));
}
LuaDefine(traceback_coroutine, "c") {
LuaArg thread, message;
LuaStack LS(L, thread, message);
lua_State *L1 = LS.ckthread(thread);
return traceback_general(L, L1, message.index());
void traceback_coroutine(lua_State *L, lua_State *CO) {
lua_xmove(CO, L, 1);
traceback_general(L, CO, 0);
}
int traceback_pcall(lua_State *L, int narg, int nret) {

View File

@@ -15,17 +15,10 @@
// traceback_coroutine
//
// Given a coroutine and an error message, returns a traceback
// of the coroutine.
// Given a coroutine which contains an error message, pop the error
// message from the coroutine, and push a traceback onto L.
//
int traceback_coroutine(lua_State *L);
// traceback_handler
//
// The function 'pcall' expects you to pass in a message handler routine.
// 'traceback_handler' is designed to be used as this argument to pcall.
//
int traceback_handler(lua_State *L);
void traceback_coroutine(lua_State *L, lua_State *CO);
// traceback_pcall
//

View File

@@ -0,0 +1,19 @@
#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

@@ -0,0 +1,46 @@
#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

@@ -120,6 +120,7 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
LS.rawset(database, "inventory", LuaNewTable);
LS.rawset(database, "id", id);
LS.rawset(metatab, "id", id);
LS.rawset(metatab, "threads", LuaNewTable);
// LS.rawset(metatab, "__metatable", LuaNil);
LS.result();
@@ -202,8 +203,8 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
lua_State *L = state();
LuaVar actor, place, ugui, func, tangibles, mt, index, actions;
LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions);
LuaVar actor, place, ugui, func, tangibles, mt, index, actions, thread, message;
LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions, thread, message);
// Get the actor and place.
LS.rawget(tangibles, LuaRegistry, "tangibles");
@@ -239,17 +240,28 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
// Construct the userdata with the GUI pointer.
LS.newpointer<Gui>(ugui, gui, false);
// Call the action function.
// Create a new thread, set up function and parameters.
lua_State *CO = LS.newthread(thread);
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();
lua_xmove(L, CO, 4);
// Resume the new coroutine.
int status = lua_resume(CO, 3);
// Three possible outcomes: finished, yielded, or errored.
if (status == LUA_YIELD) {
// Yield not implemented yet. The coroutine is simply dropped.
std::cerr << "Thread yield not implemented yet." << std::endl;
} else if (status == 0) {
// Successfully ran to completion.
std::cerr << "Thread ran to completion." << std::endl;
} else {
// Transfer the error message from CO to L, and add a traceback.
traceback_coroutine(L, CO);
std::cerr << lua_tostring(L, -1);
LS.result();
return;
}
// Nuke the userdata, in case somebody saved a pointer to it.

View File

@@ -21,4 +21,6 @@ end
function player.action.west(actor, place, gui)
print("Moving west")
t = nil
t[3] = 5
end