Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 14:30:17 +01:00
Merge remote-tracking branch 'upstream/master' into client-vehicle
Dieser Commit ist enthalten in:
Commit
727604f82c
@ -47,6 +47,7 @@ import java.util.function.BiConsumer;
|
|||||||
* metadata translators needed to translate the properties sent from the server. The translators are structured in such
|
* metadata translators needed to translate the properties sent from the server. The translators are structured in such
|
||||||
* a way that inserting a new one (for example in version updates) is convenient.
|
* a way that inserting a new one (for example in version updates) is convenient.
|
||||||
*
|
*
|
||||||
|
* @param identifier the Bedrock identifier of this entity
|
||||||
* @param <T> the entity type this definition represents
|
* @param <T> the entity type this definition represents
|
||||||
*/
|
*/
|
||||||
public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, EntityType entityType, String identifier,
|
public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, EntityType entityType, String identifier,
|
||||||
|
@ -27,16 +27,19 @@ package org.geysermc.geyser.entity.type.player;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.math.vector.Vector2f;
|
import org.cloudburstmc.math.vector.Vector2f;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
|
import org.geysermc.geyser.level.BedrockDimension;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.AttributeUtils;
|
import org.geysermc.geyser.util.AttributeUtils;
|
||||||
import org.geysermc.geyser.util.DimensionUtils;
|
import org.geysermc.geyser.util.DimensionUtils;
|
||||||
@ -81,6 +84,15 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
|
|
||||||
private int lastAirSupply = getMaxAir();
|
private int lastAirSupply = getMaxAir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if our position is currently out-of-sync with the Java server
|
||||||
|
* due to our workaround for the void floor
|
||||||
|
* <p>
|
||||||
|
* Must be reset when dying, switching worlds, or being teleported out of the void
|
||||||
|
*/
|
||||||
|
@Getter @Setter
|
||||||
|
private boolean voidPositionDesynched;
|
||||||
|
|
||||||
public SessionPlayerEntity(GeyserSession session) {
|
public SessionPlayerEntity(GeyserSession session) {
|
||||||
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
||||||
|
|
||||||
@ -99,10 +111,25 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||||
|
if (voidPositionDesynched) {
|
||||||
|
if (!isBelowVoidFloor()) {
|
||||||
|
voidPositionDesynched = false; // No need to fix our offset; we've been moved
|
||||||
|
}
|
||||||
|
}
|
||||||
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||||
session.getCollisionManager().updatePlayerBoundingBox(this.position.down(definition.offset()));
|
session.getCollisionManager().updatePlayerBoundingBox(this.position.down(definition.offset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||||
|
if (voidPositionDesynched) {
|
||||||
|
if (!isBelowVoidFloor()) {
|
||||||
|
voidPositionDesynched = false; // No need to fix our offset; we've been moved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPosition(Vector3f position) {
|
public void setPosition(Vector3f position) {
|
||||||
if (valid) { // Don't update during session init
|
if (valid) { // Don't update during session init
|
||||||
@ -237,6 +264,9 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
} else {
|
} else {
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're either respawning or switching worlds, either way, we are no longer desynched
|
||||||
|
this.setVoidPositionDesynched(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -299,4 +329,48 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
public void setVehicleJumpStrength(int vehicleJumpStrength) {
|
public void setVehicleJumpStrength(int vehicleJumpStrength) {
|
||||||
this.vehicleJumpStrength = MathUtils.constrain(vehicleJumpStrength, 0, 100);
|
this.vehicleJumpStrength = MathUtils.constrain(vehicleJumpStrength, 0, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isBelowVoidFloor() {
|
||||||
|
return position.getY() < voidFloorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int voidFloorPosition() {
|
||||||
|
// The void floor is offset about 40 blocks below the bottom of the world
|
||||||
|
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
||||||
|
return bedrockDimension.minY() - 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method handles teleporting the player below or above the Bedrock void floor.
|
||||||
|
* The Java server should never see this desync as we adjust the position that we send to it
|
||||||
|
*
|
||||||
|
* @param up in which direction to teleport - true to resync our position, or false to be
|
||||||
|
* teleported below the void floor.
|
||||||
|
*/
|
||||||
|
public void teleportVoidFloorFix(boolean up) {
|
||||||
|
// Safety to avoid double teleports
|
||||||
|
if ((voidPositionDesynched && !up) || (!voidPositionDesynched && up)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
Vector3f newPosition = this.getPosition();
|
||||||
|
if (up) {
|
||||||
|
newPosition = newPosition.up(4f);
|
||||||
|
voidPositionDesynched = false;
|
||||||
|
} else {
|
||||||
|
newPosition = newPosition.down(4f);
|
||||||
|
voidPositionDesynched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setPositionManual(newPosition);
|
||||||
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
|
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||||
|
movePlayerPacket.setPosition(newPosition);
|
||||||
|
movePlayerPacket.setRotation(getBedrockRotation());
|
||||||
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
||||||
|
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
||||||
|
session.sendUpstreamPacketImmediately(movePlayerPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ public class FilledMapItem extends MapItem {
|
|||||||
switch (mapColor) {
|
switch (mapColor) {
|
||||||
case 3830373 -> builder.damage(3); // Ocean Monument
|
case 3830373 -> builder.damage(3); // Ocean Monument
|
||||||
case 5393476 -> builder.damage(4); // Woodland explorer
|
case 5393476 -> builder.damage(4); // Woodland explorer
|
||||||
|
case 12741452 -> builder.damage(14); // Trial Chamber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,8 @@ public enum BedrockMapIcon {
|
|||||||
ICON_SNOWY_VILLAGE(MapIconType.SNOWY_VILLAGE, 20),
|
ICON_SNOWY_VILLAGE(MapIconType.SNOWY_VILLAGE, 20),
|
||||||
ICON_TAIGA_VILLAGE(MapIconType.TAIGA_VILLAGE, 21),
|
ICON_TAIGA_VILLAGE(MapIconType.TAIGA_VILLAGE, 21),
|
||||||
ICON_JUNGLE_TEMPLE(MapIconType.JUNGLE_TEMPLE, 22),
|
ICON_JUNGLE_TEMPLE(MapIconType.JUNGLE_TEMPLE, 22),
|
||||||
ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23);
|
ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23),
|
||||||
|
ICON_TRIAL_CHAMBERS(MapIconType.TRIAL_CHAMBERS, 24);
|
||||||
|
|
||||||
private static final BedrockMapIcon[] VALUES = values();
|
private static final BedrockMapIcon[] VALUES = values();
|
||||||
|
|
||||||
|
@ -418,13 +418,15 @@ public final class ItemTranslator {
|
|||||||
if (components != null) {
|
if (components != null) {
|
||||||
// ItemStack#getHoverName as of 1.20.5
|
// ItemStack#getHoverName as of 1.20.5
|
||||||
Component customName = components.get(DataComponentType.CUSTOM_NAME);
|
Component customName = components.get(DataComponentType.CUSTOM_NAME);
|
||||||
if (customName == null) {
|
|
||||||
customName = components.get(DataComponentType.ITEM_NAME);
|
|
||||||
}
|
|
||||||
if (customName != null) {
|
if (customName != null) {
|
||||||
// Get the translated name and prefix it with a reset char
|
|
||||||
return MessageTranslator.convertMessage(customName, session.locale());
|
return MessageTranslator.convertMessage(customName, session.locale());
|
||||||
}
|
}
|
||||||
|
customName = components.get(DataComponentType.ITEM_NAME);
|
||||||
|
if (customName != null) {
|
||||||
|
// Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition
|
||||||
|
// behavior as of 1.21
|
||||||
|
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapping.hasTranslation()) {
|
if (mapping.hasTranslation()) {
|
||||||
|
@ -107,7 +107,7 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
|
|||||||
bedrockNbt.put("isMovable", (byte) 1);
|
bedrockNbt.put("isMovable", (byte) 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable NbtMap spawnData) {
|
private static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable NbtMap spawnData) {
|
||||||
if (spawnData == null) {
|
if (spawnData == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -27,22 +27,31 @@ package org.geysermc.geyser.translator.level.block.entity;
|
|||||||
|
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.level.block.type.BlockState;
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||||
|
|
||||||
@BlockEntity(type = BlockEntityType.TRIAL_SPAWNER)
|
@BlockEntity(type = BlockEntityType.TRIAL_SPAWNER)
|
||||||
public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator {
|
public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
// Note that it would appear block entity updates don't include the NBT, but we do need it on chunk load.
|
||||||
@Override
|
@Override
|
||||||
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
|
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
|
||||||
if (javaNbt == null) {
|
if (javaNbt == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trial spawners have "spawn_data" instead of "SpawnData"
|
NbtMap entityData = javaNbt.getCompound("spawn_data").getCompound("entity");
|
||||||
SpawnerBlockEntityTranslator.translateSpawnData(bedrockNbt, javaNbt.getCompound("spawn_data", null));
|
if (entityData.isEmpty()) {
|
||||||
|
return;
|
||||||
// Because trial spawners don't exist on bedrock yet
|
}
|
||||||
bedrockNbt.put("id", "MobSpawner");
|
NbtMapBuilder spawnData = NbtMap.builder();
|
||||||
|
EntityDefinition<?> definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityData.getString("id"));
|
||||||
|
if (definition != null) {
|
||||||
|
spawnData.putString("TypeId", definition.identifier());
|
||||||
|
}
|
||||||
|
spawnData.putInt("Weight", entityData.getInt("Size", 1)); // ??? presumably since these are the only other two extra attributes
|
||||||
|
bedrockNbt.putCompound("spawn_data", spawnData.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,19 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket;
|
|
||||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
|
||||||
import org.cloudburstmc.math.vector.Vector3d;
|
import org.cloudburstmc.math.vector.Vector3d;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||||
import org.geysermc.geyser.level.BedrockDimension;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.ChatColor;
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
|
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket;
|
||||||
|
|
||||||
@Translator(packet = MovePlayerPacket.class)
|
@Translator(packet = MovePlayerPacket.class)
|
||||||
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
|
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
|
||||||
@ -93,29 +92,42 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
||||||
if (position != null) { // A null return value cancels the packet
|
if (position != null) { // A null return value cancels the packet
|
||||||
boolean onGround = packet.isOnGround();
|
boolean onGround = packet.isOnGround();
|
||||||
|
boolean isBelowVoid = entity.isVoidPositionDesynched();
|
||||||
|
|
||||||
boolean teleportThroughVoidFloor;
|
boolean teleportThroughVoidFloor, mustResyncPosition;
|
||||||
// Compare positions here for void floor fix below before the player's position variable is set to the packet position
|
// Compare positions here for void floor fix below before the player's position variable is set to the packet position
|
||||||
if (entity.getPosition().getY() >= packet.getPosition().getY()) {
|
if (entity.getPosition().getY() >= packet.getPosition().getY() && !isBelowVoid) {
|
||||||
int floorY = position.getFloorY();
|
int floorY = position.getFloorY();
|
||||||
// The void floor is offset about 40 blocks below the bottom of the world
|
int voidFloorLocation = entity.voidFloorPosition();
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1) && floorY >= voidFloorLocation;
|
||||||
int voidFloorLocation = bedrockDimension.minY() - 40;
|
|
||||||
teleportThroughVoidFloor = floorY <= (voidFloorLocation + 2) && floorY >= voidFloorLocation;
|
|
||||||
if (teleportThroughVoidFloor) {
|
|
||||||
// https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground.
|
|
||||||
onGround = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
teleportThroughVoidFloor = false;
|
teleportThroughVoidFloor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (teleportThroughVoidFloor || isBelowVoid) {
|
||||||
|
// https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground.
|
||||||
|
onGround = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBelowVoid) {
|
||||||
|
int floorY = position.getFloorY();
|
||||||
|
int voidFloorLocation = entity.voidFloorPosition();
|
||||||
|
mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1;
|
||||||
|
} else {
|
||||||
|
mustResyncPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double yPosition = position.getY();
|
||||||
|
if (entity.isVoidPositionDesynched()) { // not using the cached variable on purpose
|
||||||
|
yPosition += 4; // We are de-synched since we had to teleport below the void floor.
|
||||||
|
}
|
||||||
|
|
||||||
Packet movePacket;
|
Packet movePacket;
|
||||||
if (rotationChanged) {
|
if (rotationChanged) {
|
||||||
// Send rotation updates as well
|
// Send rotation updates as well
|
||||||
movePacket = new ServerboundMovePlayerPosRotPacket(
|
movePacket = new ServerboundMovePlayerPosRotPacket(
|
||||||
onGround,
|
onGround,
|
||||||
position.getX(), position.getY(), position.getZ(),
|
position.getX(), yPosition, position.getZ(),
|
||||||
yaw, pitch
|
yaw, pitch
|
||||||
);
|
);
|
||||||
entity.setYaw(yaw);
|
entity.setYaw(yaw);
|
||||||
@ -123,7 +135,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
entity.setHeadYaw(headYaw);
|
entity.setHeadYaw(headYaw);
|
||||||
} else {
|
} else {
|
||||||
// Rotation did not change; don't send an update with rotation
|
// Rotation did not change; don't send an update with rotation
|
||||||
movePacket = new ServerboundMovePlayerPosPacket(onGround, position.getX(), position.getY(), position.getZ());
|
movePacket = new ServerboundMovePlayerPosPacket(onGround, position.getX(), yPosition, position.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.setPositionManual(packet.getPosition());
|
entity.setPositionManual(packet.getPosition());
|
||||||
@ -133,16 +145,9 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
session.sendDownstreamGamePacket(movePacket);
|
session.sendDownstreamGamePacket(movePacket);
|
||||||
|
|
||||||
if (teleportThroughVoidFloor) {
|
if (teleportThroughVoidFloor) {
|
||||||
// Work around there being a floor at the bottom of the world and teleport the player below it
|
entity.teleportVoidFloorFix(false);
|
||||||
// Moving from below to above the void floor works fine
|
} else if (mustResyncPosition) {
|
||||||
entity.setPosition(entity.getPosition().sub(0, 4f, 0));
|
entity.teleportVoidFloorFix(true);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getSkullCache().updateVisibleSkulls();
|
session.getSkullCache().updateVisibleSkulls();
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren