mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 22:45:04 +01:00
Horses are still weird, but boats are mostly working
This commit is contained in:
parent
2025a2dc3a
commit
774d3670c5
10 changed files with 138 additions and 76 deletions
|
@ -701,9 +701,4 @@ public class Entity implements GeyserEntity {
|
|||
packet.setData(data);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Entity> @Nullable I as(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this) ? (I) this : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -758,7 +758,6 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
|||
|
||||
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(javaPos.getX(), javaPos.getY(), javaPos.getZ(), rotation.getX(), rotation.getY());
|
||||
vehicle.getSession().sendDownstreamPacket(moveVehiclePacket);
|
||||
vehicle.getSession().setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
protected double getGravity() {
|
||||
|
|
|
@ -524,12 +524,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
@Setter
|
||||
private boolean placedBucket;
|
||||
|
||||
/**
|
||||
* Used to send a ServerboundMoveVehiclePacket for every PlayerInputPacket after idling on a boat/horse for more than 100ms
|
||||
*/
|
||||
@Setter
|
||||
private long lastVehicleMoveTimestamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Counts how many ticks have occurred since an arm animation started.
|
||||
* -1 means there is no active arm swing; -2 means an arm swing will start in a tick.
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.session.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -37,6 +39,10 @@ public final class InputCache {
|
|||
private ServerboundPlayerInputPacket inputPacket = new ServerboundPlayerInputPacket(false, false, false, false, false, false, false);
|
||||
private boolean lastHorizontalCollision;
|
||||
private int ticksSinceLastMovePacket;
|
||||
@Getter @Setter
|
||||
private int jumpingTicks;
|
||||
@Getter @Setter
|
||||
private float jumpScale;
|
||||
|
||||
public InputCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
@ -61,6 +67,10 @@ public final class InputCache {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean wasJumping() {
|
||||
return this.inputPacket.isJump();
|
||||
}
|
||||
|
||||
public void markPositionPacketSent() {
|
||||
this.ticksSinceLastMovePacket = 0;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class TeleportCache {
|
|||
/**
|
||||
* How many move packets the teleport can be unconfirmed for before it gets resent to the client
|
||||
*/
|
||||
private static final int RESEND_THRESHOLD = 5;
|
||||
private static final int RESEND_THRESHOLD = 20; // Make it one full second with auth input
|
||||
|
||||
private final double x, y, z;
|
||||
private final float pitch, yaw;
|
||||
|
|
|
@ -42,17 +42,15 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) {
|
||||
session.setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
|
||||
Entity ridingEntity = session.getPlayerEntity().getVehicle();
|
||||
if (ridingEntity != null && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), false)) {
|
||||
Vector3f position = Vector3f.from(ridingEntity.getPosition().getX(), packet.getPosition().getY(),
|
||||
ridingEntity.getPosition().getZ());
|
||||
if (ridingEntity instanceof BoatEntity) {
|
||||
// Undo the changes usually applied to the boat
|
||||
ridingEntity.as(BoatEntity.class)
|
||||
.moveAbsoluteWithoutAdjustments(position, ridingEntity.getYaw(),
|
||||
ridingEntity.isOnGround(), true);
|
||||
// ridingEntity.as(BoatEntity.class)
|
||||
// .moveAbsoluteWithoutAdjustments(position, ridingEntity.getYaw(),
|
||||
// ridingEntity.isOnGround(), true);
|
||||
} else {
|
||||
// This doesn't work if teleported is false
|
||||
ridingEntity.moveAbsolute(position,
|
||||
|
|
|
@ -44,47 +44,6 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, PlayerInputPacket packet) {
|
||||
// ServerboundPlayerInputPacket playerInputPacket = new ServerboundPlayerInputPacket(
|
||||
// packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
|
||||
// );
|
||||
//
|
||||
// session.sendDownstreamGamePacket(playerInputPacket);
|
||||
|
||||
session.getPlayerEntity().setVehicleInput(packet.getInputMotion());
|
||||
|
||||
// Bedrock only sends movement vehicle packets while moving
|
||||
// This allows horses to take damage while standing on magma
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
boolean sendMovement = false;
|
||||
if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) {
|
||||
sendMovement = vehicle.isOnGround();
|
||||
} else if (vehicle instanceof BoatEntity) {
|
||||
if (vehicle.getPassengers().size() == 1) {
|
||||
// The player is the only rider
|
||||
sendMovement = true;
|
||||
} else {
|
||||
// Check if the player is the front rider
|
||||
if (session.getPlayerEntity().isRidingInFront()) {
|
||||
sendMovement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sendMovement) {
|
||||
long timeSinceVehicleMove = System.currentTimeMillis() - session.getLastVehicleMoveTimestamp();
|
||||
if (timeSinceVehicleMove >= 100) {
|
||||
Vector3f vehiclePosition = vehicle.getPosition();
|
||||
|
||||
if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) {
|
||||
// Remove some Y position to prevents boats flying up
|
||||
vehiclePosition = vehiclePosition.down(vehicle.getDefinition().offset());
|
||||
}
|
||||
|
||||
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(
|
||||
vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(),
|
||||
vehicle.getYaw() - 90, vehicle.getPitch()
|
||||
);
|
||||
session.sendDownstreamGamePacket(moveVehiclePacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.level.physics.CollisionResult;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
|
@ -48,17 +47,17 @@ public final class BedrockMovePlayerTranslator {
|
|||
SessionPlayerEntity entity = session.getPlayerEntity();
|
||||
if (!session.isSpawned()) return;
|
||||
|
||||
// Ignore movement packets until Bedrock's position matches the teleported position
|
||||
if (session.getUnconfirmedTeleport() != null) {
|
||||
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean actualPositionChanged = !entity.getPosition().equals(packet.getPosition());
|
||||
|
||||
if (actualPositionChanged) {
|
||||
// Send book update before the player moves
|
||||
session.getBookEditCache().checkForSend();
|
||||
|
||||
// Ignore movement packets until Bedrock's position matches the teleported position
|
||||
if (session.getUnconfirmedTeleport() != null) {
|
||||
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.getBedPosition() != null) {
|
||||
|
@ -72,9 +71,11 @@ public final class BedrockMovePlayerTranslator {
|
|||
float pitch = packet.getRotation().getX();
|
||||
float headYaw = packet.getRotation().getY();
|
||||
|
||||
// shouldSendPositionReminder also increments a tick counter, so make sure it's always called.
|
||||
boolean positionChanged = session.getInputCache().shouldSendPositionReminder() || actualPositionChanged;
|
||||
boolean rotationChanged = entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw;
|
||||
boolean hasVehicle = entity.getVehicle() != null;
|
||||
|
||||
// shouldSendPositionReminder also increments a tick counter, so make sure it's always called unless the player is on a vehicle.
|
||||
boolean positionChanged = !hasVehicle && session.getInputCache().shouldSendPositionReminder() || actualPositionChanged;
|
||||
boolean rotationChanged = hasVehicle || (entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw);
|
||||
|
||||
if (session.getLookBackScheduledFuture() != null) {
|
||||
// Resend the rotation if it was changed by Geyser
|
||||
|
@ -99,12 +100,6 @@ public final class BedrockMovePlayerTranslator {
|
|||
|
||||
session.sendDownstreamGamePacket(playerRotationPacket);
|
||||
} else if (positionChanged) {
|
||||
// World border collision will be handled by client vehicle
|
||||
if (!(entity.getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled())
|
||||
&& session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
|
||||
CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT));
|
||||
if (result != null) { // A null return value cancels the packet
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector2f;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||
|
@ -36,19 +37,25 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.BoatEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
|
@ -57,13 +64,17 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.Serv
|
|||
import java.util.Set;
|
||||
|
||||
@Translator(packet = PlayerAuthInputPacket.class)
|
||||
public class BedrockPlayerAuthInputTranslator extends PacketTranslator<PlayerAuthInputPacket> {
|
||||
public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<PlayerAuthInputPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
|
||||
SessionPlayerEntity entity = session.getPlayerEntity();
|
||||
|
||||
boolean wasJumping = session.getInputCache().wasJumping();
|
||||
session.getInputCache().processInputs(packet);
|
||||
|
||||
processVehicleInput(session, packet, wasJumping);
|
||||
|
||||
BedrockMovePlayerTranslator.translate(session, packet);
|
||||
|
||||
Set<PlayerAuthInputData> inputData = packet.getInputData();
|
||||
|
@ -202,4 +213,94 @@ public class BedrockPlayerAuthInputTranslator extends PacketTranslator<PlayerAut
|
|||
session.getGeyser().getLogger().error("Unhandled item use transaction type!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void processVehicleInput(GeyserSession session, PlayerAuthInputPacket packet, boolean wasJumping) {
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
if (vehicle == null) {
|
||||
return;
|
||||
}
|
||||
if (vehicle instanceof ClientVehicle) {
|
||||
session.getPlayerEntity().setVehicleInput(packet.getAnalogMoveVector());
|
||||
}
|
||||
|
||||
boolean sendMovement = false;
|
||||
if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) {
|
||||
sendMovement = vehicle.isOnGround();
|
||||
} else if (vehicle instanceof BoatEntity) {
|
||||
if (vehicle.getPassengers().size() == 1) {
|
||||
// The player is the only rider
|
||||
sendMovement = true;
|
||||
} else {
|
||||
// Check if the player is the front rider
|
||||
if (session.getPlayerEntity().isRidingInFront()) {
|
||||
sendMovement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vehicle instanceof AbstractHorseEntity) {
|
||||
// Behavior verified as of Java Edition 1.21.3
|
||||
int currentJumpingTicks = session.getInputCache().getJumpingTicks();
|
||||
if (currentJumpingTicks < 0) {
|
||||
session.getInputCache().setJumpingTicks(++currentJumpingTicks);
|
||||
if (currentJumpingTicks == 0) {
|
||||
session.getPlayerEntity().setVehicleJumpStrength(0);
|
||||
}
|
||||
}
|
||||
|
||||
boolean holdingJump = packet.getInputData().contains(PlayerAuthInputData.JUMPING);
|
||||
if (wasJumping && !holdingJump) {
|
||||
// Jump released
|
||||
// Yes, I'm fairly certain that entity ID is correct.
|
||||
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(),
|
||||
PlayerState.START_HORSE_JUMP, MathUtils.floor(session.getInputCache().getJumpScale() * 100f)));
|
||||
session.getInputCache().setJumpingTicks(-10);
|
||||
} else if (!wasJumping && holdingJump) {
|
||||
session.getInputCache().setJumpingTicks(0);
|
||||
session.getInputCache().setJumpScale(0);
|
||||
} else if (holdingJump) {
|
||||
session.getInputCache().setJumpingTicks(++currentJumpingTicks);
|
||||
if (currentJumpingTicks < 10) {
|
||||
session.getInputCache().setJumpScale(session.getInputCache().getJumpScale() * 0.1F);
|
||||
} else {
|
||||
session.getInputCache().setJumpScale(0.8f + 2.0f / (currentJumpingTicks - 9) * 0.1f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
session.getInputCache().setJumpScale(0);
|
||||
}
|
||||
|
||||
if (sendMovement) {
|
||||
Vector3f vehiclePosition = packet.getPosition();
|
||||
Vector2f vehicleRotation = packet.getVehicleRotation();
|
||||
if (vehicleRotation == null) {
|
||||
return; // If the client just got in or out of a vehicle for example.
|
||||
}
|
||||
|
||||
if (session.getWorldBorder().isPassingIntoBorderBoundaries(vehiclePosition, false)) {
|
||||
Vector3f position = vehicle.getPosition();
|
||||
if (vehicle instanceof BoatEntity boat) {
|
||||
// Undo the changes usually applied to the boat
|
||||
boat.moveAbsoluteWithoutAdjustments(position, vehicle.getYaw(), vehicle.isOnGround(), true);
|
||||
} else {
|
||||
// This doesn't work if teleported is false
|
||||
vehicle.moveAbsolute(position,
|
||||
vehicle.getYaw(), vehicle.getPitch(), vehicle.getHeadYaw(),
|
||||
vehicle.isOnGround(), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) {
|
||||
// Remove some Y position to prevents boats flying up
|
||||
vehiclePosition = vehiclePosition.down(vehicle.getDefinition().offset());
|
||||
}
|
||||
|
||||
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(
|
||||
vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(),
|
||||
vehicleRotation.getY() - 90, vehiclePosition.getX() // TODO I wonder if this is related to the horse spinning bugs...
|
||||
);
|
||||
session.sendDownstreamGamePacket(moveVehiclePacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,17 @@ public class MathUtils {
|
|||
return floatNumber > truncated ? truncated + 1 : truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the given float to the previous whole number
|
||||
*
|
||||
* @param floatNumber Float to round
|
||||
* @return Rounded number
|
||||
*/
|
||||
public static int floor(float floatNumber) {
|
||||
int truncated = (int) floatNumber;
|
||||
return floatNumber < truncated ? truncated - 1 : truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* If number is greater than the max, set it to max, and if number is lower than low, set it to low.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue