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());
}
}
}
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);
}
}
Aggregations