Create a coroutine to run plans
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
// 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 {
|
||||
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_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) {
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
19
luprex/core/cpp/viewer.cpp
Normal file
19
luprex/core/cpp/viewer.cpp
Normal 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);
|
||||
}
|
||||
|
||||
46
luprex/core/cpp/viewer.hpp
Normal file
46
luprex/core/cpp/viewer.hpp
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -21,4 +21,6 @@ end
|
||||
|
||||
function player.action.west(actor, place, gui)
|
||||
print("Moving west")
|
||||
t = nil
|
||||
t[3] = 5
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user