Search in sources :

Example 1 with RotateEntityEvent

use of org.spongepowered.api.event.entity.RotateEntityEvent in project SpongeCommon by SpongePowered.

the class ServerPlayerMixin method teleportTo.

/*
    @Inject(method = "markPlayerActive()V", at = @At("HEAD"))
    private void impl$onPlayerActive(final CallbackInfo ci) {
        ((ServerPlayNetHandlerBridge) this.connection).bridge$resendLatestResourcePackRequest();
    }
*/
/**
 * @author zidane - November 21st, 2020 - Minecraft 1.15
 * @reason Ensure that the teleport hook honors our events
 */
@Overwrite
public void teleportTo(final net.minecraft.server.level.ServerLevel world, final double x, final double y, final double z, final float yaw, final float pitch) {
    final net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer) (Object) this;
    double actualX = x;
    double actualY = y;
    double actualZ = z;
    double actualYaw = yaw;
    double actualPitch = pitch;
    final boolean hasMovementContext = PhaseTracker.getCauseStackManager().currentContext().containsKey(EventContextKeys.MOVEMENT_TYPE);
    try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
        if (!hasMovementContext) {
            frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN);
        }
        if (world == player.level) {
            @Nullable final Vector3d destination = this.impl$fireMoveEvent(PhaseTracker.SERVER, new Vector3d(x, y, z));
            if (destination == null) {
                return;
            }
            actualX = destination.x();
            actualY = destination.y();
            actualZ = destination.z();
            if (ShouldFire.ROTATE_ENTITY_EVENT) {
                final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) player, new Vector3d(actualPitch, actualYaw, 0), new Vector3d(pitch, yaw, 0));
                SpongeCommon.post(rotateEvent);
                actualYaw = rotateEvent.isCancelled() ? player.yRot : rotateEvent.toRotation().y();
                actualPitch = rotateEvent.isCancelled() ? player.xRot : rotateEvent.toRotation().x();
            }
            this.shadow$setCamera(player);
            this.shadow$stopRiding();
            if (player.isSleeping()) {
                player.stopSleepInBed(true, true);
            }
            player.connection.teleport(actualX, actualY, actualZ, (float) actualYaw, (float) actualPitch);
            player.setYHeadRot((float) actualYaw);
            final ChunkPos chunkpos = new ChunkPos(new BlockPos(actualX, actualY, actualZ));
            world.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 1, player.getId());
        } else {
            final ChangeEntityWorldEvent.Pre preEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre(player, world);
            if (SpongeCommon.post(preEvent)) {
                return;
            }
            if (ShouldFire.MOVE_ENTITY_EVENT) {
                final MoveEntityEvent posEvent = SpongeEventFactory.createChangeEntityWorldEventReposition(frame.currentCause(), (org.spongepowered.api.entity.Entity) player, preEvent.originalWorld(), VecHelper.toVector3d(player.position()), new Vector3d(x, y, z), preEvent.originalDestinationWorld(), new Vector3d(x, y, z), preEvent.destinationWorld());
                if (SpongeCommon.post(posEvent)) {
                    return;
                }
                actualX = posEvent.destinationPosition().x();
                actualY = posEvent.destinationPosition().y();
                actualZ = posEvent.destinationPosition().z();
            }
            this.shadow$setPos(actualX, actualY, actualZ);
            if (ShouldFire.ROTATE_ENTITY_EVENT) {
                final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) player, new Vector3d(actualYaw, actualPitch, 0), new Vector3d(yaw, pitch, 0));
                if (!SpongeCommon.post(rotateEvent)) {
                    actualYaw = (float) rotateEvent.toRotation().x();
                    actualPitch = (float) rotateEvent.toRotation().y();
                }
            }
            this.yRot = (float) actualYaw;
            this.xRot = (float) actualPitch;
            EntityUtil.performPostChangePlayerWorldLogic(player, (net.minecraft.server.level.ServerLevel) preEvent.originalWorld(), (net.minecraft.server.level.ServerLevel) preEvent.originalDestinationWorld(), (net.minecraft.server.level.ServerLevel) preEvent.destinationWorld(), false);
        }
    }
}
Also used : MoveEntityEvent(org.spongepowered.api.event.entity.MoveEntityEvent) ChangeEntityWorldEvent(org.spongepowered.api.event.entity.ChangeEntityWorldEvent) RotateEntityEvent(org.spongepowered.api.event.entity.RotateEntityEvent) Vector3d(org.spongepowered.math.vector.Vector3d) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) ChunkPos(net.minecraft.world.level.ChunkPos) BlockPos(net.minecraft.core.BlockPos) Nullable(org.checkerframework.checker.nullness.qual.Nullable) Identity(net.kyori.adventure.identity.Identity) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 2 with RotateEntityEvent

use of org.spongepowered.api.event.entity.RotateEntityEvent in project SpongeCommon by SpongePowered.

the class TeleportCommandMixin method performTeleport.

/**
 * @author Zidane
 * @reason Have the teleport command respect our events
 */
@Overwrite
private static void performTeleport(CommandSourceStack source, Entity entityIn, ServerLevel worldIn, double x, double y, double z, Set<ClientboundPlayerPositionPacket.RelativeArgument> relativeList, float yaw, float pitch, @Nullable TeleportCommand.LookAt facing) {
    double actualX = x;
    double actualY = y;
    double actualZ = z;
    double actualYaw = yaw;
    double actualPitch = pitch;
    if (!(entityIn instanceof ServerPlayer)) {
        actualYaw = Mth.wrapDegrees(yaw);
        actualPitch = Mth.wrapDegrees(pitch);
        actualPitch = Mth.clamp(actualPitch, -90.0F, 90.0F);
    }
    if (worldIn == entityIn.level) {
        try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
            frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.COMMAND);
            if (ShouldFire.MOVE_ENTITY_EVENT) {
                final MoveEntityEvent posEvent = SpongeEventFactory.createMoveEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) entityIn, VecHelper.toVector3d(entityIn.position()), new Vector3d(x, y, z), new Vector3d(x, y, z));
                if (SpongeCommon.post(posEvent)) {
                    return;
                }
                actualX = posEvent.destinationPosition().x();
                actualY = posEvent.destinationPosition().y();
                actualZ = posEvent.destinationPosition().z();
            }
            if (ShouldFire.ROTATE_ENTITY_EVENT) {
                final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) entityIn, new Vector3d(actualPitch, actualYaw, 0), new Vector3d(pitch, yaw, 0));
                SpongeCommon.post(rotateEvent);
                actualYaw = rotateEvent.isCancelled() ? entityIn.yRot : rotateEvent.toRotation().y();
                actualPitch = rotateEvent.isCancelled() ? entityIn.xRot : rotateEvent.toRotation().x();
            }
            if (entityIn instanceof ServerPlayer) {
                ChunkPos chunkpos = new ChunkPos(new BlockPos(actualX, actualY, actualZ));
                worldIn.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 1, entityIn.getId());
                entityIn.stopRiding();
                if (((ServerPlayer) entityIn).isSleeping()) {
                    ((ServerPlayer) entityIn).stopSleepInBed(true, true);
                }
                ((ServerPlayer) entityIn).connection.teleport(actualX, actualY, actualZ, (float) actualYaw, (float) actualPitch, relativeList);
            } else {
                entityIn.moveTo(actualX, actualY, actualZ, (float) actualYaw, (float) actualPitch);
            }
            entityIn.setYHeadRot((float) actualYaw);
        }
    } else {
        if (entityIn instanceof ServerPlayer) {
            // To ensure mod code is caught, handling the world change for players happens in teleport
            // Teleport will create a frame but we want to ensure it'll be the command movement type
            // TODO check if this is still correct
            PhaseTracker.getCauseStackManager().addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.COMMAND);
            ((ServerPlayer) entityIn).teleportTo(worldIn, x, y, z, yaw, pitch);
            PhaseTracker.getCauseStackManager().removeContext(EventContextKeys.MOVEMENT_TYPE);
        } else {
            try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
                frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.COMMAND);
                final ServerLevel fromWorld = (ServerLevel) entityIn.getCommandSenderWorld();
                final ChangeEntityWorldEvent.Pre preEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre(entityIn, worldIn);
                if (SpongeCommon.post(preEvent)) {
                    return;
                }
                final ChangeEntityWorldEvent.Reposition posEvent = SpongeEventFactory.createChangeEntityWorldEventReposition(frame.currentCause(), (org.spongepowered.api.entity.Entity) entityIn, (org.spongepowered.api.world.server.ServerWorld) entityIn.getCommandSenderWorld(), VecHelper.toVector3d(entityIn.position()), new Vector3d(x, y, z), preEvent.originalDestinationWorld(), new Vector3d(x, y, z), preEvent.destinationWorld());
                if (SpongeCommon.post(posEvent)) {
                    return;
                }
                entityIn.unRide();
                final Entity result = entityIn.getType().create(worldIn);
                if (result == null) {
                    return;
                }
                if (ShouldFire.ROTATE_ENTITY_EVENT) {
                    final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) entityIn, new Vector3d(entityIn.xRot, entityIn.yRot, 0), new Vector3d(actualPitch, actualYaw, 0));
                    if (!SpongeCommon.post(rotateEvent)) {
                        actualYaw = Mth.wrapDegrees(rotateEvent.toRotation().y());
                        actualPitch = Mth.wrapDegrees(rotateEvent.toRotation().x());
                        actualPitch = Mth.clamp(actualPitch, -90.0F, 90.0F);
                    } else {
                        actualYaw = entityIn.yRot;
                        actualPitch = entityIn.xRot;
                    }
                }
                result.restoreFrom(entityIn);
                result.moveTo(posEvent.destinationPosition().x(), posEvent.destinationPosition().y(), posEvent.destinationPosition().z(), (float) actualYaw, (float) actualPitch);
                result.setYHeadRot((float) actualYaw);
                worldIn.addFromAnotherDimension(result);
                entityIn.removed = true;
                Sponge.eventManager().post(SpongeEventFactory.createChangeEntityWorldEventPost(PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.entity.Entity) result, (ServerWorld) fromWorld, preEvent.originalDestinationWorld(), preEvent.destinationWorld()));
            }
        }
    }
    if (facing != null) {
        facing.perform(source, entityIn);
    }
    if (!(entityIn instanceof LivingEntity) || !((LivingEntity) entityIn).isFallFlying()) {
        entityIn.setDeltaMovement(entityIn.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
        entityIn.setOnGround(true);
    }
    if (entityIn instanceof PathfinderMob) {
        ((PathfinderMob) entityIn).getNavigation().stop();
    }
}
Also used : ServerLevel(net.minecraft.server.level.ServerLevel) LivingEntity(net.minecraft.world.entity.LivingEntity) Entity(net.minecraft.world.entity.Entity) MoveEntityEvent(org.spongepowered.api.event.entity.MoveEntityEvent) ChangeEntityWorldEvent(org.spongepowered.api.event.entity.ChangeEntityWorldEvent) RotateEntityEvent(org.spongepowered.api.event.entity.RotateEntityEvent) ServerWorld(org.spongepowered.api.world.server.ServerWorld) LivingEntity(net.minecraft.world.entity.LivingEntity) Vector3d(org.spongepowered.math.vector.Vector3d) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ServerPlayer(net.minecraft.server.level.ServerPlayer) ChunkPos(net.minecraft.world.level.ChunkPos) BlockPos(net.minecraft.core.BlockPos) PathfinderMob(net.minecraft.world.entity.PathfinderMob) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 3 with RotateEntityEvent

use of org.spongepowered.api.event.entity.RotateEntityEvent in project SpongeCommon by SpongePowered.

the class SpongeCommonEventFactory method callNaturalRotateEntityEvent.

/**
 * Performs the logic necessary to post the {@link RotateEntityEvent rotation event} for an {@link Entity}.
 *
 * @param entity The event
 */
public static void callNaturalRotateEntityEvent(final net.minecraft.world.entity.Entity entity) {
    if (entity.removed || (entity.xRot == entity.xRotO && entity.yRot == entity.yRotO)) {
        return;
    }
    try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
        frame.pushCause(entity);
        final RotateEntityEvent event = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), (Entity) entity, new Vector3d(entity.xRotO, entity.yRotO, 0), new Vector3d(entity.xRot, entity.yRot, 0));
        if (SpongeCommon.post(event)) {
            entity.xRot = entity.xRotO;
            entity.yRot = entity.yRotO;
        } else {
            entity.xRot = (float) event.toRotation().x();
            entity.yRot = (float) event.toRotation().y();
        }
    }
}
Also used : Vector3d(org.spongepowered.math.vector.Vector3d) CauseStackManager(org.spongepowered.api.event.CauseStackManager) RotateEntityEvent(org.spongepowered.api.event.entity.RotateEntityEvent)

Example 4 with RotateEntityEvent

use of org.spongepowered.api.event.entity.RotateEntityEvent in project SpongeCommon by SpongePowered.

the class ServerGamePacketListenerImplMixin method impl$callMoveEntityEvent.

/**
 * Effectively, hooking into the following code block:
 * <pre>
 *       if (isMovePlayerPacketInvalid(packetIn)) {
 *          this.disconnect(new TranslationTextComponent("multiplayer.disconnect.invalid_player_movement"));
 *       } else {
 *          ServerWorld serverworld = this.server.world(this.player.dimension);
 *          if (!this.player.queuedEndExit) { // <---- Here is where we're injecting
 *             if (this.networkTickCount == 0) {
 *                this.captureCurrentPosition();
 *             }
 * </pre>
 * we can effectively short circuit the method to handle movement code where
 * returning {@code true} will escape the packet being processed further entirely and
 * {@code false} will allow the remaining processing of the method run.
 *
 * @param packetIn The movement packet
 */
@Inject(method = "handleMovePlayer", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;awaitingPositionFromClient:Lnet/minecraft/world/phys/Vec3;"), slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/server/level/ServerPlayer;wonGame:Z"), to = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;tickCount:I", ordinal = 1)), cancellable = true)
private void impl$callMoveEntityEvent(final ServerboundMovePlayerPacket packetIn, final CallbackInfo ci) {
    // If the movement is modified we pretend that the player has queuedEndExit = true
    // so that vanilla wont process that packet further
    final ServerboundMovePlayerPacketAccessor packetInAccessor = (ServerboundMovePlayerPacketAccessor) packetIn;
    // We don't fire an event to avoid confusing plugins.
    if (!packetInAccessor.accessor$hasPos() && !packetInAccessor.accessor$hasRot()) {
        return;
    }
    final boolean goodMovementPacket = this.receivedMovePacketCount - this.knownMovePacketCount <= 5;
    final boolean fireMoveEvent = goodMovementPacket && packetInAccessor.accessor$hasPos() && ShouldFire.MOVE_ENTITY_EVENT;
    final boolean fireRotationEvent = goodMovementPacket && packetInAccessor.accessor$hasRot() && ShouldFire.ROTATE_ENTITY_EVENT;
    final ServerPlayer player = (ServerPlayer) this.player;
    final Vector3d fromRotation = new Vector3d(this.player.yRot, this.player.xRot, 0);
    // Use the position of the last movement with an event or the current player position if never called
    // We need this because we ignore very small position changes as to not spam as many move events.
    final Vector3d fromPosition = player.position();
    Vector3d toPosition = new Vector3d(packetIn.getX(this.player.getX()), packetIn.getY(this.player.getY()), packetIn.getZ(this.player.getZ()));
    Vector3d toRotation = new Vector3d(packetIn.getYRot(this.player.yRot), packetIn.getXRot(this.player.xRot), 0);
    final boolean significantRotation = fromRotation.distanceSquared(toRotation) > (.15f * .15f);
    final Vector3d originalToPosition = toPosition;
    boolean cancelMovement = false;
    boolean cancelRotation = false;
    // Call move & rotate event as needed...
    if (fireMoveEvent) {
        final MoveEntityEvent event = SpongeEventFactory.createMoveEntityEvent(PhaseTracker.getCauseStackManager().currentCause(), (ServerPlayer) this.player, fromPosition, toPosition, toPosition);
        if (SpongeCommon.post(event)) {
            cancelMovement = true;
        } else {
            toPosition = event.destinationPosition();
        }
    }
    if (significantRotation && fireRotationEvent) {
        final RotateEntityEvent event = SpongeEventFactory.createRotateEntityEvent(PhaseTracker.getCauseStackManager().currentCause(), (ServerPlayer) this.player, fromRotation, toRotation);
        if (SpongeCommon.post(event)) {
            cancelRotation = true;
            toRotation = fromRotation;
        } else {
            toRotation = event.toRotation();
        }
    }
    // player position and update the player's relation in the chunk manager.
    if (cancelMovement) {
        if (fromPosition.distanceSquared(toPosition) > 0) {
            // Set the location, as if the player was teleporting
            this.awaitingTeleportTime = this.tickCount;
            this.shadow$teleport(fromPosition.x(), fromPosition.y(), fromPosition.z(), (float) toRotation.x(), (float) toRotation.y());
        } else {
            // If this is only rotation do not teleport back
            this.player.absMoveTo(fromPosition.x(), fromPosition.y(), fromPosition.z(), (float) toRotation.x(), (float) toRotation.y());
        }
        ci.cancel();
        return;
    }
    // Handle event results
    if (!toPosition.equals(originalToPosition)) {
        // Check if we have to say it's a "teleport" vs a standard move
        final double d4 = packetIn.getX(this.player.getX());
        final double d5 = packetIn.getY(this.player.getY());
        final double d6 = packetIn.getZ(this.player.getZ());
        final double d7 = d4 - this.firstGoodX;
        final double d8 = d5 - this.firstGoodY;
        final double d9 = d6 - this.firstGoodZ;
        final double d10 = this.player.getDeltaMovement().lengthSqr();
        final double d11 = d7 * d7 + d8 * d8 + d9 * d9;
        final float f2 = this.player.isFallFlying() ? 300.0F : 100.0F;
        final int i = this.receivedMovePacketCount - this.knownMovePacketCount;
        if (d11 - d10 > (double) (f2 * (float) i) && !this.shadow$isSingleplayerOwner()) {
            // At this point, we need to set the target position so the teleport code forces it
            this.awaitingPositionFromClient = VecHelper.toVanillaVector3d(toPosition);
            ((EntityAccessor) this.player).invoker$setRot((float) toRotation.x(), (float) toRotation.y());
            // And reset the position update so the force set is done.
            this.awaitingTeleportTime = this.tickCount - Constants.Networking.MAGIC_TRIGGER_TELEPORT_CONFIRM_DIFF;
        } else {
            // otherwise, set the data back onto the packet
            packetInAccessor.accessor$hasPos(true);
            packetInAccessor.accessor$x(toPosition.x());
            packetInAccessor.accessor$y(toPosition.y());
            packetInAccessor.accessor$z(toPosition.z());
        }
    }
}
Also used : EntityAccessor(org.spongepowered.common.accessor.world.entity.EntityAccessor) ServerboundMovePlayerPacketAccessor(org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor) MoveEntityEvent(org.spongepowered.api.event.entity.MoveEntityEvent) Vector3d(org.spongepowered.math.vector.Vector3d) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) RotateEntityEvent(org.spongepowered.api.event.entity.RotateEntityEvent) Inject(org.spongepowered.asm.mixin.injection.Inject)

Aggregations

RotateEntityEvent (org.spongepowered.api.event.entity.RotateEntityEvent)4 Vector3d (org.spongepowered.math.vector.Vector3d)4 CauseStackManager (org.spongepowered.api.event.CauseStackManager)3 MoveEntityEvent (org.spongepowered.api.event.entity.MoveEntityEvent)3 BlockPos (net.minecraft.core.BlockPos)2 ChunkPos (net.minecraft.world.level.ChunkPos)2 ServerPlayer (org.spongepowered.api.entity.living.player.server.ServerPlayer)2 ChangeEntityWorldEvent (org.spongepowered.api.event.entity.ChangeEntityWorldEvent)2 Overwrite (org.spongepowered.asm.mixin.Overwrite)2 Identity (net.kyori.adventure.identity.Identity)1 ServerLevel (net.minecraft.server.level.ServerLevel)1 ServerPlayer (net.minecraft.server.level.ServerPlayer)1 Entity (net.minecraft.world.entity.Entity)1 LivingEntity (net.minecraft.world.entity.LivingEntity)1 PathfinderMob (net.minecraft.world.entity.PathfinderMob)1 Nullable (org.checkerframework.checker.nullness.qual.Nullable)1 ServerWorld (org.spongepowered.api.world.server.ServerWorld)1 Inject (org.spongepowered.asm.mixin.injection.Inject)1 ServerboundMovePlayerPacketAccessor (org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor)1 EntityAccessor (org.spongepowered.common.accessor.world.entity.EntityAccessor)1