From ffb2c71e5552991ad8157cb34bff5cffe5fa1bc8 Mon Sep 17 00:00:00 2001
From: modmuss50 <modmuss50@gmail.com>
Date: Tue, 24 May 2022 15:10:52 +0100
Subject: [PATCH] Handle teleporting within the same dimension better. (#2249)

(cherry picked from commit 72da3b3d5e7c5baf0a57699fc3ae48bc9592299a)
---
 .../dimension/FabricDimensionInternals.java   | 16 ++++++
 .../test/dimension/FabricDimensionTest.java   | 52 +++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java
index df1b9b3e6..02eedb640 100644
--- a/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java
+++ b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java
@@ -19,6 +19,7 @@ package net.fabricmc.fabric.impl.dimension;
 import com.google.common.base.Preconditions;
 
 import net.minecraft.entity.Entity;
+import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.server.world.ServerWorld;
 import net.minecraft.world.TeleportTarget;
 
@@ -48,6 +49,21 @@ public final class FabricDimensionInternals {
 
 		try {
 			currentTarget = target;
+
+			// Fast path for teleporting within the same dimension.
+			if (teleported.getWorld() == dimension) {
+				if (teleported instanceof ServerPlayerEntity serverPlayerEntity) {
+					serverPlayerEntity.networkHandler.requestTeleport(target.position.x, target.position.y, target.position.z, target.yaw, teleported.getPitch());
+				} else {
+					teleported.refreshPositionAndAngles(target.position.x, target.position.y, target.position.z, target.yaw, teleported.getPitch());
+				}
+
+				teleported.setVelocity(target.velocity);
+				teleported.setHeadYaw(target.yaw);
+
+				return teleported;
+			}
+
 			return (E) teleported.moveToWorld(dimension);
 		} finally {
 			currentTarget = null;
diff --git a/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java b/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java
index 6cd338918..5e58e3b17 100644
--- a/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java
+++ b/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java
@@ -102,6 +102,14 @@ public class FabricDimensionTest implements ModInitializer {
 		CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) ->
 				dispatcher.register(literal("fabric_dimension_test").executes(FabricDimensionTest.this::swapTargeted))
 		);
+
+		// Used to test https://github.com/FabricMC/fabric/issues/2239
+		CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("fabric_dimension_test_desync")
+				.executes(FabricDimensionTest.this::testDesync)));
+
+		// Used to test https://github.com/FabricMC/fabric/issues/2238
+		CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("fabric_dimension_test_entity")
+				.executes(FabricDimensionTest.this::testEntityTeleport)));
 	}
 
 	private int swapTargeted(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
@@ -128,6 +136,50 @@ public class FabricDimensionTest implements ModInitializer {
 		return 1;
 	}
 
+	private int testDesync(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
+		ServerPlayerEntity player = context.getSource().getPlayer();
+
+		if (player == null) {
+			context.getSource().sendFeedback(new LiteralText("You must be a player to execute this command."), false);
+			return 1;
+		}
+
+		if (!context.getSource().getServer().isDedicated()) {
+			context.getSource().sendFeedback(new LiteralText("This command can only be executed on dedicated servers."), false);
+			return 1;
+		}
+
+		TeleportTarget target = new TeleportTarget(player.getPos().add(5, 0, 0), player.getVelocity(), player.getYaw(), player.getPitch());
+		FabricDimensions.teleport(player, (ServerWorld) player.world, target);
+
+		return 1;
+	}
+
+	private int testEntityTeleport(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
+		ServerPlayerEntity player = context.getSource().getPlayer();
+
+		if (player == null) {
+			context.getSource().sendFeedback(new LiteralText("You must be a player to execute this command."), false);
+			return 1;
+		}
+
+		Entity entity = player.world
+				.getOtherEntities(player, player.getBoundingBox().expand(100, 100, 100))
+				.stream()
+				.findFirst()
+				.orElse(null);
+
+		if (entity == null) {
+			context.getSource().sendFeedback(new LiteralText("No entities found."), false);
+			return 1;
+		}
+
+		TeleportTarget target = new TeleportTarget(player.getPos(), player.getVelocity(), player.getYaw(), player.getPitch());
+		FabricDimensions.teleport(entity, (ServerWorld) entity.world, target);
+
+		return 1;
+	}
+
 	private ServerWorld getModWorld(CommandContext<ServerCommandSource> context) {
 		return getWorld(context, WORLD_KEY);
 	}