2019-08-03 06:51:05 +00:00
/ *
2022-01-01 19:03:05 +00:00
* Copyright ( c ) 2019 - 2022 GeyserMC . http : //geysermc.org
2019-08-03 06:51:05 +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
* /
2021-11-20 23:29:46 +00:00
package org.geysermc.geyser.translator.protocol.java.entity.player ;
2019-08-03 06:51:05 +00:00
2020-05-29 19:11:38 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement ;
2021-11-13 03:44:15 +00:00
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket ;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket ;
2021-12-18 16:43:57 +00:00
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket ;
2019-10-09 18:39:38 +00:00
import com.nukkitx.math.vector.Vector3f ;
2021-06-06 15:58:03 +00:00
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData ;
2019-08-03 06:51:05 +00:00
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket ;
2020-03-24 04:24:17 +00:00
import com.nukkitx.protocol.bedrock.packet.RespawnPacket ;
2021-06-06 15:58:03 +00:00
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket ;
2021-11-20 21:34:30 +00:00
import org.geysermc.geyser.entity.EntityDefinitions ;
2021-12-18 16:43:57 +00:00
import org.geysermc.geyser.entity.type.Entity ;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity ;
2021-11-22 19:52:26 +00:00
import org.geysermc.geyser.session.GeyserSession ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.session.cache.TeleportCache ;
2021-12-18 16:43:57 +00:00
import org.geysermc.geyser.text.GeyserLocale ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.translator.protocol.PacketTranslator ;
import org.geysermc.geyser.translator.protocol.Translator ;
import org.geysermc.geyser.util.ChunkUtils ;
import org.geysermc.geyser.util.EntityUtils ;
2019-12-21 17:35:48 +00:00
2021-11-13 03:44:15 +00:00
@Translator ( packet = ClientboundPlayerPositionPacket . class )
2021-11-13 04:01:45 +00:00
public class JavaPlayerPositionTranslator extends PacketTranslator < ClientboundPlayerPositionPacket > {
2019-08-03 06:51:05 +00:00
@Override
2021-11-22 19:52:26 +00:00
public void translate ( GeyserSession session , ClientboundPlayerPositionPacket packet ) {
2019-08-03 06:51:05 +00:00
if ( ! session . isLoggedIn ( ) )
return ;
2021-12-18 16:43:57 +00:00
SessionPlayerEntity entity = session . getPlayerEntity ( ) ;
2021-01-04 00:06:20 +00:00
2019-08-10 00:15:06 +00:00
if ( ! session . isSpawned ( ) ) {
2021-12-18 16:43:57 +00:00
// The server sends an absolute teleport everytime the player is respawned
2020-05-26 03:35:26 +00:00
Vector3f pos = Vector3f . from ( packet . getX ( ) , packet . getY ( ) , packet . getZ ( ) ) ;
2020-02-15 23:39:34 +00:00
entity . setPosition ( pos ) ;
2021-11-18 03:02:38 +00:00
entity . setYaw ( packet . getYaw ( ) ) ;
entity . setPitch ( packet . getPitch ( ) ) ;
entity . setHeadYaw ( packet . getYaw ( ) ) ;
2019-12-27 11:29:46 +00:00
RespawnPacket respawnPacket = new RespawnPacket ( ) ;
2020-07-30 20:31:12 +00:00
respawnPacket . setRuntimeEntityId ( 0 ) ; // Bedrock server behavior
2020-07-25 14:38:00 +00:00
respawnPacket . setPosition ( entity . getPosition ( ) ) ;
2020-02-14 23:39:26 +00:00
respawnPacket . setState ( RespawnPacket . State . SERVER_READY ) ;
2020-05-05 15:51:43 +00:00
session . sendUpstreamPacket ( respawnPacket ) ;
2019-12-27 11:29:46 +00:00
2021-11-19 01:44:03 +00:00
entity . updateBedrockMetadata ( ) ;
2019-08-05 20:30:56 +00:00
2019-08-10 00:15:06 +00:00
MovePlayerPacket movePlayerPacket = new MovePlayerPacket ( ) ;
movePlayerPacket . setRuntimeEntityId ( entity . getGeyserId ( ) ) ;
2020-07-25 14:38:00 +00:00
movePlayerPacket . setPosition ( entity . getPosition ( ) ) ;
2019-10-09 18:39:38 +00:00
movePlayerPacket . setRotation ( Vector3f . from ( packet . getPitch ( ) , packet . getYaw ( ) , 0 ) ) ;
2020-07-30 20:31:12 +00:00
movePlayerPacket . setMode ( MovePlayerPacket . Mode . RESPAWN ) ;
2019-08-03 06:51:05 +00:00
2020-05-05 15:51:43 +00:00
session . sendUpstreamPacket ( movePlayerPacket ) ;
2019-08-10 00:15:06 +00:00
session . setSpawned ( true ) ;
2021-12-18 16:43:57 +00:00
// Make sure the player moves away from (0, 32767, 0) before accepting movement packets
session . setUnconfirmedTeleport ( new TeleportCache ( packet . getX ( ) , packet . getY ( ) , packet . getZ ( ) , packet . getPitch ( ) , packet . getYaw ( ) , packet . getTeleportId ( ) ) ) ;
2019-08-10 00:15:06 +00:00
2021-12-18 16:43:57 +00:00
acceptTeleport ( session , packet . getX ( ) , packet . getY ( ) , packet . getZ ( ) , packet . getYaw ( ) , packet . getPitch ( ) , packet . getTeleportId ( ) ) ;
2020-02-06 04:23:08 +00:00
2020-03-06 01:26:36 +00:00
ChunkUtils . updateChunkPosition ( session , pos . toInt ( ) ) ;
2022-01-30 16:14:51 +00:00
if ( session . getGeyser ( ) . getConfig ( ) . isDebugMode ( ) ) {
session . getGeyser ( ) . getLogger ( ) . debug ( GeyserLocale . getLocaleStringLog ( " geyser.entity.player.spawn " , packet . getX ( ) , packet . getY ( ) , packet . getZ ( ) ) ) ;
}
2019-09-16 01:25:16 +00:00
return ;
2019-08-10 00:15:06 +00:00
}
2022-01-30 16:14:51 +00:00
Entity vehicle ;
if ( packet . isDismountVehicle ( ) & & ( vehicle = session . getPlayerEntity ( ) . getVehicle ( ) ) ! = null ) {
2021-06-06 15:58:03 +00:00
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket ( ) ;
linkPacket . setEntityLink ( new EntityLinkData ( vehicle . getGeyserId ( ) , entity . getGeyserId ( ) , EntityLinkData . Type . REMOVE , false , false ) ) ;
session . sendUpstreamPacket ( linkPacket ) ;
2021-12-18 16:43:57 +00:00
vehicle . getPassengers ( ) . remove ( entity ) ;
session . getPlayerEntity ( ) . setVehicle ( null ) ;
EntityUtils . updateRiderRotationLock ( entity , null , false ) ;
EntityUtils . updateMountOffset ( entity , null , false , false , entity . getPassengers ( ) . size ( ) > 1 ) ;
entity . updateBedrockMetadata ( ) ;
2021-06-06 15:58:03 +00:00
}
2020-05-29 19:11:38 +00:00
// If coordinates are relative, then add to the existing coordinate
double newX = packet . getX ( ) +
( packet . getRelative ( ) . contains ( PositionElement . X ) ? entity . getPosition ( ) . getX ( ) : 0 ) ;
double newY = packet . getY ( ) +
2021-11-18 03:02:38 +00:00
( packet . getRelative ( ) . contains ( PositionElement . Y ) ? entity . getPosition ( ) . getY ( ) - EntityDefinitions . PLAYER . offset ( ) : 0 ) ;
2020-05-29 19:11:38 +00:00
double newZ = packet . getZ ( ) +
( packet . getRelative ( ) . contains ( PositionElement . Z ) ? entity . getPosition ( ) . getZ ( ) : 0 ) ;
2020-11-20 19:56:39 +00:00
float newPitch = packet . getPitch ( ) +
2020-05-29 19:11:38 +00:00
( packet . getRelative ( ) . contains ( PositionElement . PITCH ) ? entity . getBedrockRotation ( ) . getX ( ) : 0 ) ;
2020-11-20 19:56:39 +00:00
float newYaw = packet . getYaw ( ) +
2020-05-29 19:11:38 +00:00
( packet . getRelative ( ) . contains ( PositionElement . YAW ) ? entity . getBedrockRotation ( ) . getY ( ) : 0 ) ;
2021-12-18 16:43:57 +00:00
int id = packet . getTeleportId ( ) ;
2020-05-29 19:11:38 +00:00
2021-12-18 16:43:57 +00:00
session . getGeyser ( ) . getLogger ( ) . debug ( " Teleport ( " + id + " ) from " + entity . getPosition ( ) . getX ( ) + " " + ( entity . getPosition ( ) . getY ( ) - EntityDefinitions . PLAYER . offset ( ) ) + " " + entity . getPosition ( ) . getZ ( ) ) ;
2021-07-18 14:58:08 +00:00
2021-11-18 03:02:38 +00:00
Vector3f lastPlayerPosition = entity . getPosition ( ) . down ( EntityDefinitions . PLAYER . offset ( ) ) ;
2021-07-18 14:58:08 +00:00
float lastPlayerPitch = entity . getBedrockRotation ( ) . getX ( ) ;
Vector3f teleportDestination = Vector3f . from ( newX , newY , newZ ) ;
2021-11-18 03:02:38 +00:00
entity . moveAbsolute ( teleportDestination , newYaw , newPitch , true , true ) ;
2020-11-20 19:56:39 +00:00
2021-11-20 21:34:30 +00:00
session . getGeyser ( ) . getLogger ( ) . debug ( " to " + entity . getPosition ( ) . getX ( ) + " " + ( entity . getPosition ( ) . getY ( ) - EntityDefinitions . PLAYER . offset ( ) ) + " " + entity . getPosition ( ) . getZ ( ) ) ;
2021-07-18 14:58:08 +00:00
// Bedrock ignores teleports that are extremely close to the player's original position and orientation,
2021-12-18 16:43:57 +00:00
// so check if we need to cache the teleport
2021-07-18 14:58:08 +00:00
if ( lastPlayerPosition . distanceSquared ( teleportDestination ) < 0 . 001 & & Math . abs ( newPitch - lastPlayerPitch ) < 5 ) {
2021-12-18 16:43:57 +00:00
session . setUnconfirmedTeleport ( null ) ;
} else {
session . setUnconfirmedTeleport ( new TeleportCache ( newX , newY , newZ , newPitch , newYaw , id ) ) ;
2021-07-18 14:58:08 +00:00
}
2021-12-18 16:43:57 +00:00
acceptTeleport ( session , newX , newY , newZ , newYaw , newPitch , id ) ;
}
private void acceptTeleport ( GeyserSession session , double x , double y , double z , float yaw , float pitch , int id ) {
// Confirm the teleport when we receive it to match Java edition
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket ( id ) ;
session . sendDownstreamPacket ( teleportConfirmPacket ) ;
// Servers (especially ones like Hypixel) expect exact coordinates given back to them.
ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket ( false , x , y , z , yaw , pitch ) ;
session . sendDownstreamPacket ( positionPacket ) ;
2019-08-03 06:51:05 +00:00
}
}