2019-09-14 01:12:36 +00:00
|
|
|
/*
|
2021-01-01 15:10:36 +00:00
|
|
|
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
2019-09-14 01:12:36 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2020-08-08 22:41:12 +00:00
|
|
|
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
2019-09-14 00:37:06 +00:00
|
|
|
|
2021-11-13 03:44:15 +00:00
|
|
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
|
|
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
|
|
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket;
|
2020-11-20 19:56:39 +00:00
|
|
|
import com.github.steveice10.packetlib.packet.Packet;
|
2020-05-04 06:06:08 +00:00
|
|
|
import com.nukkitx.math.vector.Vector3d;
|
2020-11-02 21:04:08 +00:00
|
|
|
import com.nukkitx.math.vector.Vector3f;
|
|
|
|
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
|
|
|
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
2020-06-27 22:27:00 +00:00
|
|
|
import org.geysermc.connector.common.ChatColor;
|
2021-11-18 03:02:38 +00:00
|
|
|
import org.geysermc.connector.entity.EntityDefinitions;
|
2021-07-18 14:58:08 +00:00
|
|
|
import org.geysermc.connector.entity.player.SessionPlayerEntity;
|
2019-09-14 00:37:06 +00:00
|
|
|
import org.geysermc.connector.network.session.GeyserSession;
|
|
|
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
2020-03-24 04:24:17 +00:00
|
|
|
import org.geysermc.connector.network.translators.Translator;
|
2019-09-14 00:37:06 +00:00
|
|
|
|
2020-03-24 04:24:17 +00:00
|
|
|
@Translator(packet = MovePlayerPacket.class)
|
2019-09-14 00:37:06 +00:00
|
|
|
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
|
2021-11-12 14:42:35 +00:00
|
|
|
/* The upper and lower bounds to check for the void floor that only exists in Bedrock. These are the constants for the overworld. */
|
|
|
|
private static final int BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y = -104;
|
|
|
|
private static final int BEDROCK_OVERWORLD_VOID_FLOOR_LOWER_Y = BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y + 2;
|
2019-10-16 02:47:28 +00:00
|
|
|
|
2019-09-14 00:37:06 +00:00
|
|
|
@Override
|
2021-08-30 17:55:01 +00:00
|
|
|
public void translate(GeyserSession session, MovePlayerPacket packet) {
|
2021-07-18 14:58:08 +00:00
|
|
|
SessionPlayerEntity entity = session.getPlayerEntity();
|
2021-01-04 00:06:20 +00:00
|
|
|
if (!session.isSpawned()) return;
|
2019-09-16 01:25:16 +00:00
|
|
|
|
2019-10-09 18:39:38 +00:00
|
|
|
if (!session.getUpstream().isInitialized()) {
|
|
|
|
MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket();
|
|
|
|
moveEntityBack.setRuntimeEntityId(entity.getGeyserId());
|
|
|
|
moveEntityBack.setPosition(entity.getPosition());
|
|
|
|
moveEntityBack.setRotation(entity.getBedrockRotation());
|
|
|
|
moveEntityBack.setTeleported(true);
|
|
|
|
moveEntityBack.setOnGround(true);
|
2020-05-05 15:51:43 +00:00
|
|
|
session.sendUpstreamPacketImmediately(moveEntityBack);
|
2019-10-09 18:39:38 +00:00
|
|
|
return;
|
2019-10-04 22:29:33 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 23:41:20 +00:00
|
|
|
session.setLastMovementTimestamp(System.currentTimeMillis());
|
2020-04-29 16:06:25 +00:00
|
|
|
|
2021-01-08 00:40:34 +00:00
|
|
|
// Send book update before the player moves
|
|
|
|
session.getBookEditCache().checkForSend();
|
|
|
|
|
2021-09-26 14:16:22 +00:00
|
|
|
if (!session.getTeleportMap().isEmpty()) {
|
2021-11-18 03:02:38 +00:00
|
|
|
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0));
|
2021-09-26 14:16:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-07-18 14:58:08 +00:00
|
|
|
// head yaw, pitch, head yaw
|
|
|
|
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
2021-11-18 03:02:38 +00:00
|
|
|
float yaw = packet.getRotation().getY();
|
|
|
|
float pitch = packet.getRotation().getX();
|
|
|
|
float headYaw = packet.getRotation().getY();
|
2021-07-18 14:58:08 +00:00
|
|
|
|
|
|
|
boolean positionChanged = !entity.getPosition().equals(packet.getPosition());
|
2021-11-18 03:02:38 +00:00
|
|
|
boolean rotationChanged = entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw;
|
2021-07-18 14:58:08 +00:00
|
|
|
|
|
|
|
// If only the pitch and yaw changed
|
|
|
|
// This isn't needed, but it makes the packets closer to vanilla
|
|
|
|
// It also means you can't "lag back" while only looking, in theory
|
|
|
|
if (!positionChanged && rotationChanged) {
|
2021-11-13 03:44:15 +00:00
|
|
|
ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(
|
2021-07-18 14:58:08 +00:00
|
|
|
packet.isOnGround(), packet.getRotation().getY(), packet.getRotation().getX());
|
|
|
|
|
2021-11-18 03:02:38 +00:00
|
|
|
entity.setYaw(yaw);
|
|
|
|
entity.setPitch(pitch);
|
|
|
|
entity.setHeadYaw(headYaw);
|
2021-07-18 14:58:08 +00:00
|
|
|
entity.setOnGround(packet.isOnGround());
|
|
|
|
|
|
|
|
session.sendDownstreamPacket(playerRotationPacket);
|
|
|
|
} else {
|
2021-09-10 01:27:38 +00:00
|
|
|
if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-26 14:16:22 +00:00
|
|
|
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
|
2021-09-22 01:06:07 +00:00
|
|
|
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
2021-09-10 01:20:25 +00:00
|
|
|
if (position != null) { // A null return value cancels the packet
|
2021-07-18 14:58:08 +00:00
|
|
|
Packet movePacket;
|
|
|
|
if (rotationChanged) {
|
|
|
|
// Send rotation updates as well
|
2021-11-13 03:44:15 +00:00
|
|
|
movePacket = new ServerboundMovePlayerPosRotPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ(),
|
2021-07-18 14:58:08 +00:00
|
|
|
packet.getRotation().getY(), packet.getRotation().getX());
|
2021-11-18 03:02:38 +00:00
|
|
|
entity.setYaw(yaw);
|
|
|
|
entity.setPitch(pitch);
|
|
|
|
entity.setHeadYaw(headYaw);
|
2021-07-18 14:58:08 +00:00
|
|
|
} else {
|
|
|
|
// Rotation did not change; don't send an update with rotation
|
2021-11-13 03:44:15 +00:00
|
|
|
movePacket = new ServerboundMovePlayerPosPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ());
|
2021-07-18 14:58:08 +00:00
|
|
|
}
|
2020-11-20 19:56:39 +00:00
|
|
|
|
2021-07-18 14:58:08 +00:00
|
|
|
// Compare positions here for void floor fix below before the player's position variable is set to the packet position
|
|
|
|
boolean notMovingUp = entity.getPosition().getY() >= packet.getPosition().getY();
|
|
|
|
|
|
|
|
entity.setPositionManual(packet.getPosition());
|
|
|
|
entity.setOnGround(packet.isOnGround());
|
|
|
|
|
|
|
|
// Send final movement changes
|
|
|
|
session.sendDownstreamPacket(movePacket);
|
|
|
|
|
|
|
|
if (notMovingUp) {
|
|
|
|
int floorY = position.getFloorY();
|
|
|
|
// If the client believes the world has extended height, then it also believes the void floor
|
|
|
|
// still exists, just at a lower spot
|
|
|
|
boolean extendedWorld = session.getChunkCache().isExtendedHeight();
|
|
|
|
if (floorY <= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_LOWER_Y : -38)
|
|
|
|
&& floorY >= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y : -40)) {
|
|
|
|
// Work around there being a floor at the bottom of the world and teleport the player below it
|
|
|
|
// Moving from below to above the void floor works fine
|
|
|
|
entity.setPosition(entity.getPosition().sub(0, 4f, 0));
|
|
|
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
|
|
|
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
|
|
|
movePlayerPacket.setPosition(entity.getPosition());
|
|
|
|
movePlayerPacket.setRotation(entity.getBedrockRotation());
|
|
|
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
|
|
|
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
|
|
|
session.sendUpstreamPacket(movePlayerPacket);
|
2021-01-01 01:05:00 +00:00
|
|
|
}
|
2020-11-20 19:56:39 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-10 01:20:25 +00:00
|
|
|
} else {
|
|
|
|
// Not a valid move
|
|
|
|
session.getConnector().getLogger().debug("Recalculating position...");
|
|
|
|
session.getCollisionManager().recalculatePosition();
|
2020-11-20 19:56:39 +00:00
|
|
|
}
|
2019-09-16 01:25:16 +00:00
|
|
|
}
|
|
|
|
|
2020-09-02 04:39:06 +00:00
|
|
|
// Move parrots to match if applicable
|
|
|
|
if (entity.getLeftParrot() != null) {
|
2021-11-18 03:02:38 +00:00
|
|
|
entity.getLeftParrot().moveAbsolute(entity.getPosition(), entity.getYaw(), entity.getPitch(), entity.getHeadYaw(), true, false);
|
2020-09-02 04:39:06 +00:00
|
|
|
}
|
|
|
|
if (entity.getRightParrot() != null) {
|
2021-11-18 03:02:38 +00:00
|
|
|
entity.getRightParrot().moveAbsolute(entity.getPosition(), entity.getYaw(), entity.getPitch(), entity.getHeadYaw(), true, false);
|
2020-09-02 04:39:06 +00:00
|
|
|
}
|
2020-11-02 21:04:08 +00:00
|
|
|
}
|
|
|
|
|
2021-09-26 14:16:22 +00:00
|
|
|
private boolean isInvalidNumber(float val) {
|
|
|
|
return Float.isNaN(val) || Float.isInfinite(val);
|
|
|
|
}
|
2019-09-16 01:25:16 +00:00
|
|
|
|
2021-09-26 14:16:22 +00:00
|
|
|
private boolean isValidMove(GeyserSession session, Vector3f currentPosition, Vector3f newPosition) {
|
|
|
|
if (isInvalidNumber(newPosition.getX()) || isInvalidNumber(newPosition.getY()) || isInvalidNumber(newPosition.getZ())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (currentPosition.distanceSquared(newPosition) > 300) {
|
2019-10-16 02:47:28 +00:00
|
|
|
session.getConnector().getLogger().debug(ChatColor.RED + session.getName() + " moved too quickly." +
|
2019-09-16 01:25:16 +00:00
|
|
|
" current position: " + currentPosition + ", new position: " + newPosition);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-14 00:37:06 +00:00
|
|
|
}
|
2020-11-20 19:56:39 +00:00
|
|
|
|