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

@@ -11,6 +11,7 @@
class Client : public eng::opnew {
public:
int64_t client_id_;
int64_t actor_id_;
SharedChannel channel_;
UniqueWorld sync_;
@@ -44,7 +45,7 @@ public:
world_->expose_world_to_driver(wrapper_);
// Create the admin actor. Note: there isn't any 'init' function yet.
actor_id_ = world_->create_login_actor();
actor_id_ = world_->connection_create();
// Print out admin ID for debugging purposes.
util::dprint("Admin actor id = ", actor_id_);
@@ -73,12 +74,13 @@ public:
}
void delete_client(UniqueClient &client) {
util::dprint("Client closed: actor id=", client->actor_id_);
world_->disconnected(client->actor_id_);
util::dprint("Client closed: client_id=", client->client_id_, " actor_id=", client->actor_id_);
world_->connection_delete(client->client_id_);
client.reset();
}
void send_diffs(UniqueClient &client, bool full) {
client->actor_id_ = world_->connection_get_actor(client->client_id_);
StreamBuffer *sb = client->channel_->out();
sb->write_uint8(util::MSG_DIFF);
sb->write_uint32(0);
@@ -89,27 +91,6 @@ public:
sb->overwrite_int32(tw_1, tw_2 - tw_1);
}
void redirect(int64_t id1, int64_t id2) {
for (auto &client : clients_) {
if (client->actor_id_ == id1) {
bool ok = world_->redirected(id1, id2);
if (!ok) delete_client(client);
}
}
}
// Redirection is touchy: almost any world->invoke could
// call tangible.redirect. After that point, the world is
// relying on us not to control the wrong character.
void process_redirects() {
if (world_->have_redirects()) {
World::Redirects redirects = world_->fetch_redirects();
for (const auto &pair : redirects) {
redirect(pair.first, pair.second);
}
}
}
bool handle_invocation(UniqueClient &client) {
if (client == nullptr) return false;
StreamBuffer *sb = client->channel_->in();
@@ -131,18 +112,12 @@ public:
return false;
}
// If the user sent an invalid kind, log them out.
if (!Invocation::is_valid_network_kind(inv.kind())) {
delete_client(client);
return false;
}
// Acknowledge the invocation.
client->channel_->out()->write_uint8(util::MSG_ACK);
client->channel_->out()->write_uint32(0);
// Execute the invocation with the sync model.
client->sync_->invoke(inv);
client->sync_->invoke(0, inv);
client->async_diff_ = true;
// Process the invocation in the master model.
@@ -152,8 +127,7 @@ public:
// who may not know their new actor_id yet.
//
if (inv.actor() == client->actor_id_) {
world_->invoke(inv);
process_redirects();
world_->invoke(client->client_id_, inv);
}
return true;
}
@@ -210,7 +184,7 @@ public:
// come from the local command line. We just feed
// these directly into the master model.
for (const Invocation &inv : delayed_invocations_) {
world_->invoke(inv);
world_->invoke(0, inv);
}
delayed_invocations_.clear();
@@ -220,7 +194,8 @@ public:
if (chan == nullptr) break;
if (chan->port() == 8085) {
Client *client = new Client;
client->actor_id_ = world_->create_login_actor();
client->actor_id_ = world_->connection_create();
client->client_id_ = client->actor_id_;
// TODO: initialize the login actor on the master.
client->channel_ = std::move(chan);
client->async_diff_ = true;
@@ -229,7 +204,7 @@ public:
client->sync_.reset(new World(WORLD_TYPE_PREDICTIVE));
// This login actor is never used, it is just to preserve the invariant that
// the client model and the server synchronous model are identical.
client->sync_->create_login_actor();
client->sync_->connection_create();
clients_.emplace_back(client);
util::dprint("New client: actor id=", client->actor_id_);
} else if (chan->port() == 8080) {
@@ -241,7 +216,7 @@ public:
// If the clock has advanced far enough, tick the master model.
if (clock >= next_tick_) {
world_->invoke(Invocation(AccessKind::INVOKE_TICK, 0, 0, ""));
world_->invoke(0, Invocation(AccessKind::INVOKE_TICK, 0, 0, ""));
for (UniqueClient &client : clients_) {
client->async_diff_ = true;
}
@@ -249,11 +224,6 @@ public:
if (next_tick_ < clock + 0.3) next_tick_ = clock + 0.3;
}
// This handles any redirects triggered from the server command
// line or by the tick function.
process_redirects();
util::remove_nullptrs(clients_);
// Traverse all existing channels, process any communication.
for (UniqueClient &client : clients_) {
if (client->channel_->closed()) {