worldport: re-claim our own body after a transfer
Leaving a battleground left the character unable to walk for the rest of the session. The `settle released` line named it: `WASD held by: control-lost`. vmangos takes control for the teleport (`SetClientControl(player, 0)`), so `Revoked` sets `control_lost` and parks the mover, and only a later `SMSG_CLIENT_CONTROL_UPDATE` with `allow_move = true` clears it. Nothing guarantees that packet, and nothing else clears the flag: the worldport arm replaces the pose and the settle releases, neither asks, and `seizing` at `wire_in.rs` wants `reseat`, which a worldport never sets. So the lock on the body we just left parked the body we came back as. A transfer is a mover change, so re-claim at the transfer's completion, with the ack, the way login does — the same teardown as the reference's `SetActiveMover` reset. `reseat` rides along so the existing seize path resets the outgoing mover's state. A possession is left alone: there the lock is the point. Compile-verified only — the live run is the test.
This commit is contained in:
@@ -105,6 +105,7 @@ pub(super) fn release_post_snap_hold(
|
||||
time: Res<Time>,
|
||||
mut last_counters: Local<Option<[usize; 6]>>,
|
||||
net_cmds: Option<Res<crate::net::NetCommands>>,
|
||||
self_guid: Option<Res<crate::net::SelfGuid>>,
|
||||
) {
|
||||
let Some(p) = progress else { return };
|
||||
// Residency counts only for the tile under the body. On a mismatch (the teleport's snap frame,
|
||||
@@ -149,10 +150,28 @@ pub(super) fn release_post_snap_hold(
|
||||
// this a character that comes out of a worldport unable to walk is a story, because nothing
|
||||
// else in the log says whether the hold is the settle, a lost mover, or a pending reseat.
|
||||
if was_settling && !player.settling {
|
||||
info!(
|
||||
"worldport: settle released — WASD held by: {}",
|
||||
player.movement_suppressors()
|
||||
);
|
||||
let held = player.movement_suppressors();
|
||||
info!("worldport: settle released — WASD held by: {held}");
|
||||
// A transfer is a mover change, and the server's revoke belonged to the body on the map we
|
||||
// left: vmangos takes control for the teleport (`SetClientControl(player, 0)`) and does not
|
||||
// promise the restore. Left set, `control_lost` parks the body for the rest of the session,
|
||||
// because nothing else clears it — the worldport arm replaces the pose and the settle
|
||||
// releases, and neither asks. Re-claim our own body here, at the transfer's completion and
|
||||
// with the ack, the way login does; the reference's `SetActiveMover` reset (`wire_in.rs`)
|
||||
// is the same teardown. A possession is left alone: there the lock is the point.
|
||||
if player.control_lost && player.foreign_mover.is_none() {
|
||||
if let (Some(net), Some(guid)) =
|
||||
(net_cmds.as_deref(), self_guid.as_deref().and_then(|g| g.0))
|
||||
{
|
||||
player.control_lost = false;
|
||||
player.reseat = true;
|
||||
super::move_trace::mover_claim("WORLDPORT", guid);
|
||||
let _ = net
|
||||
.0
|
||||
.send(crate::net::ClientCommand::SetActiveMover { guid });
|
||||
info!("worldport: re-claimed our own body after the transfer");
|
||||
}
|
||||
}
|
||||
}
|
||||
// The worldport ack, the reference's post-load `0xDC`, goes at either end of the hold: the
|
||||
// server keeps an unacked transfer out of world until logout.
|
||||
|
||||
Reference in New Issue
Block a user