371 lines
11 KiB
C++
371 lines
11 KiB
C++
|
|
#ifndef WORLD_HPP
|
|
#define WORLD_HPP
|
|
|
|
#include "luastack.hpp"
|
|
#include "planemap.hpp"
|
|
#include "idalloc.hpp"
|
|
#include "animqueue.hpp"
|
|
#include "invocation.hpp"
|
|
#include "streambuffer.hpp"
|
|
#include "sched.hpp"
|
|
#include "source.hpp"
|
|
#include "gui.hpp"
|
|
#include "luasnap.hpp"
|
|
#include <set>
|
|
#include <utility>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
|
|
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);
|
|
|
|
public:
|
|
// Always points back to the world model.
|
|
World *world_;
|
|
|
|
// Animation queue.
|
|
//
|
|
AnimQueue anim_queue_;
|
|
|
|
// 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.
|
|
//
|
|
PlaneItem plane_item_;
|
|
|
|
// 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_;
|
|
|
|
// constructor.
|
|
//
|
|
Tangible(World *w, int64_t id);
|
|
|
|
// Get the ID
|
|
//
|
|
int64_t id() const { return plane_item_.id(); }
|
|
|
|
void update_plane_item();
|
|
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); }
|
|
};
|
|
|
|
class World {
|
|
public:
|
|
using IdVector = util::IdVector;
|
|
using TanVector = std::vector<const Tangible*>;
|
|
using Redirects = std::map<int64_t, int64_t>;
|
|
const float RadiusVisibility = 100.0;
|
|
const float RadiusClose = 10.0;
|
|
|
|
// Constructor.
|
|
//
|
|
// The constructor also calls 'lua_open' to create a new
|
|
// lua interpreter for this world model.
|
|
//
|
|
World(util::WorldType wt);
|
|
|
|
// Destructor.
|
|
//
|
|
// Not currently functional.
|
|
//
|
|
~World();
|
|
|
|
// get_lua_state
|
|
//
|
|
// Get the lua interpreter associated with this world model.
|
|
//
|
|
lua_State *state() const { return lua_snap_.state(); }
|
|
|
|
// get_near
|
|
//
|
|
// Get a list of the tangibles that are near the player. If 'exclude_nowhere' is
|
|
// true, exclude any tangibles on the nowhere plane. The unsorted version returns
|
|
// the tangibles in an unpredictable order.
|
|
//
|
|
IdVector get_near(int64_t player_id, float radius, bool exclude_nowhere) const;
|
|
IdVector get_near_unsorted(int64_t player_id, float radius, bool exclude_nowhere) const;
|
|
|
|
// Make a tangible.
|
|
//
|
|
// If the ID is zero, allocates an ID using the thread's ID allocator. If
|
|
// pushdb is true, pushes the tangible's database onto the lua stack.
|
|
// Otherwise, leaves the lua stack untouched.
|
|
//
|
|
Tangible *tangible_make(lua_State *L, int64_t id, bool pushdb);
|
|
|
|
// Get the tangible ID of the specified LUA tangible database.
|
|
//
|
|
// Return zero if the item is not a tangible database.
|
|
//
|
|
static int64_t tangible_id(const LuaStack &LS, LuaSlot slot);
|
|
|
|
// Get a pointer to the specified tangible.
|
|
//
|
|
// If there's no such tangible, returns nullptr.
|
|
//
|
|
Tangible *tangible_get(int64_t id);
|
|
const Tangible *tangible_get(int64_t id) const;
|
|
|
|
// 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.
|
|
//
|
|
Tangible *tangible_get(const LuaStack &LS, LuaSlot slot);
|
|
|
|
// Get pointers to many tangibles.
|
|
//
|
|
TanVector tangible_get_all(const IdVector &ids) const;
|
|
|
|
// Delete the specified tangible.
|
|
//
|
|
// If there's no such tangible, this is a no-op.
|
|
//
|
|
void tangible_delete(int64_t id);
|
|
|
|
// 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 the 'interface' function of the specified sprite.
|
|
//
|
|
void update_gui(int64_t actor_id, int64_t place_id, Gui *gui);
|
|
|
|
// Invoke an Invocation object.
|
|
//
|
|
// 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);
|
|
|
|
// Update the source database from disk.
|
|
//
|
|
void update_source() { source_db_.update(); source_db_.rebuild(); }
|
|
|
|
// Run all unit tests.
|
|
//
|
|
void run_unittests() { source_db_.run_unittests(); }
|
|
|
|
// fetch_global_pointer
|
|
//
|
|
// Given a lua state, fetch the world model associated with
|
|
// that lua state.
|
|
//
|
|
static World *fetch_global_pointer(lua_State *L);
|
|
|
|
// Serialize and deserialize.
|
|
//
|
|
void serialize(StreamBuffer *sb);
|
|
void deserialize(StreamBuffer *sb);
|
|
|
|
// Snapshot and rollback.
|
|
//
|
|
void snapshot();
|
|
void rollback();
|
|
|
|
// Difference transmission.
|
|
//
|
|
// This generates diffs and stores them in the specified buffer,
|
|
// so that they can be sent to the client. It also applies the diffs
|
|
// to this model.
|
|
//
|
|
void difference_transmit(int64_t actor, World *master, StreamBuffer *sb);
|
|
|
|
// Apply differences.
|
|
//
|
|
// Note that difference_transmit applies the differences to the server
|
|
// synchronous model, so this is only used by the client synchronous model.
|
|
//
|
|
void apply_differences(StreamBuffer *sb);
|
|
|
|
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);
|
|
|
|
// Get the tangible's animation queue as a debug string.
|
|
//
|
|
std::string tangible_anim_debug_string(int64_t id) const;
|
|
|
|
// Get a list of all existing tangibles as a comma-separated string.
|
|
//
|
|
std::string tangible_ids_debug_string() const;
|
|
|
|
// 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.
|
|
//
|
|
std::string paired_tables_debug_string(lua_State *master) const;
|
|
|
|
// 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);
|
|
|
|
private:
|
|
// Run any threads which according to the scheduler queue are ready.
|
|
//
|
|
void run_scheduled_threads(int64_t clk);
|
|
|
|
// Store a pointer to a world model into a lua registry.
|
|
//
|
|
static void store_global_pointer(lua_State *L, World *w);
|
|
|
|
// Check that the main thread has nothing on the stack
|
|
//
|
|
bool stack_is_clear() const { return lua_gettop(state()) == 0; }
|
|
|
|
// Invoke a plan.
|
|
//
|
|
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata);
|
|
|
|
// pass 1 of difference transmission: actor essentials.
|
|
//
|
|
// Before we do anything else, we need to get the actor in the right place.
|
|
// We also update the actor's ID allocation pipeline.
|
|
//
|
|
static void diff_actor_essentials(const Tangible *mactor, const Tangible *sactor, StreamBuffer *sb);
|
|
int64_t patch_actor_essentials(StreamBuffer *sb);
|
|
|
|
// Pass 2 of difference transmission: visible animations.
|
|
//
|
|
// Synchronizes the animation status of every tangible inside the visibility
|
|
// radius of either model. Creates missing tangibles and deletes excess tangibles.
|
|
//
|
|
static void diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb);
|
|
void patch_visible_animations(StreamBuffer *sb);
|
|
|
|
// Compare the general tables.
|
|
//
|
|
void diff_lua_tables(lua_State *master, StreamBuffer *sb);
|
|
|
|
// Compare the tangible databases.
|
|
//
|
|
void diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb);
|
|
|
|
public:
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Numbering and pairing of lua tables.
|
|
//
|
|
// Table-to-number mapping is stored in registry.tnmap
|
|
// Number-to-table mapping is stored in registry.ntmap
|
|
//
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// numbering of tables.
|
|
//
|
|
// Returns the total number of tables numbered.
|
|
//
|
|
int number_lua_tables(const IdVector &basis);
|
|
|
|
// Deletes registry.tnmap and registry.ntmap
|
|
//
|
|
void unnumber_lua_tables();
|
|
|
|
// Number tables in the master model to match already-numbered tables in the synch model.
|
|
//
|
|
void pair_lua_tables(const IdVector &basis, lua_State *master);
|
|
|
|
// Pairs every not-yet-paired master table to a virtually-created table in the synch model.
|
|
//
|
|
// Returns the number of new tables that need to be created in the synch model.
|
|
//
|
|
int pair_new_tables(const IdVector &basis, lua_State *master);
|
|
|
|
// This is followup for pair_new_tables: actually create the new tables that
|
|
// were virtually created in the pair_new_tables step.
|
|
//
|
|
void create_new_tables(int n);
|
|
|
|
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, std::unique_ptr<Tangible>> tangibles_;
|
|
|
|
// 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_;
|
|
|
|
friend class Tangible;
|
|
friend int tangible_animate(lua_State *L);
|
|
friend int tangible_build(lua_State *L);
|
|
friend int tangible_redirect(lua_State *L);
|
|
};
|
|
|
|
#endif // WORLD_HPP
|