Entity: workaround teleport client bug #4394 by despawning and respawning the entity (#4870)

this is a sucky solution but it works well enough for this scenario.

From my research it appears that while the client-side MovementInterpolator is active on the client and hasn't yet reached its target, any teleport sent during the lerp will get overridden by the lerp.
This appears to last 3-4 ticks (about 150-200 ms) which explains why this can be reproduced by stopping movement just before the ender pearl lands (human reaction times would make the reproduction unreliable otherwise).

Things to note:
- All entities are affected by this bug.
- MovePlayerPacket appears not to have the problem, but we can't use it because it doesn't work for non-players.
- MoveActorAbsolute and MoveActorDelta are both handled by the same code and will have the same lerping bug.

This is the cleanest solution I could come up with.
This commit is contained in:
Dylan T 2022-04-08 23:12:01 +01:00 committed by GitHub
parent 1aee5b1ed8
commit d1dfbd95e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -768,17 +768,29 @@ abstract class Entity{
}
protected function broadcastMovement(bool $teleport = false) : void{
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
$this->id,
$this->getOffsetPosition($this->location),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw,
(
($teleport ? MoveActorAbsolutePacket::FLAG_TELEPORT : 0) |
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
)
)]);
if($teleport){
//TODO: HACK! workaround for https://github.com/pmmp/PocketMine-MP/issues/4394
//this happens because MoveActor*Packet doesn't clear interpolation targets on the client, so the entity
//snaps to the teleport position, but then lerps back to the original position if a normal movement for the
//entity was recently broadcasted. This can be seen with players throwing ender pearls.
//TODO: remove this if the bug ever gets fixed (lol)
foreach($this->hasSpawned as $player){
$this->despawnFrom($player);
$this->spawnTo($player);
}
}else{
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
$this->id,
$this->getOffsetPosition($this->location),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw,
(
//TODO: if the above hack for #4394 gets removed, we should be setting FLAG_TELEPORT here
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
)
)]);
}
}
protected function broadcastMotion() : void{