More work on redirect

This commit is contained in:
2026-06-02 18:34:03 -04:00
parent 6c9f75bfac
commit d951d2ab61
12 changed files with 298 additions and 201 deletions

View File

@@ -92,7 +92,8 @@ public:
//
// This flag is set to true when a client is controlling this player.
// It gets set back to false when the client logs out or attaches
// to a different player. This can only be set in master models.
// to a different player. If this is set, then the connections_
// table contains a map from a client ID to this actor.
//
bool is_controlled_;
@@ -129,7 +130,6 @@ class World : public eng::opnew {
public:
using IdVector = util::IdVector;
using TanVector = eng::vector<const Tangible*>;
using Redirects = eng::map<int64_t, int64_t>;
const float RadiusVisibility = 1000.0;
const float RadiusClose = 1000.0;
@@ -221,46 +221,7 @@ public:
// 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.
//
// If this is a master model, The function 'login.init'
// called. Then, the following login flags are set:
// can_be_controlled, is_controlled, and delete_on_disconnect.
//
// In a client model, 'login.init' is not called,
// and the login flags are not used in client models.
//
int64_t create_login_actor();
// Log out a connected player.
//
// This is to be called after a client disconnects.
//
void disconnected(int64_t actor_id);
// Notify the world that the front end has implemented a
// redirect. This can return null to indicate a last-minute
// failure, in which case the front end must disconnect.
//
bool redirected(int64_t actor_id, int64_t new_id);
// Add a redirect.
//
void add_redirect(int64_t a, int64_t b) { redirects_.emplace(a,b); }
// Fetch all redirects and clear the redirects table.
//
Redirects fetch_redirects();
// Return true if there are any redirects.
//
bool have_redirects() const { return !redirects_.empty(); }
// Probe an arbitrary lua expression.
//
// Any print-statements in the lua code are sent into
@@ -285,7 +246,11 @@ public:
// It is legal to mutate a world model without using 'Invoke', but
// only in authoritative world models.
//
void invoke(const Invocation &inv);
// If you pass in a nonzero client id, then that means the invocation was
// sent by a connected client. In that case, this checks that the invocation
// is legal for that client.
//
void invoke(int64_t client_id, const Invocation &inv);
// Get the PrintBuffer of the actor.
//
@@ -351,6 +316,11 @@ public:
// Serialize and deserialize.
//
// Caution: this will save all state, including state like current connections
// and ongoing HTTP requests. It may be desirable, after saving and restoring,
// to purge connections and HTTP requests. There are separate functions to do
// these things.
//
void serialize(StreamBuffer *sb);
void deserialize(StreamBuffer *sb);
@@ -395,19 +365,6 @@ public:
//
void lthread_prints_to_actor(int64_t actor_id);
// Set a lua global variable.
//
// The table just stores strings, and the difference transmitter
// just difference transmits those strings. The strings are meant
// to be serialized lua data structures, but there is no enforcement
// of that here.
//
void set_global(const eng::string &var, std::string_view value);
// Get a lua global variable.
//
const eng::string &get_global(const eng::string &var);
// Allocate a single ID.
//
// The rules are as follows:
@@ -427,7 +384,75 @@ public:
// Otherwise, return.
void guard_nopredict(lua_State *L, const char *fn);
public:
//////////////////////////////////////////////////////////////////////////
//
// Global variables.
//
//////////////////////////////////////////////////////////////////////////
// Set a lua global variable.
//
// The table just stores strings, and the difference transmitter
// just difference transmits those strings. The strings are meant
// to be serialized lua data structures, but there is no enforcement
// of that here.
//
void set_global(const eng::string &var, std::string_view value);
// Get a lua global variable.
//
const eng::string &get_global(const eng::string &var);
public:
//////////////////////////////////////////////////////////////////////////
//
// Connection Management
//
//////////////////////////////////////////////////////////////////////////
// Create a connection.
//
// This creates a login actor, and also records the existence of
// the connection. Returns the actor_id of the login actor, which
// is also the client id.
//
int64_t connection_create();
// This is to be called after a client disconnects. This removes the
// connection. On error, return an error message.
//
eng::string connection_delete(int64_t client_id);
// Get the current client_id for an actor_id.
// Returns 0 if the actor is not a connected actor.
//
int64_t connection_get_client(int64_t actor_id) const;
// Get the current actor_id for a client_id.
// Returns 0 if the client_id is not a connected client.
//
int64_t connection_get_actor(int64_t client_id) const;
// Add a redirect. On error, return an error message.
//
eng::string connection_redirect(int64_t client_id, int64_t actor_id);
// Close all connections.
//
// This is often useful after reloading a save game - the save contains
// the connection state!
//
void connection_close_all();
private:
////////////////////////////////////////////////////////////////////////////
//
// Invocation and scheduling.
//
////////////////////////////////////////////////////////////////////////////
// Add a thread to the scheduler queue.
//
void schedule(int64_t clk, int64_t thid, int64_t plid);
@@ -533,14 +558,21 @@ public:
public:
///////////////////////////////////////////////////////////
//
// difference transmission internals related to 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.
// Difference transmission entry point.
//
///////////////////////////////////////////////////////////
int64_t patch(StreamBuffer *sb, DebugCollector *dbc);
void diff(int64_t actor, bool full, World *master, StreamBuffer *sb);
///////////////////////////////////////////////////////////
//
// Difference transmission internals
//
///////////////////////////////////////////////////////////
util::IdVector get_visible_union(int64_t actor_id, World *master);
void patch_numbered_tables(StreamBuffer *sb, DebugCollector *dbc);
void diff_numbered_tables(lua_State *master, StreamBuffer *sb);
@@ -550,14 +582,6 @@ public:
void patch_tangible_classes(StreamBuffer *sb, DebugCollector *dbc);
void diff_tangible_classes(const IdVector &basis, lua_State *master, StreamBuffer *sb);
///////////////////////////////////////////////////////////
//
// Difference transmission internals
//
///////////////////////////////////////////////////////////
util::IdVector get_visible_union(int64_t actor_id, World *master);
int64_t patch_actor(StreamBuffer *sb, DebugCollector *dbc);
void diff_actor(int64_t actor_id, World *master, StreamBuffer *sb);
@@ -576,15 +600,6 @@ public:
void patch_globals(StreamBuffer *sb, DebugCollector *dbc);
void diff_globals(World *master, StreamBuffer *sb);
///////////////////////////////////////////////////////////
//
// Difference transmission entry point.
//
///////////////////////////////////////////////////////////
int64_t patch(StreamBuffer *sb, DebugCollector *dbc);
void diff(int64_t actor, bool full, World *master, StreamBuffer *sb);
public:
///////////////////////////////////////////////////////////
//
@@ -640,6 +655,13 @@ public:
void unnumber_lua_tables();
private:
///////////////////////////////////////////////////////////
//
// Instance Variables
//
///////////////////////////////////////////////////////////
// Type of model
WorldType world_type_;
@@ -692,9 +714,9 @@ private:
//
StreamBuffer snapshot_;
// Redirects.
// Connections. A Map from client_id to current actor ID.
//
Redirects redirects_;
std::map<int64_t, int64_t> connections_;
// Storage for wrapper_get_tangibles_near and wrapper_get_animation_queues.
// These hold results alive while the driver reads from the raw pointers.
@@ -713,7 +735,6 @@ private:
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);
friend int lfn_tangible_nopredict(lua_State *L);