|
|
|
|
@@ -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;
|
|
|
|
|
// Spawn the thread and run it.
|
|
|
|
|
int nargs = 0;
|
|
|
|
|
spawn(LS, actor_id, place_id, func, false, nargs, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
spawn(LS, actor_id, place_id, func, true, nargs, false);
|
|
|
|
|
}
|
|
|
|
|
LS.rawset(threads, tid, thinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
|
}
|
|
|
|
|
|