Search in sources :

Example 1 with ServerboundMovePlayerPacketAccessor

use of org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor 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)

Example 2 with ServerboundMovePlayerPacketAccessor

use of org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor in project SpongeCommon by SpongePowered.

the class PacketPhaseUtil method onProcessPacket.

@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
public static void onProcessPacket(final Packet packetIn, final PacketListener netHandler) {
    if (netHandler instanceof ServerGamePacketListenerImpl) {
        net.minecraft.server.level.ServerPlayer packetPlayer = ((ServerGamePacketListenerImpl) netHandler).player;
        // Only process the CustomPayload & Respawn packets from players if they are dead.
        if (!packetPlayer.isAlive() && (!(packetIn instanceof ServerboundCustomPayloadPacket) && (!(packetIn instanceof ServerboundClientCommandPacket) || ((ServerboundClientCommandPacket) packetIn).getAction() != ServerboundClientCommandPacket.Action.PERFORM_RESPAWN))) {
            return;
        }
        try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
            frame.pushCause(packetPlayer);
            // Don't process movement capture logic if player hasn't moved
            boolean ignoreMovementCapture;
            if (packetIn instanceof ServerboundMovePlayerPacket) {
                final ServerboundMovePlayerPacket movingPacket = ((ServerboundMovePlayerPacket) packetIn);
                if (movingPacket instanceof ServerboundMovePlayerPacket.Rot) {
                    ignoreMovementCapture = true;
                } else if (packetPlayer.getX() == ((ServerboundMovePlayerPacketAccessor) movingPacket).accessor$x() && packetPlayer.getY() == ((ServerboundMovePlayerPacketAccessor) movingPacket).accessor$y() && packetPlayer.getZ() == ((ServerboundMovePlayerPacketAccessor) movingPacket).accessor$z()) {
                    ignoreMovementCapture = true;
                } else {
                    ignoreMovementCapture = false;
                }
                // we cannot ignore movement capture
                if (ignoreMovementCapture) {
                    // Basically, we need to sanity check the nearby blocks because if they have
                    // any positional logic, we need to run captures
                    final AABB boundingBox = packetPlayer.getBoundingBox();
                    final BlockPos min = new BlockPos(boundingBox.minX + 0.001D, boundingBox.minY + 0.001D, boundingBox.minZ + 0.001D);
                    final BlockPos max = new BlockPos(boundingBox.maxX - 0.001D, boundingBox.maxY - 0.001D, boundingBox.maxZ - 0.001D);
                    final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
                    if (packetPlayer.level.hasChunksAt(min, max)) {
                        for (int x = min.getX(); x <= max.getX(); ++x) {
                            for (int y = min.getY(); y <= max.getY(); ++y) {
                                for (int z = min.getZ(); z <= max.getZ(); ++z) {
                                    pos.set(x, y, z);
                                    final Block block = packetPlayer.level.getBlockState(pos).getBlock();
                                    if (((TrackableBlockBridge) block).bridge$hasEntityInsideLogic()) {
                                        ignoreMovementCapture = false;
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                ignoreMovementCapture = false;
            }
            if (ignoreMovementCapture || (packetIn instanceof ServerboundClientInformationPacket)) {
                packetIn.handle(netHandler);
            } else {
                final IPhaseState<? extends PacketContext<?>> packetState = PacketPhase.getInstance().getStateForPacket(packetIn);
                // At the very least make an unknown packet state case.
                final PacketContext<?> context = packetState.createPhaseContext(PhaseTracker.SERVER);
                context.source(packetPlayer).packetPlayer(packetPlayer).packet(packetIn);
                if (!PacketPhase.getInstance().isPacketInvalid(packetIn, packetPlayer, packetState)) {
                    PacketPhase.getInstance().populateContext(packetIn, packetPlayer, packetState, context);
                    context.creator(((ServerPlayer) packetPlayer).uniqueId());
                    context.notifier(((ServerPlayer) packetPlayer).uniqueId());
                }
                try (final PhaseContext<?> packetContext = context) {
                    packetContext.buildAndSwitch();
                    packetIn.handle(netHandler);
                }
            }
        }
    } else {
        // client
        packetIn.handle(netHandler);
    }
}
Also used : ServerboundMovePlayerPacketAccessor(org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor) TrackableBlockBridge(org.spongepowered.common.bridge.world.level.block.TrackableBlockBridge) ServerboundCustomPayloadPacket(net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket) ServerboundClientCommandPacket(net.minecraft.network.protocol.game.ServerboundClientCommandPacket) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ServerboundMovePlayerPacket(net.minecraft.network.protocol.game.ServerboundMovePlayerPacket) Block(net.minecraft.world.level.block.Block) ServerboundClientInformationPacket(net.minecraft.network.protocol.game.ServerboundClientInformationPacket) BlockPos(net.minecraft.core.BlockPos) AABB(net.minecraft.world.phys.AABB) ServerGamePacketListenerImpl(net.minecraft.server.network.ServerGamePacketListenerImpl)

Aggregations

ServerboundMovePlayerPacketAccessor (org.spongepowered.common.accessor.network.protocol.game.ServerboundMovePlayerPacketAccessor)2 BlockPos (net.minecraft.core.BlockPos)1 ServerboundClientCommandPacket (net.minecraft.network.protocol.game.ServerboundClientCommandPacket)1 ServerboundClientInformationPacket (net.minecraft.network.protocol.game.ServerboundClientInformationPacket)1 ServerboundCustomPayloadPacket (net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket)1 ServerboundMovePlayerPacket (net.minecraft.network.protocol.game.ServerboundMovePlayerPacket)1 ServerGamePacketListenerImpl (net.minecraft.server.network.ServerGamePacketListenerImpl)1 Block (net.minecraft.world.level.block.Block)1 AABB (net.minecraft.world.phys.AABB)1 ServerPlayer (org.spongepowered.api.entity.living.player.server.ServerPlayer)1 CauseStackManager (org.spongepowered.api.event.CauseStackManager)1 MoveEntityEvent (org.spongepowered.api.event.entity.MoveEntityEvent)1 RotateEntityEvent (org.spongepowered.api.event.entity.RotateEntityEvent)1 Inject (org.spongepowered.asm.mixin.injection.Inject)1 EntityAccessor (org.spongepowered.common.accessor.world.entity.EntityAccessor)1 TrackableBlockBridge (org.spongepowered.common.bridge.world.level.block.TrackableBlockBridge)1 Vector3d (org.spongepowered.math.vector.Vector3d)1