Skip to content

Commit e4efe14

Browse files
authored
Smooth teleportation (#536)
* Initial attempt at v1_17_R1 smooth teleportataion * Fix compile errors for v1_17_R1 smooth teleportation * Revert worldhandler changes * Finish cleanup * Cleanup and reorganize * Move and start new teleport utils * Finish Spigot mapped teleport with placeholder mojang mapped teleport * Initial attempt at mojang mapped * Fix typo * Convert to spigot mappings, remove unknown fields * Update AbstractTeleport.java * Initial 1.18 test * Clarified teleportation classes and modes * Rename teleportation implementations, add 1.19.1 * Cleanup and add smooth teleportation to Manoverboard
1 parent 0cf847b commit e4efe14

10 files changed

Lines changed: 597 additions & 166 deletions

File tree

modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@
88
import net.countercraft.movecraft.events.ManOverboardEvent;
99
import net.countercraft.movecraft.localisation.I18nSupport;
1010
import net.countercraft.movecraft.util.MathUtils;
11+
import net.countercraft.movecraft.util.teleport.TeleportUtils;
1112
import org.bukkit.Bukkit;
1213
import org.bukkit.Location;
1314
import org.bukkit.command.Command;
1415
import org.bukkit.command.CommandExecutor;
1516
import org.bukkit.command.CommandSender;
1617
import org.bukkit.entity.Player;
1718
import org.bukkit.util.Vector;
19+
import org.jetbrains.annotations.NotNull;
1820

1921
import static net.countercraft.movecraft.util.ChatUtils.MOVECRAFT_COMMAND_PREFIX;
2022

21-
public class ManOverboardCommand implements CommandExecutor{
23+
public class ManOverboardCommand implements CommandExecutor {
2224

2325
@Override
2426
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
@@ -71,13 +73,13 @@ public boolean onCommand(CommandSender commandSender, Command command, String s,
7173

7274
player.setVelocity(new Vector(0, 0, 0));
7375
player.setFallDistance(0);
74-
player.teleport(telPoint);
76+
TeleportUtils.teleport(player, telPoint, 0, 0);
7577
return true;
7678
}
7779

78-
private Location getCraftTeleportPoint(Craft craft) {
79-
double telX = (craft.getHitBox().getMinX() + craft.getHitBox().getMaxX())/2D + 0.5D;
80-
double telZ = (craft.getHitBox().getMinZ() + craft.getHitBox().getMaxZ())/2D + 0.5D;
80+
private @NotNull Location getCraftTeleportPoint(@NotNull Craft craft) {
81+
double telX = ((craft.getHitBox().getMinX() + craft.getHitBox().getMaxX()) / 2D) + 0.5D;
82+
double telZ = ((craft.getHitBox().getMinZ() + craft.getHitBox().getMaxZ()) / 2D) + 0.5D;
8183
double telY = craft.getHitBox().getMaxY() + 1;
8284
return new Location(craft.getWorld(), telX, telY, telZ);
8385
}

modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
package net.countercraft.movecraft.mapUpdater.update;
1919

20-
import net.countercraft.movecraft.util.TeleportUtils;
20+
import net.countercraft.movecraft.util.teleport.TeleportUtils;
2121
import org.bukkit.Location;
2222
import org.bukkit.Sound;
2323
import org.bukkit.World;
@@ -88,9 +88,8 @@ public void doUpdate() {
8888
entity.teleport(new Location(world, x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch()));
8989
return;
9090
}
91-
//Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch);
9291
Location location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z);
93-
TeleportUtils.teleport((Player) entity, location, yaw);
92+
TeleportUtils.teleport((Player) entity, location, yaw, pitch);
9493
if (sound != null) {
9594
((Player) entity).playSound(location, sound, volume, 1.0f);
9695
}

modules/Movecraft/src/main/java/net/countercraft/movecraft/util/TeleportUtils.java

Lines changed: 0 additions & 152 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package net.countercraft.movecraft.util.teleport;
2+
3+
import org.bukkit.Location;
4+
import org.bukkit.entity.Player;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public abstract class AbstractTeleport {
8+
9+
public static boolean initialize() {
10+
return false;
11+
}
12+
13+
public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { }
14+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package net.countercraft.movecraft.util.teleport;
2+
3+
import org.bukkit.Location;
4+
import org.bukkit.entity.Player;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
import java.lang.reflect.Constructor;
8+
import java.lang.reflect.Field;
9+
import java.lang.reflect.InvocationTargetException;
10+
import java.lang.reflect.Method;
11+
import java.util.Set;
12+
13+
/**
14+
* Code taken with permission from MicleBrick
15+
* https://www.spigotmc.org/threads/teleport-player-smoothly.317416/
16+
* Used for 1.14.4 to 1.16.5
17+
*/
18+
public class SpigotMappedTeleport extends AbstractTeleport {
19+
private static Set<Object> teleportFlags;
20+
21+
private static Constructor packetConstructor;
22+
private static Constructor vec3D;
23+
24+
private static Method position;
25+
private static Method sendMethod;
26+
27+
private static Field connectionField;
28+
private static Field justTeleportedField;
29+
private static Field teleportPosField;
30+
private static Field lastPosXField;
31+
private static Field lastPosYField;
32+
private static Field lastPosZField;
33+
private static Field teleportAwaitField;
34+
private static Field AField;
35+
private static Field eField;
36+
private static Field yaw;
37+
private static Field pitch;
38+
39+
private static @NotNull Class<?> getNmsClass(String name) throws ClassNotFoundException {
40+
return Class.forName("net.minecraft.server." + TeleportUtils.getVersion() + "." + name);
41+
}
42+
43+
private static void sendPacket(Object packet, Player p) {
44+
try {
45+
Object handle = TeleportUtils.getHandle(p);
46+
Object pConnection = connectionField.get(handle);
47+
sendMethod.invoke(pConnection, packet);
48+
}
49+
catch (Exception e) {
50+
e.printStackTrace();
51+
}
52+
}
53+
54+
public static boolean initialize() {
55+
boolean success = false;
56+
try {
57+
Class<?> packet = getNmsClass("Packet");
58+
Class<?> entity = getNmsClass("Entity");
59+
Class<?> entityPlayer = getNmsClass("EntityPlayer");
60+
Class<?> connectionClass = getNmsClass("PlayerConnection");
61+
Class<?> packetClass = getNmsClass("PacketPlayOutPosition");
62+
Class<?> vecClass = getNmsClass("Vec3D");
63+
sendMethod = connectionClass.getMethod("sendPacket", packet);
64+
65+
position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE);
66+
67+
yaw = TeleportUtils.getField(entity, "yaw");
68+
pitch = TeleportUtils.getField(entity, "pitch");
69+
connectionField = TeleportUtils.getField(entityPlayer, "playerConnection");
70+
71+
packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE);
72+
vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE);
73+
74+
Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants();
75+
teleportFlags = Set.of(enumObjects[4], enumObjects[3]);
76+
77+
justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported");
78+
teleportPosField = TeleportUtils.getField(connectionClass, "teleportPos");
79+
lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX");
80+
lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY");
81+
lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ");
82+
teleportAwaitField = TeleportUtils.getField(connectionClass, "teleportAwait");
83+
AField = TeleportUtils.getField(connectionClass, "A");
84+
eField = TeleportUtils.getField(connectionClass, "e");
85+
success = true;
86+
}
87+
catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException | SecurityException e) {
88+
e.printStackTrace();
89+
}
90+
return success;
91+
}
92+
93+
public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) {
94+
double x = location.getX();
95+
double y = location.getY();
96+
double z = location.getZ();
97+
Object handle = TeleportUtils.getHandle(player);
98+
try {
99+
position.invoke(handle, x, y, z, yaw.get(handle), pitch.get(handle));
100+
Object connection = connectionField.get(handle);
101+
justTeleportedField.set(connection, true);
102+
teleportPosField.set(connection, vec3D.newInstance(x, y, z));
103+
lastPosXField.set(connection, x);
104+
lastPosYField.set(connection, y);
105+
lastPosZField.set(connection, z);
106+
int teleportAwait = teleportAwaitField.getInt(connection) + 1;
107+
if (teleportAwait == Integer.MAX_VALUE)
108+
teleportAwait = 0;
109+
teleportAwaitField.set(connection, teleportAwait);
110+
AField.set(connection, eField.get(connection));
111+
112+
Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait);
113+
sendPacket(packet, player);
114+
}
115+
catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) {
116+
e.printStackTrace();
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)