Refactor code in world-core that spawns threads

This commit is contained in:
2024-02-27 17:01:26 -05:00
parent aaedf9e3f0
commit 2b426eefeb
6 changed files with 112 additions and 111 deletions

View File

@@ -87,6 +87,7 @@ public:
}
void do_choose_command(const StringVec &cmd) {
stdostream() << "Chose menu item: " << cmd[1] << std::endl;
eng::string action = gui_.get_action(sv::to_int64(cmd[1]));
if (action == "") {
stdostream() << "Invalid menu item #" << std::endl;

View File

@@ -54,9 +54,10 @@ void LuaConsole::simplify(const StringVec &words) {
return;
} else if (sv::valid_int64(words[0])) {
if (words.size() == 1) {
eng::string num = words[0];
words_.clear();
words_.push_back("choose");
words_.push_back(words[0]);
words_.push_back(num);
} else {
synerr("/choose command takes no arguments");
}

View File

@@ -664,6 +664,8 @@ public:
template<class... SS>
LuaExtStack(const LuaCoreStack &LS0, SS & ... stackslots) : LuaCoreStack(LS0.state(), stackslots...) {}
int oldtop() const { return oldtop_; }
~LuaExtStack() {
if (!lua_isthrowing(L_)) {
lua_settop(L_, oldtop_);

View File

@@ -594,6 +594,90 @@ void World::invoke(const Invocation &inv) {
}
}
bool World::spawn(LuaCoreStack &LS0, int64_t actor_id, int64_t place_id, LuaSlot func,
bool passactorplace, int nargs, bool print) {
lua_State *L = LS0.state();
LuaVar actor, place, mt, index, tangibles, thread, threads, thinfo;
LuaExtStack LS(L, actor, place, mt, index, tangibles, thread, threads, thinfo);
// Get the actor and place, C++ version. Make sure both exist.
Tangible *tactor = tangible_get(actor_id);
Tangible *tplace = tangible_get(place_id);
if ((tactor == nullptr) || (tplace == nullptr)) {
return false;
}
// Get the actor and place, lua version. Make sure both exist.
LS.rawget(tangibles, LuaRegistry, "tangibles");
LS.rawget(actor, tangibles, actor_id);
LS.rawget(place, tangibles, place_id);
if (!LS.istable(actor) || !LS.istable(place)) {
return false;
}
// Get an ID for the thread.
// We currently always use the actor pool. We may extend
// this to allow the use of the place pool.
int64_t tid = tactor->id_player_pool_.get_one();
// Get the place's metatable.
LS.getmetatable(mt, place);
if (!LS.istable(mt)) {
return false;
}
// If the function is a string, look it up in the place's class.
if (LS.isstring(func)) {
LS.rawget(index, mt, "__index");
if (!LS.istable(index)) {
return false;
}
LS.rawget(func, index, func);
}
// Make sure the function is a function.
if (!LS.isfunction(func)) {
return false;
}
// Create a new thread. Push function, and maybe actor and place.
lua_State *CO = LS.newthread(thread);
lua_pushvalue(L, func.index());
if (passactorplace) {
lua_pushvalue(L, actor.index());
lua_pushvalue(L, place.index());
}
lua_xmove(L, CO, passactorplace ? 3:1);
// Push any extra arguments. Extra arguments were pushed onto
// the lua stack before calling spawn, so they are located at oldtop.
if (nargs > 0) {
int base = LS.oldtop() - nargs + 1;
for (int i = 0; i < nargs; i++) {
lua_pushvalue(L, base + i);
}
lua_xmove(L, CO, nargs);
}
// Create the thread info table.
LS.newtable(thinfo);
LS.rawset(thinfo, "thread", thread);
LS.rawset(thinfo, "actorid", actor_id);
LS.rawset(thinfo, "isnew", true);
LS.rawset(thinfo, "useppool", true);
LS.rawset(thinfo, "print", print);
// Store the thread into place's thread table.
LS.rawget(threads, mt, "threads");
if (!LS.istable(threads)) {
return false;
}
LS.rawset(threads, tid, thinfo);
schedule(0, tid, place_id);
return true;
}
void World::invoke_flush_prints(int64_t actor_id, int64_t place_id, std::string_view datapack) {
assert(stack_is_clear());
// Check argument sanity.
@@ -614,22 +698,10 @@ void World::invoke_flush_prints(int64_t actor_id, int64_t place_id, std::string_
void World::invoke_lua(int64_t actor_id, int64_t place_id, std::string_view datapack) {
assert(stack_is_clear());
// Make sure that actor and place exist and are not stubs.
Tangible *tactor = tangible_get(actor_id);
Tangible *tplace = tangible_get(place_id);
if ((tactor == nullptr) || (tplace == nullptr)) {
return;
}
// Get a thread ID for the new thread.
int64_t tid = tplace->id_player_pool_.get_one();
// Set up for lua manipulation.
{
lua_State *L = state();
LuaVar func, tangibles, place, mt, thread, thinfo, threads;
LuaExtStack LS(L, func, tangibles, place, mt, thread, thinfo, threads);
LuaVar func;
LuaExtStack LS(L, func);
// create the compiled closure.
int status = luaL_loadbuffer(L, datapack.data(), datapack.size(), "=invoke");
@@ -641,41 +713,10 @@ void World::invoke_lua(int64_t actor_id, int64_t place_id, std::string_view data
return;
}
// Get the place.
LS.rawget(tangibles, LuaRegistry, "tangibles");
LS.rawget(place, tangibles, place_id);
if (!LS.istable(place)) {
return;
}
// Get the place's metatable.
LS.getmetatable(mt, place);
if (!LS.istable(mt)) {
return;
}
// Create a new thread, set up function and parameters.
lua_State *CO = LS.newthread(thread);
lua_pushvalue(L, func.index());
lua_xmove(L, CO, 1);
// Create the thread info table.
LS.newtable(thinfo);
LS.rawset(thinfo, "thread", thread);
LS.rawset(thinfo, "actorid", actor_id);
LS.rawset(thinfo, "isnew", true);
LS.rawset(thinfo, "useppool", true);
LS.rawset(thinfo, "print", true);
// Store the thread into place's thread table.
LS.rawget(threads, mt, "threads");
if (!LS.istable(threads)) {
return;
}
LS.rawset(threads, tid, thinfo);
// Spawn the thread and run it.
int nargs = 0;
spawn(LS, actor_id, place_id, func, false, nargs, true);
}
schedule(0, tid, place_id);
run_scheduled_threads();
assert(stack_is_clear());
}
@@ -694,77 +735,23 @@ void World::invoke_choose(int64_t actor_id, int64_t place_id, std::string_view d
if (!sv::has_prefix(datapack, "cb_")) {
return;
}
// Get the actor and place. Make sure both exist.
Tangible *tactor = tangible_get(actor_id);
Tangible *tplace = tangible_get(place_id);
if ((tactor == nullptr) || (tplace == nullptr)) {
return;
}
// Get an ID for the thread. We always use the player
// pool in this case.
int64_t tid = tactor->id_player_pool_.get_one();
{
// Set up for Lua manipulation.
lua_State *L = state();
LuaVar actor, place, func, tangibles, mt, index, thread, threads, thinfo, message, invdata;
LuaExtStack LS(L, actor, place, func, tangibles, mt, index, thread, threads, thinfo, message, invdata);
LuaVar func, invdata;
LuaExtStack LS(L, func, invdata);
// 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)) {
return;
}
// Get the action closure.
LS.getmetatable(mt, place);
if (!LS.istable(mt)) {
return;
}
LS.rawget(index, mt, "__index");
if (!LS.istable(index)) {
return;
}
LS.rawget(func, index, datapack);
if (!LS.isfunction(func)) {
return;
}
LS.set(func, datapack);
// TODO: maybe add the ability to pass data in as a table?
// We're planning to add the ability to pass data in as a table.
// For now the table is always empty.
LS.newtable(invdata);
// 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());
// Spawn the thread and run it.
int nargs = 1;
lua_pushvalue(L, invdata.index());
lua_xmove(L, CO, 4);
// Create the thread info table.
LS.newtable(thinfo);
LS.rawset(thinfo, "thread", thread);
LS.rawset(thinfo, "actorid", actor_id);
LS.rawset(thinfo, "isnew", true);
LS.rawset(thinfo, "useppool", true);
LS.rawset(thinfo, "print", false);
// Store the thread into place's thread table.
LS.rawget(threads, mt, "threads");
if (!LS.istable(threads)) {
return;
}
LS.rawset(threads, tid, thinfo);
spawn(LS, actor_id, place_id, func, true, nargs, false);
}
// Push the thread's ID into the runnable thread queue,
// then run the thread queue.
schedule(0, tid, place_id);
run_scheduled_threads();
assert(stack_is_clear());
}

View File

@@ -372,7 +372,11 @@ private:
// Invoke the lua_source operation.
//
void invoke_lua_source(int64_t actor_id, int64_t place_id, std::string_view datapack);
// Low level spawn thread function.
//
bool spawn(LuaCoreStack &LS0, int64_t actor_id, int64_t place_id, LuaSlot func, bool passactorplace, int nargs, bool print);
public:
////////////////////////////////////////////////////////////////////////////
//