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

@@ -152,12 +152,20 @@ void Tangible::serialize(StreamBuffer *sb) {
anim_queue_.serialize(sb);
id_player_pool_.serialize(sb);
print_buffer_.serialize(sb);
sb->write_bool(can_be_controlled_);
sb->write_bool(is_controlled_);
sb->write_bool(force_disconnect_);
sb->write_bool(delete_on_disconnect_);
}
void Tangible::deserialize(StreamBuffer *sb) {
anim_queue_.deserialize(sb);
id_player_pool_.deserialize(sb);
print_buffer_.deserialize(sb);
can_be_controlled_ = sb->read_bool();
is_controlled_ = sb->read_bool();
force_disconnect_ = sb->read_bool();
delete_on_disconnect_ = sb->read_bool();
update_plane_item();
}
@@ -294,13 +302,7 @@ void World::get_near(int64_t player_id, float radius, bool exclude_nowhere, bool
get_near(scan, into);
}
World::Redirects World::fetch_redirects() {
World::Redirects result = std::move(redirects_);
redirects_.clear();
return result;
}
int64_t World::create_login_actor() {
int64_t World::connection_create() {
assert(stack_is_clear());
int64_t id = id_global_pool_.get_one();
{
@@ -327,13 +329,18 @@ int64_t World::create_login_actor() {
spawn(LS, id, id, func, 0, false);
}
}
connections_.emplace(id, id);
if (is_authoritative()) {
run_scheduled_threads();
}
return id;
}
void World::disconnected(int64_t actor_id) {
eng::string World::connection_delete(int64_t client_id) {
auto iter = connections_.find(client_id);
if (iter == connections_.end()) return "no such client id";
int64_t actor_id = iter->second;
connections_.erase(iter);
Tangible *tan = tangible_get(actor_id);
assert(tan != nullptr);
assert(tan->is_controlled_);
@@ -343,16 +350,39 @@ void World::disconnected(int64_t actor_id) {
util::dprintf("Deleted actor: %lld\n", actor_id);
tangible_delete(actor_id);
}
return "";
}
bool World::redirected(int64_t actor_id, int64_t new_id) {
disconnected(actor_id);
Tangible *tan = tangible_get(new_id);
if (tan && (tan->can_be_controlled_) && (!tan->is_controlled_)) {
tan->is_controlled_ = true;
return true;
} else {
return false;
int64_t World::connection_get_actor(int64_t client_id) const {
auto iter = connections_.find(client_id);
if (iter == connections_.end()) return 0;
return iter->second;
}
int64_t World::connection_get_client(int64_t actor_id) const {
for (const auto &pair : connections_) {
if (pair.second == actor_id) return pair.first;
}
return 0;
}
eng::string World::connection_redirect(int64_t client_id, int64_t new_id) {
Tangible *newtan = tangible_get(new_id);
if (newtan == nullptr) return "no such target tangible";
if (newtan->is_controlled_) return "target tangible is already controlled";
if (!newtan->can_be_controlled_) return "target tangible is not a potential actor";
eng::string delresult = connection_delete(client_id);
if (!delresult.empty()) return delresult;
newtan->is_controlled_ = true;
newtan->force_disconnect_ = false;
connections_[client_id] = new_id;
return "";
}
void World::connection_close_all() {
while (!connections_.empty()) {
int64_t client_id = connections_.begin()->first;
connection_delete(client_id);
}
}
@@ -564,6 +594,7 @@ bool World::rebuild_sourcedb(int64_t actor_id) {
if (actor_id != 0) lthread_prints_to_actor(actor_id);
}
}
source_db_.rebuild_funcnames();
lthread_prints_ << "Compiled " << successes << " modules successfully." << std::endl;
if (failures > 0) {
lthread_prints_ << "Compiled " << failures << " modules with errors." << std::endl;
@@ -743,7 +774,13 @@ HttpServerResponse World::http_serve(const HttpParser &request) {
return response;
}
void World::invoke(const Invocation &inv) {
void World::invoke(int64_t client_id, const Invocation &inv) {
if (client_id != 0) {
int64_t actor_id = connection_get_actor(client_id);
if (actor_id == 0) return;
if (inv.actor() != actor_id) return;
if (!Invocation::is_valid_network_kind(inv.kind())) return;
}
switch (inv.kind()) {
case AccessKind::INVOKE_LUA_CALL:
invoke_lua_call(inv.actor(), inv.place(), inv.datapack());
@@ -838,7 +875,7 @@ bool World::spawn(LuaCoreStack &LS0, int64_t actor_id, int64_t place_id, LuaSlot
LS.rawset(thinfo, "isnew", true);
LS.rawset(thinfo, "useppool", true);
LS.rawset(thinfo, "print", print);
// Store the thread into place's thread table.
LS.rawget(threads, mt, "threads");
if (!LS.istable(threads)) {
@@ -1230,7 +1267,6 @@ const eng::string &World::get_global(const eng::string &gvar) {
void World::serialize(StreamBuffer *sb) {
assert(stack_is_clear());
assert(redirects_.empty());
// int64_t wc0 = sb->total_writes();
lua_snap_.serialize(sb);
id_global_pool_.serialize(sb);
@@ -1242,12 +1278,16 @@ void World::serialize(StreamBuffer *sb) {
sb->write_int64(p.first);
p.second->serialize(sb);
}
sb->write_uint32(connections_.size());
for (const auto &p : connections_) {
sb->write_int64(p.first);
sb->write_int64(p.second);
}
assert(stack_is_clear());
}
void World::deserialize(StreamBuffer *sb) {
assert(stack_is_clear());
redirects_.clear();
lua_snap_.deserialize(sb);
id_global_pool_.deserialize(sb);
clock_ = sb->read_int64();
@@ -1259,7 +1299,7 @@ void World::deserialize(StreamBuffer *sb) {
}
// Deserialize tangibles.
size_t ntan = sb->read_uint32();
for (size_t i = 0; i < ntan; i++) {
for (uint32_t i = 0; i < ntan; i++) {
int64_t id = sb->read_int64();
UniqueTangible &t = tangibles_[id];
if (t == nullptr) {
@@ -1269,6 +1309,14 @@ void World::deserialize(StreamBuffer *sb) {
}
t->deserialize(sb);
}
// Deserialize connections.
connections_.clear();
uint32_t nconn = sb->read_uint32();
for (uint32_t i = 0; i < nconn; i++) {
int64_t client_id = sb->read_int64();
int64_t actor_id = sb->read_int64();
connections_.emplace(client_id, actor_id);
}
// Delete tangibles that didn't get deserialized.
for (auto iter = tangibles_.begin(); iter != tangibles_.end(); ) {
if (iter->second->plane_item_.id() == 0) {
@@ -1277,8 +1325,6 @@ void World::deserialize(StreamBuffer *sb) {
++iter;
}
}
// After a save and load, http requests no longer should exist
abort_all_http_requests(425, "http requests aborted by loading a save game");
assert(stack_is_clear());
}