Implemented World::probe_lua_call and tested

This commit is contained in:
2024-09-01 19:43:00 -04:00
parent d4f46eef45
commit 47a570064c
9 changed files with 196 additions and 47 deletions

View File

@@ -9,6 +9,68 @@
#include <iostream>
// Read a SimpleDynamic value from the streambuffer and push
// it onto the lua stack.
void push_simple_dynamic(lua_State *L, StreamBuffer *sb) {
SimpleDynamicTag type = sb->read_simple_dynamic_tag();
switch (type) {
case SimpleDynamicTag::NUMBER: {
lua_pushnumber(L, sb->read_double());
break;
}
case SimpleDynamicTag::BOOLEAN: {
lua_pushboolean(L, sb->read_bool() ? 1:0);
break;
}
case SimpleDynamicTag::STRING: {
std::string_view s = sb->read_string_view();
lua_pushlstring(L, s.data(), s.size());
break;
}
case SimpleDynamicTag::VECTOR: {
double x = sb->read_double();
double y = sb->read_double();
double z = sb->read_double();
lua_newtable(L);
lua_pushnumber(L, x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, y);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, z);
lua_rawseti(L, -2, 3);
break;
}
default: throw StreamCorruption();
}
}
// Given a lua value, try to pack it into the stream buffer as a simple dynamic.
bool encode_simple_dynamic(LuaCoreStack &LS, LuaSlot &slot, StreamBuffer *sb) {
switch (LS.type(slot)) {
case LUA_TNUMBER:
sb->write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
sb->write_double(LS.cknumber(slot));
return true;
case LUA_TSTRING:
sb->write_simple_dynamic_tag(SimpleDynamicTag::STRING);
sb->write_string(LS.ckstringview(slot));
return true;
case LUA_TBOOLEAN:
sb->write_simple_dynamic_tag(SimpleDynamicTag::BOOLEAN);
sb->write_bool(LS.ckboolean(slot));
return true;
case LUA_TTABLE: {
std::optional<util::DXYZ> xyz = LS.tryxyz(slot);
if (!xyz.has_value()) return false;
sb->write_simple_dynamic_tag(SimpleDynamicTag::VECTOR);
sb->write_dxyz(xyz.value());
return true;
}
default: return false;
}
}
void World::store_global_pointer(lua_State *L, World *v) {
lua_pushstring(L, "world");
lua_pushlightuserdata(L, v);
@@ -292,7 +354,7 @@ void World::disconnected(int64_t actor_id) {
}
}
eng::string World::probe_lua(int64_t actor_id, std::string_view lua) {
eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
assert(stack_is_clear());
lua_State *L = state();
@@ -343,6 +405,93 @@ eng::string World::probe_lua(int64_t actor_id, std::string_view lua) {
return result;
}
void World::probe_lua_call(int64_t place_id, int64_t actor_id, std::string_view datapack, StreamBuffer *retvals) {
assert(stack_is_clear());
lua_State *L = state();
// 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;
}
// Use a streambuffer to parse the datapack.
StreamBuffer datasb(datapack);
// Extract the class and function name from the datapack.
eng::string classname;
eng::string funcname;
try {
classname = datasb.read_string_limit(100);
funcname = datasb.read_string_limit(100);
} catch (const StreamException &ex) {
return;
}
if ((!sv::is_lua_id(classname)) || (!sv::is_lua_id(funcname))) {
return;
}
LuaVar lclass, lfunc, actor, place, tangibles, retvec, retval;
LuaExtStack LS(L, lclass, lfunc, actor, place, tangibles, retvec, retval);
// 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;
}
// Get the class table and closure
eng::string err = LS.getclass(lclass, classname);
if ((!err.empty()) || (!LS.istable(lclass))) {
return;
}
LS.rawget(lfunc, lclass, funcname);
if (!LS.isfunction(lfunc)) {
return;
}
// Call the closure.
lua_pushvalue(L, lfunc.index());
lua_pushvalue(L, actor.index());
lua_pushvalue(L, place.index());
int nargs = 2;
try {
while (!datasb.empty()) {
push_simple_dynamic(L, &datasb);
nargs++;
}
} catch (const StreamException &exc) {
return;
}
open_lthread_state(actor_id, place_id, 0, false, true);
eng::string msg = traceback_pcall(L, nargs, 1);
// Send any prints to the console.
eng::string prints = lthread_prints_->str();
lthread_prints_.reset();
util::dprint(prints);
if (msg.empty()) {
lua_replace(L, retvec.index());
if (LS.istable(retvec)) {
for (int i = 1 ; ; i++) {
LS.rawget(retval, retvec, i);
bool ok = encode_simple_dynamic(LS, retval, retvals);
if (!ok) break;
}
}
} else {
util::dprint(msg);
}
close_lthread_state();
}
// This is called from World::update_source, and also
// from World::patch_source in the difference transmitter.
//
@@ -704,42 +853,6 @@ void World::invoke_lua(int64_t actor_id, int64_t place_id, std::string_view data
}
// Read a SimpleDynamic value from the streambuffer and push
// it onto the lua stack.
void push_simple_dynamic(lua_State *L, StreamBuffer *sb) {
SimpleDynamicTag type = sb->read_simple_dynamic_tag();
switch (type) {
case SimpleDynamicTag::NUMBER: {
lua_pushnumber(L, sb->read_double());
break;
}
case SimpleDynamicTag::BOOLEAN: {
lua_pushboolean(L, sb->read_bool() ? 1:0);
break;
}
case SimpleDynamicTag::STRING: {
std::string_view s = sb->read_string_view();
lua_pushlstring(L, s.data(), s.size());
break;
}
case SimpleDynamicTag::VECTOR: {
double x = sb->read_double();
double y = sb->read_double();
double z = sb->read_double();
lua_newtable(L);
lua_pushnumber(L, x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, y);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, z);
lua_rawseti(L, -2, 3);
break;
}
default: throw StreamCorruption();
}
}
void World::invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack) {
assert(stack_is_clear());
@@ -966,9 +1079,7 @@ void World::open_lthread_state(int64_t actor, int64_t place, int64_t thread, boo
void World::close_lthread_state() {
// Copy prints from lthread_prints_ stringstream into
// the appropriate actor's PrintBuffer. If for some reason
// there isn't an actor, or if the actor doesn't have a PrintBuffer,
// send the output to std::cerr.
// the appropriate actor's PrintBuffer.
if (lthread_prints_ != nullptr) {
const eng::string &output = lthread_prints_->str();
if (output.size() > 0) {