Plan invocations are now serializable objects
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
CXX=g++ -std=c++17 -Wall -g -Iinc -Icpp
|
CXX=g++ -std=c++17 -Wall -g -Iinc -Icpp
|
||||||
|
|
||||||
CPP_FILES=\
|
CPP_FILES=\
|
||||||
|
cpp/invocation.cpp\
|
||||||
cpp/spookyv2.cpp\
|
cpp/spookyv2.cpp\
|
||||||
cpp/util.cpp\
|
cpp/util.cpp\
|
||||||
cpp/luastack.cpp\
|
cpp/luastack.cpp\
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ bool Gui::has_action(const std::string &action) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LuaDefine(gui_menu_item, "c") {
|
LuaDefine(gui_menu_item, "c") {
|
||||||
Gui *gui = Gui::fetch_global_pointer(L);
|
Gui *gui = Gui::fetch_global_pointer(L);
|
||||||
LuaArg laction, llabel;
|
LuaArg laction, llabel;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
|
#include "streambuffer.hpp"
|
||||||
|
|
||||||
class GuiElt {
|
class GuiElt {
|
||||||
friend class Gui;
|
friend class Gui;
|
||||||
@@ -45,7 +46,6 @@ public:
|
|||||||
static Gui *fetch_global_pointer(lua_State *L);
|
static Gui *fetch_global_pointer(lua_State *L);
|
||||||
};
|
};
|
||||||
|
|
||||||
using GuiResult = std::map<std::string, std::string>;
|
|
||||||
|
|
||||||
#endif // GUI_HPP
|
#endif // GUI_HPP
|
||||||
|
|
||||||
|
|||||||
44
luprex/core/cpp/invocation.cpp
Normal file
44
luprex/core/cpp/invocation.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
#include "invocation.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
void InvocationData::serialize(StreamBuffer *sb) const {
|
||||||
|
assert(int(size()) < 65536);
|
||||||
|
sb->write_uint16(size());
|
||||||
|
for (const auto &pair : *this) {
|
||||||
|
sb->write_string(pair.first);
|
||||||
|
sb->write_string(pair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvocationData::deserialize(StreamBuffer *sb) {
|
||||||
|
clear();
|
||||||
|
int size = sb->read_uint16();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
std::string key = sb->read_string();
|
||||||
|
std::string val = sb->read_string();
|
||||||
|
(*this)[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Invocation::Invocation() : kind_(KIND_INVALID), actor_(0), place_(0) {}
|
||||||
|
|
||||||
|
Invocation::Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action, const InvocationData &data)
|
||||||
|
: kind_(kind), actor_(actor), place_(place), action_(action), data_(data) {}
|
||||||
|
|
||||||
|
void Invocation::serialize(StreamBuffer *sb) const {
|
||||||
|
sb->write_uint8(kind_);
|
||||||
|
sb->write_int64(actor_);
|
||||||
|
sb->write_int64(place_);
|
||||||
|
sb->write_string(action_);
|
||||||
|
data_.serialize(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Invocation::deserialize(StreamBuffer *sb) {
|
||||||
|
kind_ = Kind(sb->read_uint8());
|
||||||
|
actor_ = sb->read_int64();
|
||||||
|
place_ = sb->read_int64();
|
||||||
|
action_ = sb->read_string();
|
||||||
|
data_.deserialize(sb);
|
||||||
|
}
|
||||||
|
|
||||||
47
luprex/core/cpp/invocation.hpp
Normal file
47
luprex/core/cpp/invocation.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef INVOCATION_HPP
|
||||||
|
#define INVOCATION_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <deque>
|
||||||
|
#include "streambuffer.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class InvocationData : public std::map<std::string, std::string> {
|
||||||
|
public:
|
||||||
|
void serialize(StreamBuffer *sb) const;
|
||||||
|
void deserialize(StreamBuffer *sb);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Invocation {
|
||||||
|
public:
|
||||||
|
enum Kind {
|
||||||
|
KIND_INVALID,
|
||||||
|
KIND_PLAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Kind kind_;
|
||||||
|
int64_t actor_;
|
||||||
|
int64_t place_;
|
||||||
|
std::string action_;
|
||||||
|
InvocationData data_;
|
||||||
|
public:
|
||||||
|
Invocation();
|
||||||
|
Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action, const InvocationData &data);
|
||||||
|
|
||||||
|
Kind kind() const { return kind_; }
|
||||||
|
int64_t actor() const { return actor_; }
|
||||||
|
int64_t place() const { return place_; }
|
||||||
|
const std::string &action() const { return action_; }
|
||||||
|
const InvocationData &data() const { return data_; }
|
||||||
|
|
||||||
|
void serialize(StreamBuffer *sb) const;
|
||||||
|
void deserialize(StreamBuffer *sb);
|
||||||
|
};
|
||||||
|
|
||||||
|
class InvocationQueue : public std::deque<Invocation> {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INVOCATION_HPP
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
|
#include "invocation.hpp"
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "traceback.hpp"
|
#include "traceback.hpp"
|
||||||
#include "textgame.hpp"
|
#include "textgame.hpp"
|
||||||
@@ -122,10 +123,11 @@ void TextGame::do_choose_command(const StringVec &cmd) {
|
|||||||
}
|
}
|
||||||
std::string action = elts[index].action();
|
std::string action = elts[index].action();
|
||||||
std::cerr << "Invoking plan: " << action << std::endl;
|
std::cerr << "Invoking plan: " << action << std::endl;
|
||||||
GuiResult dummyresult;
|
InvocationData dummyresult;
|
||||||
dummyresult["flavor"] = "chocolate";
|
dummyresult["flavor"] = "chocolate";
|
||||||
dummyresult["color"] = "blue";
|
dummyresult["color"] = "blue";
|
||||||
world_->invoke_plan(actor_id_, gui_place_, action, dummyresult);
|
Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_place_, action, dummyresult);
|
||||||
|
world_->invoke(inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextGame::do_snapshot_command(const StringVec &cmd) {
|
void TextGame::do_snapshot_command(const StringVec &cmd) {
|
||||||
|
|||||||
@@ -265,7 +265,22 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
|
|||||||
assert(stack_is_clear());
|
assert(stack_is_clear());
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const GuiResult &gres) {
|
void World::invoke(const Invocation &inv) {
|
||||||
|
switch (inv.kind()) {
|
||||||
|
case Invocation::KIND_PLAN:
|
||||||
|
invoke_plan(inv.actor(), inv.place(), inv.action(), inv.data());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Do nothing. Standard behavior for any invalid command is to
|
||||||
|
// simply do nothing at all. Perhaps eventually we may add a flag
|
||||||
|
// to the world model to indicate that we've detected an invalid
|
||||||
|
// command, to allow us to close the connection to a client that
|
||||||
|
// is misbehaving.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata) {
|
||||||
assert(stack_is_clear());
|
assert(stack_is_clear());
|
||||||
|
|
||||||
// Validate that the action is legal.
|
// Validate that the action is legal.
|
||||||
@@ -288,8 +303,8 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
|||||||
|
|
||||||
// Set up for Lua manipulation.
|
// Set up for Lua manipulation.
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
LuaVar actor, place, func, tangibles, mt, index, actions, thread, threads, message, guires;
|
LuaVar actor, place, func, tangibles, mt, index, actions, thread, threads, message, invdata;
|
||||||
LuaStack LS(L, actor, place, func, tangibles, mt, index, actions, thread, threads, message, guires);
|
LuaStack LS(L, actor, place, func, tangibles, mt, index, actions, thread, threads, message, invdata);
|
||||||
|
|
||||||
// Get the actor and place.
|
// Get the actor and place.
|
||||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||||
@@ -322,10 +337,10 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the GuiResult into a lua table.
|
// Convert the InvocationData into a lua table.
|
||||||
LS.newtable(guires);
|
LS.newtable(invdata);
|
||||||
for (const auto &p : gres) {
|
for (const auto &p : idata) {
|
||||||
LS.rawset(guires, p.first, p.second);
|
LS.rawset(invdata, p.first, p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new thread, set up function and parameters.
|
// Create a new thread, set up function and parameters.
|
||||||
@@ -333,7 +348,7 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
|||||||
lua_pushvalue(L, func.index());
|
lua_pushvalue(L, func.index());
|
||||||
lua_pushvalue(L, actor.index());
|
lua_pushvalue(L, actor.index());
|
||||||
lua_pushvalue(L, place.index());
|
lua_pushvalue(L, place.index());
|
||||||
lua_pushvalue(L, guires.index());
|
lua_pushvalue(L, invdata.index());
|
||||||
lua_xmove(L, CO, 4);
|
lua_xmove(L, CO, 4);
|
||||||
|
|
||||||
// Store the thread into place's thread table.
|
// Store the thread into place's thread table.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "planemap.hpp"
|
#include "planemap.hpp"
|
||||||
#include "idalloc.hpp"
|
#include "idalloc.hpp"
|
||||||
#include "animqueue.hpp"
|
#include "animqueue.hpp"
|
||||||
|
#include "invocation.hpp"
|
||||||
#include "sched.hpp"
|
#include "sched.hpp"
|
||||||
#include "source.hpp"
|
#include "source.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
@@ -113,6 +114,10 @@ public:
|
|||||||
|
|
||||||
// Check if main thread has nothing on the stack
|
// Check if main thread has nothing on the stack
|
||||||
bool stack_is_clear() const { return lua_gettop(state()) == 0; }
|
bool stack_is_clear() const { return lua_gettop(state()) == 0; }
|
||||||
|
|
||||||
|
// Invoke an action plan.
|
||||||
|
//
|
||||||
|
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata);
|
||||||
public:
|
public:
|
||||||
// Constructor.
|
// Constructor.
|
||||||
//
|
//
|
||||||
@@ -181,9 +186,12 @@ public:
|
|||||||
//
|
//
|
||||||
void update_gui(int64_t actor_id, int64_t place_id, Gui *gui);
|
void update_gui(int64_t actor_id, int64_t place_id, Gui *gui);
|
||||||
|
|
||||||
// Invoke an action plan.
|
// Invoke an Invocation object.
|
||||||
//
|
//
|
||||||
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const GuiResult &gres);
|
// This is the primary dispatcher for all operations that mutate a world model.
|
||||||
|
// To mutate a world model, create an invocation, then invoke it.
|
||||||
|
//
|
||||||
|
void invoke(const Invocation &inv);
|
||||||
|
|
||||||
// fetch_global_pointer
|
// fetch_global_pointer
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user