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_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 {
|
void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
|
||||||
checkstring(classname);
|
checkstring(classname);
|
||||||
|
|
||||||
|
|||||||
@@ -425,6 +425,7 @@ public:
|
|||||||
void checknometa(LuaSlot index) const;
|
void checknometa(LuaSlot index) const;
|
||||||
|
|
||||||
void newtable(LuaSlot target) const;
|
void newtable(LuaSlot target) const;
|
||||||
|
lua_State *newthread(LuaSlot target) const;
|
||||||
|
|
||||||
void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const;
|
void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const;
|
||||||
|
|
||||||
|
|||||||
@@ -4,26 +4,26 @@
|
|||||||
#define TRACEBACK_LEVELS2 10
|
#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);
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
// Convert message to a string and push the string.
|
// Convert message to a string
|
||||||
if (lua_tostring(L, msgindex)) {
|
if (!lua_tostring(L, top)) {
|
||||||
lua_pushvalue(L, msgindex);
|
luaL_callmeta(L, top, "__tostring");
|
||||||
} else {
|
// If callmeta didn't produce exactly one string, clear the stack
|
||||||
luaL_callmeta(L, msgindex, "__tostring");
|
// and push "unknown error"
|
||||||
}
|
if ((lua_gettop(L) == top + 1) && (lua_tostring(L, -1))) {
|
||||||
|
lua_remove(L, top);
|
||||||
// If we didn't end up with exactly one string on
|
} else {
|
||||||
// the stack, then clear the stack and push 'unknown error'.
|
lua_settop(L, top - 1);
|
||||||
if ((lua_gettop(L) != top + 1) || (!lua_tostring(L, -1))) {
|
lua_pushstring(L, "unknown error");
|
||||||
lua_settop(L, top);
|
}
|
||||||
lua_pushstring(L, "unknown error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the traceback.
|
// Append the traceback.
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
int level = 1;
|
int level = baselevel;
|
||||||
int firstpart = 1;
|
int firstpart = 1;
|
||||||
while (lua_getstack(L1, level++, &ar)) {
|
while (lua_getstack(L1, level++, &ar)) {
|
||||||
if (level > TRACEBACK_LEVELS1 && firstpart) {
|
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>",
|
lua_pushfstring(L, " in function <%s:%d>",
|
||||||
ar.short_src, ar.linedefined);
|
ar.short_src, ar.linedefined);
|
||||||
}
|
}
|
||||||
if (lua_gettop(L) - top > 5) {
|
if (1 + lua_gettop(L) - top > 5) {
|
||||||
lua_concat(L, lua_gettop(L) - top);
|
lua_concat(L, 1 + lua_gettop(L) - top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pushstring(L, "\n");
|
lua_pushstring(L, "\n");
|
||||||
if (lua_gettop(L) - top > 1) {
|
if (1 + lua_gettop(L) - top > 1) {
|
||||||
lua_concat(L, lua_gettop(L) - top);
|
lua_concat(L, 1 + lua_gettop(L) - top);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int traceback_handler(lua_State *L) {
|
||||||
|
traceback_general(L, L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(traceback_handler, "c") {
|
void traceback_coroutine(lua_State *L, lua_State *CO) {
|
||||||
return traceback_general(L, L, lua_gettop(L));
|
lua_xmove(CO, L, 1);
|
||||||
}
|
traceback_general(L, CO, 0);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int traceback_pcall(lua_State *L, int narg, int nret) {
|
int traceback_pcall(lua_State *L, int narg, int nret) {
|
||||||
|
|||||||
@@ -15,17 +15,10 @@
|
|||||||
|
|
||||||
// traceback_coroutine
|
// traceback_coroutine
|
||||||
//
|
//
|
||||||
// Given a coroutine and an error message, returns a traceback
|
// Given a coroutine which contains an error message, pop the error
|
||||||
// of the coroutine.
|
// message from the coroutine, and push a traceback onto L.
|
||||||
//
|
//
|
||||||
int traceback_coroutine(lua_State *L);
|
void traceback_coroutine(lua_State *L, lua_State *CO);
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// traceback_pcall
|
// 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, "inventory", LuaNewTable);
|
||||||
LS.rawset(database, "id", id);
|
LS.rawset(database, "id", id);
|
||||||
LS.rawset(metatab, "id", id);
|
LS.rawset(metatab, "id", id);
|
||||||
|
LS.rawset(metatab, "threads", LuaNewTable);
|
||||||
// LS.rawset(metatab, "__metatable", LuaNil);
|
// LS.rawset(metatab, "__metatable", LuaNil);
|
||||||
|
|
||||||
LS.result();
|
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();
|
lua_State *L = state();
|
||||||
|
|
||||||
LuaVar 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);
|
LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions, thread, message);
|
||||||
|
|
||||||
// Get the actor and place.
|
// Get the actor and place.
|
||||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
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.
|
// Construct the userdata with the GUI pointer.
|
||||||
LS.newpointer<Gui>(ugui, gui, false);
|
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, func.index());
|
||||||
lua_pushvalue(L, actor.index());
|
lua_pushvalue(L, actor.index());
|
||||||
lua_pushvalue(L, place.index());
|
lua_pushvalue(L, place.index());
|
||||||
lua_pushvalue(L, ugui.index());
|
lua_pushvalue(L, ugui.index());
|
||||||
int status = traceback_pcall(L, 3, 0);
|
lua_xmove(L, CO, 4);
|
||||||
if (status != 0) {
|
|
||||||
gui->clear();
|
// 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);
|
std::cerr << lua_tostring(L, -1);
|
||||||
LS.result();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nuke the userdata, in case somebody saved a pointer to it.
|
// Nuke the userdata, in case somebody saved a pointer to it.
|
||||||
|
|||||||
@@ -21,4 +21,6 @@ end
|
|||||||
|
|
||||||
function player.action.west(actor, place, gui)
|
function player.action.west(actor, place, gui)
|
||||||
print("Moving west")
|
print("Moving west")
|
||||||
|
t = nil
|
||||||
|
t[3] = 5
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user