Implemented World::probe_lua_call and tested
This commit is contained in:
@@ -102,7 +102,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
struct AnimValue : public SimpleDynamic<eng::string> {
|
struct AnimValue : public SimpleDynamicValue {
|
||||||
bool persistent;
|
bool persistent;
|
||||||
|
|
||||||
AnimValue() { persistent = false; }
|
AnimValue() { persistent = false; }
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public:
|
|||||||
|
|
||||||
virtual void do_luaprobe_command(std::string_view cmd) override {
|
virtual void do_luaprobe_command(std::string_view cmd) override {
|
||||||
world_to_asynchronous();
|
world_to_asynchronous();
|
||||||
stdostream() << world_->probe_lua(actor_id_, cmd);
|
stdostream() << world_->probe_lua_expr(actor_id_, cmd);
|
||||||
world_to_synchronous();
|
world_to_synchronous();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,35 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void do_work_command() override {
|
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 {
|
virtual void do_display_command() override {
|
||||||
@@ -111,7 +139,7 @@ public:
|
|||||||
|
|
||||||
virtual void do_luaprobe_command(std::string_view cmd) override {
|
virtual void do_luaprobe_command(std::string_view cmd) override {
|
||||||
master_->snapshot();
|
master_->snapshot();
|
||||||
stdostream() << master_->probe_lua(admin_id_, cmd);
|
stdostream() << master_->probe_lua_expr(admin_id_, cmd);
|
||||||
master_->rollback();
|
master_->rollback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ std::optional<util::DXYZ> LuaCoreStack::tryxyz(LuaSlot s) const {
|
|||||||
lua_rawgeti(L_, s, 3);
|
lua_rawgeti(L_, s, 3);
|
||||||
lua_rawgeti(L_, s, 2);
|
lua_rawgeti(L_, s, 2);
|
||||||
lua_rawgeti(L_, s, 1);
|
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;
|
util::DXYZ result;
|
||||||
result.x = lua_tonumber(L_, -1);
|
result.x = lua_tonumber(L_, -1);
|
||||||
result.y = lua_tonumber(L_, -2);
|
result.y = lua_tonumber(L_, -2);
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ public:
|
|||||||
virtual char const *what() const { return "Stream Corruption"; }
|
virtual char const *what() const { return "Stream Corruption"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using SimpleDynamicValue = SimpleDynamic<eng::string>;
|
||||||
|
|
||||||
class StreamBufferCore {
|
class StreamBufferCore {
|
||||||
protected:
|
protected:
|
||||||
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
||||||
|
|||||||
@@ -9,6 +9,68 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#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) {
|
void World::store_global_pointer(lua_State *L, World *v) {
|
||||||
lua_pushstring(L, "world");
|
lua_pushstring(L, "world");
|
||||||
lua_pushlightuserdata(L, v);
|
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());
|
assert(stack_is_clear());
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
|
|
||||||
@@ -343,6 +405,93 @@ eng::string World::probe_lua(int64_t actor_id, std::string_view lua) {
|
|||||||
return result;
|
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
|
// This is called from World::update_source, and also
|
||||||
// from World::patch_source in the difference transmitter.
|
// 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) {
|
void World::invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack) {
|
||||||
assert(stack_is_clear());
|
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() {
|
void World::close_lthread_state() {
|
||||||
// Copy prints from lthread_prints_ stringstream into
|
// Copy prints from lthread_prints_ stringstream into
|
||||||
// the appropriate actor's PrintBuffer. If for some reason
|
// the appropriate actor's PrintBuffer.
|
||||||
// there isn't an actor, or if the actor doesn't have a PrintBuffer,
|
|
||||||
// send the output to std::cerr.
|
|
||||||
if (lthread_prints_ != nullptr) {
|
if (lthread_prints_ != nullptr) {
|
||||||
const eng::string &output = lthread_prints_->str();
|
const eng::string &output = lthread_prints_->str();
|
||||||
if (output.size() > 0) {
|
if (output.size() > 0) {
|
||||||
|
|||||||
@@ -242,7 +242,14 @@ public:
|
|||||||
// from the stringstream. If the lua expression returns a
|
// from the stringstream. If the lua expression returns a
|
||||||
// value, that is also printed to the stringstream.
|
// 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.
|
// Invoke an Invocation object.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -628,7 +628,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SimpleDynamicTag::STRING: result->set_string(read_string()); 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("A:", a)
|
||||||
pprint("B:", b)
|
pprint("B:", b)
|
||||||
pprint("C:", c)
|
pprint("C:", c)
|
||||||
|
return {13, "chicken", {2,3,4}, false}
|
||||||
end
|
end
|
||||||
|
|
||||||
function engio.move(actor, place, action, xyz, facing)
|
function engio.move(actor, place, action, xyz, facing)
|
||||||
|
|||||||
Reference in New Issue
Block a user