Implemented World::probe_lua_call and tested
This commit is contained in:
@@ -102,7 +102,7 @@
|
||||
#include <cassert>
|
||||
#include <ostream>
|
||||
|
||||
struct AnimValue : public SimpleDynamic<eng::string> {
|
||||
struct AnimValue : public SimpleDynamicValue {
|
||||
bool persistent;
|
||||
|
||||
AnimValue() { persistent = false; }
|
||||
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
|
||||
virtual void do_luaprobe_command(std::string_view cmd) override {
|
||||
world_to_asynchronous();
|
||||
stdostream() << world_->probe_lua(actor_id_, cmd);
|
||||
stdostream() << world_->probe_lua_expr(actor_id_, cmd);
|
||||
world_to_synchronous();
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,35 @@ public:
|
||||
}
|
||||
|
||||
virtual void do_work_command() override {
|
||||
do_unknown_command("work");
|
||||
master_->snapshot();
|
||||
StreamBuffer datapack;
|
||||
StreamBuffer retvals;
|
||||
datapack.write_string("engio");
|
||||
datapack.write_string("myfunction");
|
||||
datapack.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
|
||||
datapack.write_double(3.7);
|
||||
datapack.write_simple_dynamic_tag(SimpleDynamicTag::STRING);
|
||||
datapack.write_string("banana");
|
||||
datapack.write_simple_dynamic_tag(SimpleDynamicTag::BOOLEAN);
|
||||
datapack.write_bool(true);
|
||||
master_->probe_lua_call(admin_id_, admin_id_, datapack.view(), &retvals);
|
||||
while (!retvals.empty()) {
|
||||
SimpleDynamicValue value;
|
||||
retvals.read_simple_dynamic(&value);
|
||||
if (value.type == SimpleDynamicTag::NUMBER) {
|
||||
util::dprint("retval: ", value.x);
|
||||
} else if (value.type == SimpleDynamicTag::STRING) {
|
||||
util::dprint("retval: ", value.s);
|
||||
} else if (value.type == SimpleDynamicTag::BOOLEAN) {
|
||||
util::dprint(value.x ? "retval: true" : "retval: false");
|
||||
} else if (value.type == SimpleDynamicTag::VECTOR) {
|
||||
util::dprint("retval: ", value.x, " ", value.y, " ", value.z);
|
||||
} else {
|
||||
util::dprint("retval: invalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
master_->rollback();
|
||||
}
|
||||
|
||||
virtual void do_display_command() override {
|
||||
@@ -111,7 +139,7 @@ public:
|
||||
|
||||
virtual void do_luaprobe_command(std::string_view cmd) override {
|
||||
master_->snapshot();
|
||||
stdostream() << master_->probe_lua(admin_id_, cmd);
|
||||
stdostream() << master_->probe_lua_expr(admin_id_, cmd);
|
||||
master_->rollback();
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ std::optional<util::DXYZ> LuaCoreStack::tryxyz(LuaSlot s) const {
|
||||
lua_rawgeti(L_, s, 3);
|
||||
lua_rawgeti(L_, s, 2);
|
||||
lua_rawgeti(L_, s, 1);
|
||||
if (lua_isnumber(L_, -1) && lua_isnumber(L_, -2) && lua_isnumber(L_, -3)) {
|
||||
if ((lua_type(L_, -1)==LUA_TNUMBER) && (lua_type(L_, -2)==LUA_TNUMBER) && (lua_type(L_, -3)==LUA_TNUMBER)) {
|
||||
util::DXYZ result;
|
||||
result.x = lua_tonumber(L_, -1);
|
||||
result.y = lua_tonumber(L_, -2);
|
||||
|
||||
@@ -243,6 +243,8 @@ public:
|
||||
virtual char const *what() const { return "Stream Corruption"; }
|
||||
};
|
||||
|
||||
using SimpleDynamicValue = SimpleDynamic<eng::string>;
|
||||
|
||||
class StreamBufferCore {
|
||||
protected:
|
||||
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -242,7 +242,14 @@ public:
|
||||
// from the stringstream. If the lua expression returns a
|
||||
// value, that is also printed to the stringstream.
|
||||
//
|
||||
eng::string probe_lua(int64_t actor_id, std::string_view lua);
|
||||
eng::string probe_lua_expr(int64_t actor_id, std::string_view lua);
|
||||
|
||||
// Probe that calls lua function, passing arguments.
|
||||
//
|
||||
// Print statements are discarded. The lua function may return a vector
|
||||
// of values. If so, the values are packed into a StreamBuffer.
|
||||
//
|
||||
void probe_lua_call(int64_t place_id, int64_t actor_id, std::string_view datapack, StreamBuffer *retvals);
|
||||
|
||||
// Invoke an Invocation object.
|
||||
//
|
||||
|
||||
@@ -628,7 +628,7 @@ public:
|
||||
break;
|
||||
}
|
||||
case SimpleDynamicTag::STRING: result->set_string(read_string()); break;
|
||||
default: assert(false);
|
||||
default: result->set_uninitialized(); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ function engio.myfunction(actor, place, a, b, c)
|
||||
pprint("A:", a)
|
||||
pprint("B:", b)
|
||||
pprint("C:", c)
|
||||
return {13, "chicken", {2,3,4}, false}
|
||||
end
|
||||
|
||||
function engio.move(actor, place, action, xyz, facing)
|
||||
|
||||
Reference in New Issue
Block a user