Files
integration/luprex/core/cpp/world.hpp

498 lines
16 KiB
C++
Raw Normal View History

#ifndef WORLD_HPP
#define WORLD_HPP
#include "luastack.hpp"
2021-01-16 01:24:33 -05:00
#include "planemap.hpp"
#include "idalloc.hpp"
#include "animqueue.hpp"
#include "invocation.hpp"
#include "streambuffer.hpp"
2021-11-21 13:35:39 -05:00
#include "debugcollector.hpp"
2021-10-20 14:05:09 -04:00
#include "printbuffer.hpp"
2021-02-18 17:21:25 -05:00
#include "sched.hpp"
2021-01-16 01:24:33 -05:00
#include "source.hpp"
2021-02-07 17:26:48 -05:00
#include "gui.hpp"
2021-02-09 17:15:54 -05:00
#include "luasnap.hpp"
2021-02-18 14:56:12 -05:00
#include <set>
#include <utility>
#include <memory>
2021-01-16 01:24:33 -05:00
#include <unordered_map>
2021-01-16 01:24:33 -05:00
class World;
class Tangible {
private:
friend class World;
// Serialize and deserialize
//
// The tangible's ID is not serialized. When you serialize a tangible, you
// should probably serialize the ID separately.
//
// The Lua portion of the tangible is not serialized here. Instead, the lua
// portion is serialized when you serialize the lua state as a whole.
//
// PlaneItem is not serialized. The deserialize routine rebuilds the
// PlaneItem from the AnimQueue.
//
// World pointer is not serialized.
//
void serialize(StreamBuffer *sb);
void deserialize(StreamBuffer *sb);
2021-01-16 01:24:33 -05:00
public:
// Always points back to the world model.
World *world_;
2021-01-22 17:35:23 -05:00
// Animation queue.
2021-01-16 01:24:33 -05:00
//
AnimQueue anim_queue_;
2021-01-22 17:35:23 -05:00
// Plane Item.
//
// The PlaneItem also contains this tangible's ID.
// To move this PlaneItem, update the anim_queue first, then call
// update_plane_item, which copies the data from the anim_queue.
//
2021-01-22 17:35:23 -05:00
PlaneItem plane_item_;
2021-01-16 01:24:33 -05:00
// Player ID pool
//
// This is present in every tangible, whether a player or not.
// However, the fifo is only enabled in logged-in players.
//
IdPlayerPool id_player_pool_;
2021-10-20 14:05:09 -04:00
// Print Buffer
//
2021-11-26 15:45:36 -05:00
// Stores the console output for this actor until it can be
// probed by the client. Most tangibles have empty printbuffers,
// which are stored as just a null pointer internally.
2021-10-20 14:05:09 -04:00
//
2021-11-14 15:57:18 -05:00
PrintBuffer print_buffer_;
2021-10-20 14:05:09 -04:00
// constructor.
//
Tangible(World *w, int64_t id);
2021-01-22 17:35:23 -05:00
// Get the ID
//
2021-07-26 13:12:44 -04:00
int64_t id() const { return plane_item_.id(); }
2021-02-25 15:43:05 -05:00
void update_plane_item();
2021-07-18 17:48:39 -04:00
bool is_an_actor() { return (id_player_pool_.get_fifo_capacity() > 0); }
void configure_id_pool_for_actor() { id_player_pool_.set_fifo_capacity(20); }
2021-01-16 01:24:33 -05:00
};
using UniqueTangible = std::unique_ptr<Tangible>;
class World {
public:
using IdVector = util::IdVector;
2021-07-26 13:12:44 -04:00
using TanVector = std::vector<const Tangible*>;
2021-03-30 18:35:08 -04:00
using Redirects = std::map<int64_t, int64_t>;
2021-08-09 12:54:32 -04:00
const float RadiusVisibility = 100.0;
const float RadiusClose = 10.0;
2021-03-30 18:35:08 -04:00
2021-01-16 01:24:33 -05:00
// Constructor.
//
// The constructor also calls 'lua_open' to create a new
2021-08-03 11:25:12 -04:00
// lua interpreter for this world model.
2021-01-16 01:24:33 -05:00
//
2021-07-18 17:48:39 -04:00
World(util::WorldType wt);
2021-01-16 01:24:33 -05:00
// Destructor.
//
// Not currently functional.
//
~World();
2021-01-16 01:24:33 -05:00
// get_lua_state
//
// Get the lua interpreter associated with this world model.
//
2021-03-30 18:35:08 -04:00
lua_State *state() const { return lua_snap_.state(); }
2021-01-16 01:24:33 -05:00
2021-02-07 13:38:29 -05:00
// get_near
2021-01-22 17:35:23 -05:00
//
// Get a list of the tangibles that are near the player. If 'exclude_nowhere' is
2021-11-16 13:14:59 -05:00
// true, exclude any tangibles on the nowhere plane (but still include the player himself).
// The unsorted version returns the tangibles in an unpredictable order.
2021-01-17 16:23:10 -05:00
//
IdVector get_near(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player) const;
IdVector get_near_unsorted(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player) const;
2021-01-22 17:35:23 -05:00
// Make a tangible.
2021-01-17 16:23:10 -05:00
//
2021-11-26 15:45:36 -05:00
// You must provide a valid previously-unused ID. If pushdb is true, pushes
// the tangible's database onto the lua stack. Otherwise, leaves the lua
// stack untouched.
2021-01-22 17:35:23 -05:00
//
2021-09-10 17:06:07 -04:00
Tangible *tangible_make(lua_State *L, int64_t id, const std::string &plane, bool pushdb);
2021-01-17 16:23:10 -05:00
2021-01-22 17:35:23 -05:00
// Get a pointer to the specified tangible.
//
2021-08-03 12:40:12 -04:00
// If there's no such tangible, returns nullptr.
//
2021-01-22 17:35:23 -05:00
Tangible *tangible_get(int64_t id);
2021-07-26 13:12:44 -04:00
const Tangible *tangible_get(int64_t id) const;
2021-02-25 15:43:05 -05:00
// Get a pointer to the specified tangible.
//
// The value on the lua stack should be a valid lua tangible. If not,
// a lua error is generated.
//
2021-08-23 23:34:30 -04:00
Tangible *tangible_get(const LuaStack &LS, LuaSlot slot);
2021-07-26 13:12:44 -04:00
// Get pointers to many tangibles.
//
TanVector tangible_get_all(const IdVector &ids) const;
2021-01-17 16:23:10 -05:00
// Delete the specified tangible.
//
2021-08-03 12:40:12 -04:00
// If there's no such tangible, this is a no-op.
//
void tangible_delete(int64_t id);
2021-08-03 11:25:12 -04:00
2021-03-30 18:35:08 -04:00
// Create a login actor.
//
// Creates a tangible of class 'login' and returns its ID.
// This is used to create a temporary actor which is used during
// the login process.
//
int64_t create_login_actor();
// Fetch all redirects and clear the redirects table.
//
Redirects fetch_redirects();
// Probe an arbitrary lua expression.
//
// Any print-statements in the lua code are sent into
// a stringstream. The return value of probe_lua is the string
// from the stringstream. If the lua expression returns a
// value, that is also printed to the stringstream.
//
std::string probe_lua(int64_t actor_id, const std::string &lua);
2021-02-07 17:26:48 -05:00
// Probe the 'interface' function of the specified sprite.
//
void update_gui(int64_t actor_id, int64_t place_id, Gui *gui);
// Invoke an Invocation object.
2021-02-16 13:31:34 -05:00
//
// 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);
2021-10-15 14:47:12 -04:00
// Get the PrintBuffer of the actor.
//
const PrintBuffer *get_printbuffer(int64_t actor_id);
2021-08-03 11:25:12 -04:00
// Update the source database from disk.
//
2021-10-05 12:54:37 -04:00
// Special case: if the source pointer is nullptr, does not update.
//
void update_source(util::LuaSourcePtr source);
2021-08-03 11:25:12 -04:00
// Run all unit tests.
//
void run_unittests();
2021-08-03 11:25:12 -04:00
// fetch_global_pointer
2021-01-16 01:24:33 -05:00
//
// Given a lua state, fetch the world model associated with
// that lua state.
//
2021-02-25 14:09:16 -05:00
static World *fetch_global_pointer(lua_State *L);
2021-02-16 13:31:34 -05:00
// Serialize and deserialize.
//
void serialize(StreamBuffer *sb);
void deserialize(StreamBuffer *sb);
// Snapshot and rollback.
2021-02-16 13:31:34 -05:00
//
void snapshot();
void rollback();
2021-11-09 16:27:39 -05:00
bool snapshot_empty() { return snapshot_.empty(); }
2021-09-10 17:06:07 -04:00
// Run any threads which according to the scheduler queue are ready.
//
2021-11-26 15:45:36 -05:00
void run_scheduled_threads();
2021-09-10 17:06:07 -04:00
// Check that the main thread has nothing on the stack
//
bool stack_is_clear() const { return lua_gettop(state()) == 0; }
// Set the lthread state.
//
// Whenever lua code is running, and ONLY when lua code is running,
// we store the following information in the world model:
//
// * lthread_actor_id: current actor
// * lthread_place_id: current place
// * lthread_use_ppool: true if we should use the player ID pool.
// * lthread_prints_: a stringstream which will collect 'print' statements.
//
// As soon as the lua code stops executing, these variables are
// cleared.
//
void clear_lthread_state();
void open_lthread_state(int64_t actor_id, int64_t place_id, bool ppool, bool prints);
void close_lthread_state();
std::ostream *lthread_print_stream() const;
// Allocate a single ID.
//
// The rules are as follows:
// * if lthread_use_ppool is false, uses the global pool.
// * if lthread_actor_id is not a valid actor id, uses the global pool.
// * otherwise, uses the player pool of lthread_actor_id.
//
int64_t alloc_id_predictable();
2021-10-13 19:41:59 -04:00
private:
// Store a pointer to a world model into a lua registry.
//
static void store_global_pointer(lua_State *L, World *w);
2021-09-10 17:06:07 -04:00
// Invoke a plan.
//
2021-10-15 14:47:12 -04:00
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
2021-10-15 14:47:12 -04:00
// Invoke a lua string.
//
void invoke_lua(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
// Invoke the flush-prints operation.
//
void invoke_flush_prints(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
2021-11-26 15:45:36 -05:00
// Invoke the tick operation.
//
void invoke_tick(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
2021-08-03 11:25:12 -04:00
public:
////////////////////////////////////////////////////////////////////////////
//
// TESTING SUPPORT
//
// The following functions are not designed to be useful for production
// code, they're designed to be helpful for unit testing.
//
////////////////////////////////////////////////////////////////////////////
// Add a 'walkto' animation to the specified tangible.
//
void tangible_walkto(int64_t id, int64_t animid, float x, float y);
2021-08-03 12:40:12 -04:00
// Get the tangible's animation queue as a debug string.
//
std::string tangible_anim_debug_string(int64_t id) const;
2021-08-03 11:25:12 -04:00
// Get a list of all existing tangibles as a comma-separated string.
//
std::string tangible_ids_debug_string() const;
2021-08-13 17:02:35 -04:00
2021-11-16 13:14:59 -05:00
// Get a list of all tangibles near the target as a string.
//
std::string tangibles_near_debug_string(int64_t actor, int64_t distance);
2021-08-13 17:02:35 -04:00
// Shows the TID (table ID) of the tables that were numbered.
// TIDs are in alphabetical order. Any table without a TID
// shows up as "unknown"
//
std::string numbered_tables_debug_string() const;
// Paired tables debug string. Shows TID=TID pairs, sorted alphabetically.
//
2021-08-23 23:34:30 -04:00
std::string paired_tables_debug_string(lua_State *master) const;
2021-08-13 17:02:35 -04:00
// Store a string in the tangible's database.
//
void tangible_set_string(int64_t id, const std::string &path, const std::string &value);
// Copy a lua global variable into the tangible's database.
//
void tangible_copy_global(int64_t id, const std::string &path, const std::string &global);
// Pretty-print the entire tangible database and return it as a string.
//
std::string tangible_pprint(int64_t id) const;
2021-09-10 17:06:07 -04:00
// Set the tangible's lua class.
//
2021-09-10 17:06:07 -04:00
void tangible_set_class(int64_t id, const std::string &c) const;
2021-09-10 17:06:07 -04:00
// Get the tangible's lua class (returns empty string if none).
//
2021-09-10 17:06:07 -04:00
std::string tangible_get_class(int64_t id) const;
2021-09-10 17:06:07 -04:00
public:
///////////////////////////////////////////////////////////
//
2021-09-10 17:06:07 -04:00
// world-difftab: Nonrecursive table comparison
//
// These routines compare tables in the master lua to the corresponding
// tables in the synchronous lua. This is a nonrecursive process, because
// the recursion has already been done during the table enumeration process.
//
///////////////////////////////////////////////////////////
2021-11-21 13:35:39 -05:00
void patch_numbered_tables(StreamBuffer *sb, DebugCollector *dbc);
2021-09-10 17:06:07 -04:00
void diff_numbered_tables(lua_State *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_tangible_databases(StreamBuffer *sb, DebugCollector *dbc);
2021-09-10 17:06:07 -04:00
void diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_tangible_classes(StreamBuffer *sb, DebugCollector *dbc);
2021-09-10 17:06:07 -04:00
void diff_tangible_classes(const IdVector &basis, lua_State *master, StreamBuffer *sb);
public:
///////////////////////////////////////////////////////////
//
// Difference transmission
//
///////////////////////////////////////////////////////////
2021-09-10 17:06:07 -04:00
util::IdVector get_visible_union(int64_t actor_id, World *master);
2021-11-21 13:35:39 -05:00
int64_t patch_actor(StreamBuffer *sb, DebugCollector *dbc);
void diff_actor(int64_t actor_id, World *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_visible(StreamBuffer *sb, DebugCollector *dbc);
void diff_visible(const util::IdVector &ids, World *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_luatabs(StreamBuffer *sb, DebugCollector *dbc);
void diff_luatabs(int64_t actor_id, World *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_tanclass(StreamBuffer *sb, DebugCollector *dbc);
2021-09-10 17:06:07 -04:00
void diff_tanclass(int64_t actor_id, World *master, StreamBuffer *sb);
2021-11-21 13:35:39 -05:00
void patch_source(StreamBuffer *sb, DebugCollector *dbc);
void diff_source(World *master, StreamBuffer *sb);
// This is the main entry point for difference transmission.
//
2021-11-21 13:35:39 -05:00
int64_t patch_everything(StreamBuffer *sb, DebugCollector *dbc);
void diff_everything(int64_t actor, World *master, StreamBuffer *sb);
2021-08-13 17:02:35 -04:00
public:
///////////////////////////////////////////////////////////
//
2021-09-07 14:38:46 -04:00
// world-pairtab: Numbering and pairing of lua tables.
2021-08-13 17:02:35 -04:00
//
// The following routines pair up tables in the synchronous
// model with tables in the master model, by assigning matching
// table numbers. This is not one subroutine but several, because
// some of the steps happen on the server, some on the client,
// and so forth.
//
// The goal of these routines is to build these data structures:
//
2021-08-13 17:02:35 -04:00
// Table-to-number mapping is stored in registry.tnmap
// Number-to-table mapping is stored in registry.ntmap
//
///////////////////////////////////////////////////////////
// In the synchronous models, number tables recursively.
//
// This is a simple recursive traversal, which numbers tables.
// This creates the initial ntmap in the synchronous models.
2021-08-13 17:02:35 -04:00
//
int number_lua_tables(const IdVector &basis);
// Pair tables in the master model to tables in the synch model.
2021-08-13 17:02:35 -04:00
//
// Recursively walk the master and synchronous model in parallel,
// copying table numbers from the synchronous ntmap into the master's ntmap.
2021-08-13 17:02:35 -04:00
//
2021-08-23 23:34:30 -04:00
void pair_lua_tables(const IdVector &basis, lua_State *master);
2021-08-13 17:02:35 -04:00
// Number previously unpaired tables in the master model.
2021-08-13 17:02:35 -04:00
//
// This finds every not-yet-numbered table in the master model,
// and appends these tables to the master's ntmap. Once they're
// in the ntmap, they can be paired by simply creating new tables
// in the synchronous model.
2021-08-13 17:02:35 -04:00
//
int number_remaining_tables(const IdVector &basis, lua_State *master);
2021-08-13 17:02:35 -04:00
// Create new tables in the synchronous models.
//
// Creates new tables in the synchronous model and appends these
// new tables to the synchronous model's ntmap.
2021-08-13 17:02:35 -04:00
//
void create_new_tables(int n);
// Delete the table numbering.
//
// This simply removes registry.tnmap and registry.ntmap
//
void unnumber_lua_tables();
private:
// Type of model
util::WorldType world_type_;
// A lua intepreter with snapshot function.
//
LuaSnap lua_snap_;
// The Global ID Pool.
//
IdGlobalPool id_global_pool_;
// Source Database.
//
SourceDB source_db_;
PlaneMap plane_map_;
// Tangibles table.
//
std::unordered_map<int64_t, UniqueTangible> tangibles_;
2021-11-26 15:45:36 -05:00
// Current time.
int64_t clock_;
// Thread schedule: must include every thread, except
// for the one currently-executing thread.
//
Schedule thread_sched_;
// Serialized snapshot of world model.
StreamBuffer snapshot_;
// Redirects.
//
Redirects redirects_;
// lthread variables: see set_lthread_state for explanation.
//
int64_t lthread_actor_id_;
int64_t lthread_place_id_;
int64_t lthread_use_ppool_;
std::unique_ptr<std::ostringstream> lthread_prints_;
friend class Tangible;
friend int lfn_tangible_animate(lua_State *L);
friend int lfn_tangible_build(lua_State *L);
friend int lfn_tangible_redirect(lua_State *L);
friend int lfn_tangible_actor(lua_State *L);
friend int lfn_tangible_place(lua_State *L);
2021-11-21 13:35:39 -05:00
friend int lfn_tangible_nopredict(lua_State *L);
friend int lfn_tangible_near(lua_State *L);
friend int lfn_tangible_scan(lua_State *L);
};
using UniqueWorld = std::unique_ptr<World>;
#endif // WORLD_HPP