Handle player teleports properly (#389)

* Handle player teleports properly

Co-authored-by: ForceUpdate1 <mneuhaus44@gmail.com>

* impl teleport cache

* impl teleport cache

* removed debugs

* Cleanup

Co-authored-by: ForceUpdate1 <mneuhaus44@gmail.com>
This commit is contained in:
rtm516 2020-04-29 17:06:25 +01:00 committed by GitHub
parent 82433f8078
commit bea070395f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 114 additions and 35 deletions

View file

@ -158,11 +158,11 @@ public class Entity {
session.getUpstream().sendPacket(moveEntityPacket);
}
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) {
moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround);
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) {
moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround, teleported);
}
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround) {
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
setPosition(position);
setRotation(rotation);
@ -171,7 +171,7 @@ public class Entity {
moveEntityPacket.setPosition(position);
moveEntityPacket.setRotation(getBedrockRotation());
moveEntityPacket.setOnGround(isOnGround);
moveEntityPacket.setTeleported(false);
moveEntityPacket.setTeleported(teleported);
session.getUpstream().sendPacket(moveEntityPacket);
}

View file

@ -83,7 +83,7 @@ public class PlayerEntity extends LivingEntity {
addPlayerPacket.setUsername(username);
addPlayerPacket.setRuntimeEntityId(geyserId);
addPlayerPacket.setUniqueEntityId(geyserId);
addPlayerPacket.setPosition(position);
addPlayerPacket.setPosition(position.clone().sub(0, EntityType.PLAYER.getOffset(), 0));
addPlayerPacket.setRotation(getBedrockRotation());
addPlayerPacket.setMotion(motion);
addPlayerPacket.setHand(hand);
@ -130,7 +130,7 @@ public class PlayerEntity extends LivingEntity {
}
@Override
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround) {
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
setPosition(position);
setRotation(rotation);
@ -139,7 +139,11 @@ public class PlayerEntity extends LivingEntity {
movePlayerPacket.setPosition(this.position);
movePlayerPacket.setRotation(getBedrockRotation());
movePlayerPacket.setOnGround(isOnGround);
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
movePlayerPacket.setMode(teleported ? MovePlayerPacket.Mode.TELEPORT : MovePlayerPacket.Mode.NORMAL);
if (teleported) {
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN);
}
session.getUpstream().sendPacket(movePlayerPacket);
}

View file

@ -30,8 +30,9 @@ import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsExcepti
import com.github.steveice10.mc.auth.exception.request.RequestException;
import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
import com.github.steveice10.packetlib.Client;
import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet;
@ -83,8 +84,10 @@ public class GeyserSession implements CommandSender {
private final UpstreamSession upstream;
private RemoteServer remoteServer;
private Client downstream;
@Setter private AuthData authData;
@Setter private BedrockClientData clientData;
@Setter
private AuthData authData;
@Setter
private BedrockClientData clientData;
private PlayerEntity playerEntity;
private PlayerInventory inventory;
@ -94,6 +97,8 @@ public class GeyserSession implements CommandSender {
private InventoryCache inventoryCache;
private ScoreboardCache scoreboardCache;
private WindowCache windowCache;
@Setter
private TeleportCache teleportCache;
private DataCache<Packet> javaPacketCache;
@ -439,4 +444,19 @@ public class GeyserSession implements CommandSender {
// startGamePacket.setMovementServerAuthoritative(true);
upstream.sendPacket(startGamePacket);
}
public boolean confirmTeleport(Vector3f position) {
if (teleportCache != null) {
if (!teleportCache.canConfirm(position)) {
GeyserConnector.getInstance().getLogger().debug("Unconfirmed Teleport " + teleportCache.getTeleportConfirmId()
+ " Ignore movement " + position + " expected " + teleportCache);
return false;
}
int teleportId = teleportCache.getTeleportConfirmId();
teleportCache = null;
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(teleportId);
getDownstream().getSession().send(teleportConfirmPacket);
}
return true;
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.session.cache;
import com.nukkitx.math.vector.Vector3f;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class TeleportCache {
private static final double ERROR = 0.2;
private static final double ERROR_Y = 0.5;
private double x, y, z;
private int teleportConfirmId;
public boolean canConfirm(Vector3f position) {
return (Math.abs(this.x - position.getX()) < ERROR &&
Math.abs(this.y - position.getY()) < ERROR_Y &&
Math.abs(this.z - position.getZ()) < ERROR);
}
}

View file

@ -34,7 +34,6 @@ import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
import com.nukkitx.math.GenericMath;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
@ -59,23 +58,31 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
return;
}
// We need to parse the float as a string since casting a float to a double causes us to
// lose precision and thus, causes players to get stuck when walking near walls
double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset();
if (packet.isOnGround()) javaY = Math.ceil(javaY * 2) / 2;
Vector3f position = Vector3f.from(Double.parseDouble(Float.toString(packet.getPosition().getX())), javaY,
Double.parseDouble(Float.toString(packet.getPosition().getZ())));
if(!session.confirmTeleport(position)){
return;
}
if (!isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) {
session.getConnector().getLogger().debug("Recalculating position...");
recalculatePosition(session, entity, entity.getPosition());
return;
}
double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset();
if (packet.isOnGround()) javaY = Math.ceil(javaY * 2) / 2;
// We need to parse the float as a string since casting a float to a double causes us to
// lose precision and thus, causes players to get stuck when walking near walls
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
packet.isOnGround(), Double.parseDouble(Float.toString(packet.getPosition().getX())), javaY, Double.parseDouble(Float.toString(packet.getPosition().getZ())), packet.getRotation().getY(), packet.getRotation().getX()
packet.isOnGround(), position.getX(), position.getY(), position.getZ(), packet.getRotation().getY(), packet.getRotation().getX()
);
// head yaw, pitch, head yaw
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
entity.setPosition(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0));
entity.setPosition(position);
entity.setRotation(rotation);
/*

View file

@ -44,6 +44,6 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
}
if (entity == null) return;
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround());
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround(), false);
}
}

View file

@ -25,13 +25,6 @@
package org.geysermc.connector.network.translators.java.entity.player;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.ChunkUtils;
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
import com.nukkitx.math.vector.Vector3f;
@ -40,13 +33,20 @@ import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.session.cache.TeleportCache;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.ChunkUtils;
@Translator(packet = ServerPlayerPositionRotationPacket.class)
public class JavaPlayerPositionRotationTranslator extends PacketTranslator<ServerPlayerPositionRotationPacket> {
@Override
public void translate(ServerPlayerPositionRotationPacket packet, GeyserSession session) {
Entity entity = session.getPlayerEntity();
PlayerEntity entity = session.getPlayerEntity();
if (entity == null)
return;
@ -94,18 +94,21 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
}
session.setSpawned(true);
if (!packet.getRelative().isEmpty()) {
session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId()));
entity.moveRelative(session, packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ(), packet.getYaw(), packet.getPitch(), true);
} else {
double xDis = Math.abs(entity.getPosition().getX() - packet.getX());
double yDis = entity.getPosition().getY() - packet.getY();
double zDis = Math.abs(entity.getPosition().getZ() - packet.getZ());
if (xDis > 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5) {
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), true);
session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId()));
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), true, true);
} else {
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
session.getDownstream().getSession().send(teleportConfirmPacket);
}
}
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
session.getDownstream().getSession().send(teleportConfirmPacket);
}
}

View file

@ -25,23 +25,21 @@
package org.geysermc.connector.network.translators.java.entity.spawn;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.SkinUtils;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket;
import com.nukkitx.math.vector.Vector3f;
@Translator(packet = ServerSpawnPlayerPacket.class)
public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlayerPacket> {
@Override
public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
Vector3f position = Vector3f.from(packet.getX(), packet.getY() - EntityType.PLAYER.getOffset(), packet.getZ());
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getYaw());
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUuid());