diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java index 7b5178cfc..9e56ba830 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java @@ -6,6 +6,7 @@ import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -33,6 +34,7 @@ import org.valkyrienskies.core.api.ships.properties.ShipTransform; import org.valkyrienskies.mod.common.entity.ShipMountedToData; import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.EntityDragger; import org.valkyrienskies.mod.common.util.EntityDraggingInformation; import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @@ -106,6 +108,50 @@ private void originalCheckInside(final AABBd aABB) { private void preGetEyePosition(final float partialTicks, final CallbackInfoReturnable cir) { final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(Entity.class.cast(this), partialTicks); if (shipMountedToData == null) { + if (Entity.class.cast(this) instanceof final ServerPlayer sPlayer && sPlayer instanceof final IEntityDraggingInformationProvider dragProvider) { + if (dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip() && dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { + final Ship shipDraggedBy = VSGameUtilsKt.getAllShips(level).getById(dragProvider.getDraggingInformation().getLastShipStoodOn()); + if (shipDraggedBy != null) { + final Vector3dc worldPos = shipDraggedBy.getShipToWorld().transformPosition(dragProvider.getDraggingInformation().getServerRelativePlayerPosition(), new Vector3d()); + cir.setReturnValue(new Vec3(worldPos.x(), worldPos.y(), worldPos.z())); + } + } + } + return; + } + final LoadedShip shipMountedTo = shipMountedToData.getShipMountedTo(); + + final ShipTransform shipTransform; + if (shipMountedTo instanceof ClientShip) { + shipTransform = ((ClientShip) shipMountedTo).getRenderTransform(); + } else { + shipTransform = shipMountedTo.getShipTransform(); + } + final Vector3dc basePos = shipTransform.getShipToWorldMatrix() + .transformPosition(shipMountedToData.getMountPosInShip(), new Vector3d()); + final Vector3dc eyeRelativePos = shipTransform.getShipCoordinatesToWorldCoordinatesRotation().transform( + new Vector3d(0.0, getEyeHeight(), 0.0) + ); + final Vec3 newEyePos = VectorConversionsMCKt.toMinecraft(basePos.add(eyeRelativePos, new Vector3d())); + cir.setReturnValue(newEyePos); + } + + /** + * @reason Needed for players to pick blocks correctly when mounted to a ship + */ + @Inject(method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"), cancellable = true) + private void preGetEyePositionServer(final CallbackInfoReturnable cir) { + final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(Entity.class.cast(this), null); + if (shipMountedToData == null) { + if (Entity.class.cast(this) instanceof final ServerPlayer sPlayer && sPlayer instanceof final IEntityDraggingInformationProvider dragProvider) { + if (dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip() && dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { + final Ship shipDraggedBy = VSGameUtilsKt.getAllShips(level).getById(dragProvider.getDraggingInformation().getLastShipStoodOn()); + if (shipDraggedBy != null) { + final Vector3dc worldPos = shipDraggedBy.getShipToWorld().transformPosition(dragProvider.getDraggingInformation().getServerRelativePlayerPosition(), new Vector3d()); + cir.setReturnValue(new Vec3(worldPos.x(), worldPos.y(), worldPos.z())); + } + } + } return; } final LoadedShip shipMountedTo = shipMountedToData.getShipMountedTo(); @@ -132,6 +178,31 @@ private void preGetEyePosition(final float partialTicks, final CallbackInfoRetur private void preCalculateViewVector(final float xRot, final float yRot, final CallbackInfoReturnable cir) { final LoadedShip shipMountedTo = VSGameUtilsKt.getShipMountedTo(Entity.class.cast(this)); if (shipMountedTo == null) { + if (Entity.class.cast(this) instanceof final ServerPlayer sPlayer && sPlayer instanceof final IEntityDraggingInformationProvider dragProvider) { + if (dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip() && dragProvider.getDraggingInformation().getServerRelativePlayerYaw() != null) { + final Ship shipDraggedBy = VSGameUtilsKt.getAllShips(level).getById(dragProvider.getDraggingInformation().getLastShipStoodOn()); + if (shipDraggedBy != null) { + final float realYRot = (float) EntityDragger.INSTANCE.serversideEyeRotationOrDefault(sPlayer, yRot); + final float f = xRot * (float) (Math.PI / 180.0); + final float g = -realYRot * (float) (Math.PI / 180.0); + final float h = Mth.cos(g); + final float i = Mth.sin(g); + final float j = Mth.cos(f); + final float k = Mth.sin(f); + final Vector3dc originalViewVector = new Vector3d(i * j, -k, h * j); + + final ShipTransform shipTransform; + if (shipDraggedBy instanceof ClientShip) { + shipTransform = ((ClientShip) shipDraggedBy).getRenderTransform(); + } else { + shipTransform = shipDraggedBy.getShipTransform(); + } + final Vec3 newViewVector = VectorConversionsMCKt.toMinecraft( + shipTransform.getShipCoordinatesToWorldCoordinatesRotation().transform(originalViewVector, new Vector3d())); + cir.setReturnValue(newViewVector); + } + } + } return; } final float f = xRot * (float) (Math.PI / 180.0); @@ -183,6 +254,9 @@ private void preCalculateViewVector(final float xRot, final float yRot, final Ca @Shadow public abstract EntityType getType(); + @Shadow + private float yRot; + @Override @NotNull public EntityDraggingInformation getDraggingInformation() { diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/distance_replace/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/distance_replace/MixinEntity.java index 5a55a93bf..ceac1c34d 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/distance_replace/MixinEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/distance_replace/MixinEntity.java @@ -1,6 +1,5 @@ package org.valkyrienskies.mod.mixin.feature.distance_replace; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; @@ -9,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.valkyrienskies.mod.common.VSGameUtilsKt; -import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; /** * Replaces all distance checks to include ships diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinEntity.java index 23f7b2c19..e850694f2 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinEntity.java @@ -3,8 +3,6 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import java.util.Random; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.BlockParticleOption; import net.minecraft.core.particles.ParticleTypes; @@ -30,7 +28,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import org.valkyrienskies.core.api.ships.ClientShip; import org.valkyrienskies.core.api.ships.Ship; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.util.EntityDraggingInformation; diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLivingEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLivingEntity.java index 705cc9fc4..b8335b20c 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLivingEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLivingEntity.java @@ -15,7 +15,6 @@ import org.valkyrienskies.mod.common.util.EntityDraggingInformation; import org.valkyrienskies.mod.common.util.EntityLerper; import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; -import org.valkyrienskies.mod.util.LoggingKt; @Mixin(LivingEntity.class) public abstract class MixinLivingEntity extends Entity { @@ -24,6 +23,10 @@ public MixinLivingEntity(EntityType entityType, Level level) { super(entityType, level); } + /** + * @author Tomato + * @reason Adjusted lerping for entities being dragged by ships. + */ @Inject( method = "aiStep", at = @At(value = "HEAD") diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLocalPlayer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLocalPlayer.java index 7c43b5d22..8bca04f60 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLocalPlayer.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLocalPlayer.java @@ -12,6 +12,7 @@ import org.joml.Vector3d; import org.joml.Vector3dc; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.valkyrienskies.core.api.ships.ClientShip; import org.valkyrienskies.mod.common.VSGameUtilsKt; @@ -23,10 +24,17 @@ @Mixin(LocalPlayer.class) public abstract class MixinLocalPlayer extends Entity implements IEntityDraggingInformationProvider { + @Shadow + public abstract float getViewYRot(float f); + public MixinLocalPlayer(EntityType entityType, Level level) { super(entityType, level); } + /** + * @author Tomato + * @reason Intercept client -> server player position sending to send our own data. + */ @WrapOperation(method = "sendPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V")) private void wrapSendPosition(ClientPacketListener instance, Packet arg, Operation original) { if (getDraggingInformation().isEntityBeingDraggedByAShip()) { @@ -36,9 +44,9 @@ private void wrapSendPosition(ClientPacketListener instance, Packet arg, Oper Vector3dc relativePosition = ship.getWorldToShip().transformPosition( VectorConversionsMCKt.toJOML(getEyePosition()), new Vector3d()); - double relativeYaw = EntityLerper.INSTANCE.yawToShip(ship, getYHeadRot()); + double relativeYaw = EntityLerper.INSTANCE.yawToShip(ship, getViewYRot(1f)); - PacketPlayerShipMotion packet = new PacketPlayerShipMotion(getId(), relativePosition.x(), relativePosition.y(), relativePosition.z(), relativeYaw); + PacketPlayerShipMotion packet = new PacketPlayerShipMotion(ship.getId(), relativePosition.x(), relativePosition.y(), relativePosition.z(), relativeYaw); ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().sendToServer(packet); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinServerEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinServerEntity.java index 53705d57b..296c7151f 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinServerEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinServerEntity.java @@ -1,7 +1,5 @@ package org.valkyrienskies.mod.mixin.feature.entity_collision; -import static org.valkyrienskies.mod.common.util.VectorConversionsMCKt.toJOML; - import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import java.util.function.Consumer; @@ -12,7 +10,6 @@ import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import org.joml.Vector3d; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; @@ -44,6 +41,10 @@ public class MixinServerEntity { @Final private static Logger LOGGER; + /** + * @author Tomato + * @reason Intercept entity motion packets to send our own data, then cancel the original packet. + */ @WrapOperation( method = "sendChanges", at = @At( @@ -63,14 +64,6 @@ private void wrapBroadcastAccept(Consumer instance, Object t, Operation or Vector3d position = ship.getWorldToShip().transformPosition(new Vector3d(entity.getX(), entity.getY(), entity.getZ())); Vector3d motion = ship.getTransform().transformDirectionNoScalingFromWorldToShip(new Vector3d(entity.getDeltaMovement().x(), entity.getDeltaMovement().y(), entity.getDeltaMovement().z()), new Vector3d()); -// Vector3d entityLookYawOnly = new Vector3d(Math.sin(-Math.toRadians(entity.getYRot())), 0.0, Math.cos(-Math.toRadians(entity.getYRot()))); -// Vector3d newLookIdeal = ship.getTransform().getShipToWorld().transformDirection(entityLookYawOnly); -// -//// Get the X and Y rotation from [newLookIdeal] -// double newXRot = Math.asin(-newLookIdeal.y()); -// double xRotCos = Math.cos(newXRot); -// double newYRot = -Math.atan2(newLookIdeal.x() / xRotCos, newLookIdeal.z() / xRotCos); - double yaw; if (!(t instanceof ClientboundRotateHeadPacket)) { yaw = EntityLerper.INSTANCE.yawToShip(ship, entity.getYRot()); diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/screen_distance_check/MixinScreenHandler.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/screen_distance_check/MixinScreenHandler.java index 97ede99d6..8a7e524ec 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/screen_distance_check/MixinScreenHandler.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/screen_distance_check/MixinScreenHandler.java @@ -2,10 +2,12 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.EntityDragger; import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; @Mixin(AbstractContainerMenu.class) @@ -23,17 +25,8 @@ public class MixinScreenHandler { ) private static double includeShipsInDistanceCheck( final Player receiver, final double x, final double y, final double z) { - double realX = x; - double realY = y; - double realZ = z; - if (receiver instanceof IEntityDraggingInformationProvider dragProvider && dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip()) { - if (dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { - realX = dragProvider.getDraggingInformation().getServerRelativePlayerPosition().x(); - realY = dragProvider.getDraggingInformation().getServerRelativePlayerPosition().y(); - realZ = dragProvider.getDraggingInformation().getServerRelativePlayerPosition().z(); - } - } - return VSGameUtilsKt.squaredDistanceToInclShips(receiver, realX, realY, realZ); + final Vec3 eye = EntityDragger.INSTANCE.serversideEyePosition(receiver); + return VSGameUtilsKt.squaredDistanceToInclShips(receiver, eye.x, eye.y, eye.z); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/reachentityattributes/MixinReachEntityAttributes.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/reachentityattributes/MixinReachEntityAttributes.java index e00474ce9..913b6ae78 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/reachentityattributes/MixinReachEntityAttributes.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/reachentityattributes/MixinReachEntityAttributes.java @@ -13,8 +13,7 @@ import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Shadow; import org.valkyrienskies.mod.common.VSGameUtilsKt; -import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; -import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; +import org.valkyrienskies.mod.common.util.EntityDragger; @Pseudo @Mixin(ReachEntityAttributes.class) @@ -34,12 +33,7 @@ public static List getPlayersWithinReach(final Predicate viewerP for (final Player player : world.players()) { if (viewerPredicate.test(player)) { final var reach = getReachDistance(player, baseReachDistance); - Vec3 eye = player.getEyePosition(); - if (player instanceof IEntityDraggingInformationProvider dragProvider && dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip()) { - if (dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { - eye = VectorConversionsMCKt.toMinecraft(dragProvider.getDraggingInformation().getServerRelativePlayerPosition()); - } - } + final Vec3 eye = EntityDragger.INSTANCE.serversideEyePosition(player); if (VSGameUtilsKt.squaredDistanceBetweenInclShips(world, x + 0.5, y + 0.5, z + 0.5, eye.x, eye.y, eye.z) <= (reach * reach)) { playersWithinReach.add(player); } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/PlayerUtil.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/PlayerUtil.kt index a246a2bb7..4f4df009e 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/PlayerUtil.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/PlayerUtil.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.level.Level import net.minecraft.world.phys.Vec3 import org.valkyrienskies.core.api.ships.LoadedShip +import org.valkyrienskies.mod.common.util.EntityDragger.serversideEyeRotationOrDefault import org.valkyrienskies.mod.common.util.toJOML import org.valkyrienskies.mod.common.util.toMinecraft import org.valkyrienskies.mod.mixin.accessors.entity.EntityAccessor @@ -38,8 +39,9 @@ object PlayerUtil { val yaw = -atan2(direction.x, direction.z) val pitch = -atan2(direction.y, sqrt((direction.x * direction.x) + (direction.z * direction.z))) - player.yRot = (yaw * (180 / Math.PI)).toFloat() + player.yRot = player.serversideEyeRotationOrDefault(yaw * (180 / Math.PI)).toFloat() player.yHeadRot = player.yRot + player.xRot = (pitch * (180 / Math.PI)).toFloat() (player as EntityAccessor).setPosNoUpdates(position.toMinecraft()) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt index ca01ab0a3..da71f01c0 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt @@ -41,6 +41,7 @@ import org.valkyrienskies.core.util.expand import org.valkyrienskies.mod.common.entity.ShipMountedToData import org.valkyrienskies.mod.common.entity.ShipMountedToDataProvider import org.valkyrienskies.mod.common.util.DimensionIdProvider +import org.valkyrienskies.mod.common.util.EntityDragger.serversideEyePosition import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider import org.valkyrienskies.mod.common.util.MinecraftPlayer import org.valkyrienskies.mod.common.util.set @@ -120,17 +121,8 @@ val Player.playerWrapper get() = (this as PlayerDuck).vs_getPlayer() * Like [Entity.squaredDistanceTo] except the destination is transformed into world coordinates if it is a ship */ fun Entity.squaredDistanceToInclShips(x: Double, y: Double, z: Double): Double { - var xEntity = this.x - var yEntity = this.y - var zEntity = this.z - if (this is ServerPlayer && this is IEntityDraggingInformationProvider && this.draggingInformation.isEntityBeingDraggedByAShip()) { - if (this.draggingInformation.serverRelativePlayerPosition != null) { - xEntity = this.draggingInformation.serverRelativePlayerPosition!!.x() - yEntity = this.draggingInformation.serverRelativePlayerPosition!!.y() - zEntity = this.draggingInformation.serverRelativePlayerPosition!!.z() - } - } - return level.squaredDistanceBetweenInclShips(x, y, z, xEntity, yEntity, zEntity) + val eyePos = this.serversideEyePosition() + return level.squaredDistanceBetweenInclShips(x, y, z, eyePos.x, eyePos.y - 1.0, eyePos.z) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketMobShipRotation.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketMobShipRotation.kt index d4feebff2..1baed8791 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketMobShipRotation.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketMobShipRotation.kt @@ -2,4 +2,7 @@ package org.valkyrienskies.mod.common.networking import org.valkyrienskies.core.impl.networking.simple.SimplePacket +/** + * This packet is used in place of [net.minecraft.network.protocol.game.ClientboundRotateHeadPacket] to update the head rotation of a mob being dragged by a ship. + */ data class PacketMobShipRotation(val entityID: Int, val shipID: Long, val yaw: Double): SimplePacket diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketPlayerShipMotion.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketPlayerShipMotion.kt index d9c2ab973..8c9fce295 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketPlayerShipMotion.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketPlayerShipMotion.kt @@ -2,4 +2,8 @@ package org.valkyrienskies.mod.common.networking import org.valkyrienskies.core.impl.networking.simple.SimplePacket +/** + * This packet is used to update the player's relative position and yaw rotation while being dragged by a ship, alongside + * [net.minecraft.network.protocol.game.ServerboundMovePlayerPacket]. + */ data class PacketPlayerShipMotion(val shipID: Long, val x: Double, val y: Double, val z: Double, val yRot: Double): SimplePacket diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt index a407165c1..f5a9669a5 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft import net.minecraft.client.player.LocalPlayer import net.minecraft.core.Registry import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerPlayer import org.joml.Vector3d import org.valkyrienskies.core.api.ships.LoadedServerShip @@ -17,6 +18,7 @@ import org.valkyrienskies.mod.common.shipObjectWorld import org.valkyrienskies.mod.common.util.EntityLerper import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider import org.valkyrienskies.mod.common.util.MinecraftPlayer +import org.valkyrienskies.mod.common.util.toMinecraft import org.valkyrienskies.mod.common.vsCore object VSGamePackets { @@ -130,8 +132,18 @@ object VSGamePackets { val player = (iPlayer as MinecraftPlayer).player as ServerPlayer if (player is IEntityDraggingInformationProvider) { - player.draggingInformation.relativePositionOnShip = Vector3d(motion.x, motion.y, motion.z) - player.draggingInformation.relativeYawOnShip = motion.yRot + if (player.draggingInformation.lastShipStoodOn == null || player.draggingInformation.lastShipStoodOn != motion.shipID) { + player.draggingInformation.lastShipStoodOn = motion.shipID + } + player.draggingInformation.serverRelativePlayerPosition = Vector3d(motion.x, motion.y, motion.z) + if (player.level != null) { + val sLevel = (player.level as ServerLevel) + val ship = sLevel.shipObjectWorld.allShips.getById(motion.shipID) + if (ship != null) { + player.setPos(ship.shipToWorld.transformPosition(Vector3d(motion.x, motion.y, motion.z), Vector3d()).toMinecraft()) + } + } + player.draggingInformation.serverRelativePlayerYaw = motion.yRot } } } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityDragger.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityDragger.kt index ac7ee0b48..78990a4e7 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityDragger.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityDragger.kt @@ -1,14 +1,18 @@ package org.valkyrienskies.mod.common.util +import net.minecraft.client.player.LocalPlayer import net.minecraft.server.level.ServerPlayer +import net.minecraft.util.Mth import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Player +import net.minecraft.world.phys.Vec3 import org.joml.Vector3d import org.joml.Vector3dc import org.valkyrienskies.core.api.ships.ClientShip import org.valkyrienskies.mod.common.getShipMountedTo import org.valkyrienskies.mod.common.getShipObjectManagingPos import org.valkyrienskies.mod.common.shipObjectWorld +import kotlin.math.abs import kotlin.math.asin import kotlin.math.atan2 import kotlin.math.cos @@ -57,7 +61,7 @@ object EntityDragger { // endregion // region Compute look dragging - val yViewRot = entity.getViewYRot(if (preTick) 0f else 1f).toDouble() + val yViewRot = entity.yRot.toDouble() // Get the y-look vector of the entity only using y-rotation, ignore x-rotation val entityLookYawOnly = @@ -77,15 +81,15 @@ object EntityDragger { // The Y rotation of the entity before dragging var entityYRotCorrected = entity.yRot % 360.0 // Limit [entityYRotCorrected] to be between -180 to 180 degrees - if (entityYRotCorrected < -180.0) entityYRotCorrected += 360.0 - if (entityYRotCorrected > 180.0) entityYRotCorrected -= 360.0 + if (entityYRotCorrected <= -180.0) entityYRotCorrected += 360.0 + if (entityYRotCorrected >= 180.0) entityYRotCorrected -= 360.0 // The Y rotation of the entity after dragging val newYRotAsDegrees = Math.toDegrees(newYRot) // Limit [addedYRotFromDragging] to be between -180 to 180 degrees var addedYRotFromDragging = newYRotAsDegrees - entityYRotCorrected - if (addedYRotFromDragging < -180.0) addedYRotFromDragging += 360.0 - if (addedYRotFromDragging > 180.0) addedYRotFromDragging -= 360.0 + if (addedYRotFromDragging <= -180.0) addedYRotFromDragging += 360.0 + if (addedYRotFromDragging >= 180.0) addedYRotFromDragging -= 360.0 addedYRot = addedYRotFromDragging // endregion @@ -112,10 +116,25 @@ object EntityDragger { entityDraggingInformation.addedMovementLastTick = addedMovement // Apply [addedYRot] - // Don't apply it to server players to fix rotation of placed blocks if (addedYRot.isFinite()) { - entity.yRot += addedYRot.toFloat() - entity.yHeadRot += addedYRot.toFloat() + if (!entity.level.isClientSide()) { + if (entity !is ServerPlayer) { + entity.yRot = ((entity.yRot + addedYRot.toFloat()) + 360f) % 360f + entity.yHeadRot = ((entity.yHeadRot + addedYRot.toFloat()) + 360f) % 360f + } else { + entity.yRot = Mth.wrapDegrees(entity.yRot + addedYRot.toFloat()) + entity.yHeadRot = Mth.wrapDegrees(entity.yHeadRot + addedYRot.toFloat()) + } + } else { + if (entity !is LocalPlayer) { + entity.yRot = Mth.wrapDegrees(entity.yRot + addedYRot.toFloat()) + entity.yHeadRot = Mth.wrapDegrees(entity.yHeadRot + addedYRot.toFloat()) + } else { + entity.yRot = (entity.yRot + addedYRot.toFloat()) + entity.yHeadRot = (entity.yHeadRot + addedYRot.toFloat()) + } + } + entityDraggingInformation.addedYawRotLastTick = addedYRot } } @@ -123,4 +142,52 @@ object EntityDragger { entityDraggingInformation.mountedToEntity = entity.vehicle != null } } + + /** + * Checks if the entity is a ServerPlayer and has a [serverRelativePlayerPosition] set. If it does, returns that, which is in ship space; otherwise, returns worldspace eye position. + */ + fun Entity.serversideEyePosition(): Vec3 { + if (this is ServerPlayer && this is IEntityDraggingInformationProvider && this.draggingInformation.isEntityBeingDraggedByAShip()) { + if (this.draggingInformation.serverRelativePlayerPosition != null) { + return this.draggingInformation.serverRelativePlayerPosition!!.toMinecraft() + } + } + return this.eyePosition + } + + /** + * Checks if the entity is a ServerPlayer and has a [serverRelativePlayerYaw] set. If it does, returns that, which is in ship space; otherwise, returns worldspace eye rotation. + */ + fun Entity.serversideEyeRotation(): Double { + if (this is ServerPlayer && this is IEntityDraggingInformationProvider && this.draggingInformation.isEntityBeingDraggedByAShip()) { + if (this.draggingInformation.serverRelativePlayerYaw != null) { + return this.draggingInformation.serverRelativePlayerYaw!! * 180.0 / Math.PI + } + } + return this.yRot.toDouble() + } + + /** + * Checks if the entity is a ServerPlayer and has a [serverRelativePlayerPosition] set. If it does, returns that, which is in ship space; otherwise, returns a default value. + */ + fun Entity.serversideEyePositionOrDefault(default: Vec3): Vec3 { + if (this is ServerPlayer && this is IEntityDraggingInformationProvider && this.draggingInformation.isEntityBeingDraggedByAShip()) { + if (this.draggingInformation.serverRelativePlayerPosition != null) { + return this.draggingInformation.serverRelativePlayerPosition!!.toMinecraft() + } + } + return default + } + + /** + * Checks if the entity is a ServerPlayer and has a [serverRelativePlayerYaw] set. If it does, returns that, which is in ship space; otherwise, returns a default value. + */ + fun Entity.serversideEyeRotationOrDefault(default: Double): Double { + if (this is ServerPlayer && this is IEntityDraggingInformationProvider && this.draggingInformation.isEntityBeingDraggedByAShip()) { + if (this.draggingInformation.serverRelativePlayerYaw != null) { + return Math.toDegrees(this.draggingInformation.serverRelativePlayerYaw!!) + } + } + return default + } } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityLerper.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityLerper.kt index 3b3b0bdc8..2cab51aaa 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityLerper.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityLerper.kt @@ -2,16 +2,20 @@ package org.valkyrienskies.mod.common.util import net.minecraft.util.Mth import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity import org.joml.Vector3d import org.joml.Vector3dc import org.valkyrienskies.core.api.ships.ClientShip import org.valkyrienskies.core.api.ships.Ship -import kotlin.math.asin import kotlin.math.atan2 import kotlin.math.cos import kotlin.math.sin object EntityLerper { + + /** + * Called from preAiStep. This function lerps the entity's movement while keeping it locked relative to the ship. + */ fun lerpStep(dragInfo: EntityDraggingInformation, ship: ClientShip, entity: Entity) { if (dragInfo.lerpSteps > 0) { val currentX: Double = dragInfo.relativePositionOnShip?.x() ?: return @@ -25,59 +29,31 @@ object EntityLerper { val currentYaw: Double = dragInfo.relativeYawOnShip ?: return val lerpYaw: Double = dragInfo.lerpYawOnShip ?: return - // println(previousX) - // - // println("previous pos : ${ship.transform.shipToWorld.transformPosition(dragInfo.previousRelativePositionOnShip!!, Vector3d())}") - // println("current pos : ${ship.transform.shipToWorld.transformPosition(dragInfo.relativePositionOnShip!!, Vector3d())}") - - // val previousPosRelWorld: Vector3dc = ship.shipToWorld.transformPosition(dragInfo.relativePositionOnShip, Vector3d()) - // entity.setPos(previousPosRelWorld.x(), previousPosRelWorld.y(), previousPosRelWorld.z()) - val newX: Double = currentX + (lerpX - currentX) / dragInfo.lerpSteps val newY: Double = currentY + (lerpY - currentY) / dragInfo.lerpSteps val newZ: Double = currentZ + (lerpZ - currentZ) / dragInfo.lerpSteps val newPos = ship.shipToWorld.transformPosition(newX, newY, newZ, Vector3d()) - // val previousEntityYawOnly: Vector3dc = Vector3d(sin(-currentYaw), 0.0, cos(-currentYaw)) - // val entityYawOnly: Vector3dc = Vector3d(sin(-lerpYaw), 0.0, cos(-lerpYaw)) - - // val previousYawWorld = Math.toDegrees( - // ship.transform.transformDirectionNoScalingFromShipToWorld(previousEntityYawOnly, Vector3d()).y() - // ) - // val yawWorld = - // Math.toDegrees(ship.transform.transformDirectionNoScalingFromShipToWorld(entityYawOnly, Vector3d()).y()) val currentYawWorld = yawToWorld(ship, currentYaw) val lerpYawWorld = yawToWorld(ship, lerpYaw) dragInfo.relativePositionOnShip = Vector3d(newX, newY, newZ) entity.setPos(newPos.x(), newPos.y(), newPos.z()) - // entity.setDeltaMovement( - // newPos.x() - previousPosRelWorld.x(), - // newPos.y() - previousPosRelWorld.y(), - // newPos.z() - previousPosRelWorld.z()) val g = Mth.wrapDegrees(lerpYawWorld - currentYawWorld) - val inTermsOf360 = (currentYawWorld + g / dragInfo.lerpSteps).toFloat() % 360f - val newYaw = if (inTermsOf360 < -180) { - inTermsOf360 + 360f - } else if (inTermsOf360 > 180) { - inTermsOf360 - 360f - } else { - inTermsOf360 - } + val newYaw = (currentYawWorld + g / dragInfo.lerpSteps).toFloat() + entity.yRot = newYaw dragInfo.relativeYawOnShip = yawToShip(ship, newYaw.toDouble()) dragInfo.lerpSteps -= 1 - println("Lerped. Remaining steps: ${dragInfo.lerpSteps}") - // println("Change in position: ${newPos.x()}, ${newPos.y()}, ${newPos.z()}") - println("Change in rotation: ${entity.yRot} on ${Math.toDegrees(dragInfo.relativeYawOnShip!!.toDouble())}") - } else { - // println("no lerp") } } + /** + * Additional function to lerp head separately, as it's a separate packet. + */ fun lerpHeadStep(dragInfo: EntityDraggingInformation, ship: ClientShip, entity: Entity) { if (dragInfo.headLerpSteps > 0) { val currentHeadYaw: Double = dragInfo.relativeHeadYawOnShip ?: return @@ -86,16 +62,9 @@ object EntityLerper { val currentHeadYawWorld = yawToWorld(ship, currentHeadYaw) val lerpHeadYawWorld = yawToWorld(ship, lerpHeadYaw) - val g = Mth.wrapDegrees(lerpHeadYawWorld - currentHeadYawWorld) - val inTermsOf360 = (currentHeadYawWorld + g / dragInfo.headLerpSteps).toFloat() % 360f - val newHeadYaw = if (inTermsOf360 < -180) { - inTermsOf360 + 360f - } else if (inTermsOf360 > 180) { - inTermsOf360 - 360f - } else { - inTermsOf360 - } - entity.yHeadRot = newHeadYaw + val newHeadYaw = currentHeadYawWorld + Mth.wrapDegrees(lerpHeadYawWorld - currentHeadYawWorld) / dragInfo.headLerpSteps + + entity.yHeadRot = newHeadYaw.toFloat() dragInfo.relativeHeadYawOnShip = yawToShip(ship, newHeadYaw.toDouble()) dragInfo.headLerpSteps-- @@ -103,28 +72,31 @@ object EntityLerper { } /** - * Takes in radians, outputs degrees + * Converts yaw to worldspace. + * + * Takes in radians, outputs degrees. */ fun yawToWorld(ship: Ship, yaw: Double): Double { - val entityYawOnly: Vector3dc = Vector3d(cos(yaw), 0.0, sin(yaw)) + val entityYawOnly: Vector3dc = Vector3d(sin(yaw), 0.0, cos(yaw)) val newLookIdeal = ship.transform.transformDirectionNoScalingFromShipToWorld(entityYawOnly, Vector3d()) - val newYRot = atan2(newLookIdeal.z(), newLookIdeal.x()) + val newYRot = atan2(newLookIdeal.x(), newLookIdeal.z()) - return Math.toDegrees(newYRot) + return Mth.wrapDegrees(newYRot * 180.0 / Math.PI) } /** + * Converts yaw to shipspace. + * * Takes in degrees, outputs radians */ fun yawToShip(ship: Ship, yaw: Double): Double { - val entityYawOnly: Vector3dc = Vector3d(cos(Math.toRadians(yaw)), 0.0, sin(Math.toRadians(yaw))) + val entityYawOnly: Vector3dc = Vector3d(sin(yaw * Math.PI / 180.0), 0.0, cos(yaw * Math.PI / 180.0)) val newLookIdeal = ship.transform.transformDirectionNoScalingFromWorldToShip(entityYawOnly, Vector3d()) - val newYRot = atan2(newLookIdeal.z(), newLookIdeal.x()) - + val newYRot = atan2(newLookIdeal.x(), newLookIdeal.z()) return newYRot } } diff --git a/common/src/main/resources/valkyrienskies-common.mixins.json b/common/src/main/resources/valkyrienskies-common.mixins.json index 5b0d6161b..84114b2b1 100644 --- a/common/src/main/resources/valkyrienskies-common.mixins.json +++ b/common/src/main/resources/valkyrienskies-common.mixins.json @@ -134,6 +134,7 @@ "client.world.MixinClientLevel", "feature.block_tint.MixinClientLevel", "feature.commands.MixinClientSuggestionProvider", + "feature.entity_collision.MixinLocalPlayer", "feature.fix_render_chunk_sorting.MixinRenderChunk", "feature.fluid_camera_fix.MixinCamera", "feature.render_blockentity_distance_check.MixinBlockEntityRenderDispatcher", diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/forge_interact/MixinIForgePlayer.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/forge_interact/MixinIForgePlayer.java index 45236f22b..dfbbc7733 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/forge_interact/MixinIForgePlayer.java +++ b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/forge_interact/MixinIForgePlayer.java @@ -11,8 +11,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.config.VSGameConfig; -import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; -import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; +import org.valkyrienskies.mod.common.util.EntityDragger; @Mixin(IForgePlayer.class) public interface MixinIForgePlayer { @@ -21,18 +20,15 @@ public interface MixinIForgePlayer { Player self(); /** - * Include ships in server-side distance check when player interacts with a block. + * @author Ewoudje + * @reason Include ships in server-side distance check when player interacts with a block. + * Modified by Tomato to use the serversided player reference position. */ @Overwrite(remap = false) default boolean canInteractWith(final BlockPos pos, final double padding) { if (VSGameConfig.SERVER.getEnableInteractDistanceChecks()) { final double reach = this.self().getReachDistance() + padding; - Vec3 eyes = this.self().getEyePosition(); - if (this.self() instanceof IEntityDraggingInformationProvider dragProvider && dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip()) { - if (dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { - eyes = VectorConversionsMCKt.toMinecraft(dragProvider.getDraggingInformation().getServerRelativePlayerPosition()); - } - } + final Vec3 eyes = EntityDragger.INSTANCE.serversideEyePosition(this.self()); return VSGameUtilsKt.squaredDistanceBetweenInclShips(this.self().level, pos.getX() + 0.5, pos.getY() + 0.5, @@ -44,15 +40,15 @@ default boolean canInteractWith(final BlockPos pos, final double padding) { } } + /** + * @author Ewoudje + * @reason Include ships in server-side distance check when player interacts with an entity. + * Modified by Tomato to use the serversided player reference position. + */ @Overwrite(remap = false) default boolean isCloseEnough(final Entity entity, final double distance) { if (VSGameConfig.SERVER.getEnableInteractDistanceChecks()) { - Vec3 eye = this.self().getEyePosition(); - if (this.self() instanceof IEntityDraggingInformationProvider dragProvider && dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip()) { - if (dragProvider.getDraggingInformation().getServerRelativePlayerPosition() != null) { - eye = VectorConversionsMCKt.toMinecraft(dragProvider.getDraggingInformation().getServerRelativePlayerPosition()); - } - } + final Vec3 eye = EntityDragger.INSTANCE.serversideEyePosition(this.self()); final Vec3 targetCenter = entity.getPosition(1.0F).add(0.0, (double) (entity.getBbHeight() / 2.0F), 0.0); final Optional hit = entity.getBoundingBox().clip(eye, targetCenter); return (hit.isPresent() ?