Skip to content

Commit

Permalink
Smooth teleportation (#536)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
TylerS1066 authored Jul 31, 2022
1 parent 0cf847b commit e4efe14
Show file tree
Hide file tree
Showing 10 changed files with 597 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
import net.countercraft.movecraft.events.ManOverboardEvent;
import net.countercraft.movecraft.localisation.I18nSupport;
import net.countercraft.movecraft.util.MathUtils;
import net.countercraft.movecraft.util.teleport.TeleportUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;

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

public class ManOverboardCommand implements CommandExecutor{
public class ManOverboardCommand implements CommandExecutor {

@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
Expand Down Expand Up @@ -71,13 +73,13 @@ public boolean onCommand(CommandSender commandSender, Command command, String s,

player.setVelocity(new Vector(0, 0, 0));
player.setFallDistance(0);
player.teleport(telPoint);
TeleportUtils.teleport(player, telPoint, 0, 0);
return true;
}

private Location getCraftTeleportPoint(Craft craft) {
double telX = (craft.getHitBox().getMinX() + craft.getHitBox().getMaxX())/2D + 0.5D;
double telZ = (craft.getHitBox().getMinZ() + craft.getHitBox().getMaxZ())/2D + 0.5D;
private @NotNull Location getCraftTeleportPoint(@NotNull Craft craft) {
double telX = ((craft.getHitBox().getMinX() + craft.getHitBox().getMaxX()) / 2D) + 0.5D;
double telZ = ((craft.getHitBox().getMinZ() + craft.getHitBox().getMaxZ()) / 2D) + 0.5D;
double telY = craft.getHitBox().getMaxY() + 1;
return new Location(craft.getWorld(), telX, telY, telZ);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

package net.countercraft.movecraft.mapUpdater.update;

import net.countercraft.movecraft.util.TeleportUtils;
import net.countercraft.movecraft.util.teleport.TeleportUtils;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.World;
Expand Down Expand Up @@ -88,9 +88,8 @@ public void doUpdate() {
entity.teleport(new Location(world, x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch()));
return;
}
//Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch);
Location location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z);
TeleportUtils.teleport((Player) entity, location, yaw);
TeleportUtils.teleport((Player) entity, location, yaw, pitch);
if (sound != null) {
((Player) entity).playSound(location, sound, volume, 1.0f);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.countercraft.movecraft.util.teleport;

import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

public abstract class AbstractTeleport {

public static boolean initialize() {
return false;
}

public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package net.countercraft.movecraft.util.teleport;

import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
* Code taken with permission from MicleBrick
* https://www.spigotmc.org/threads/teleport-player-smoothly.317416/
* Used for 1.14.4 to 1.16.5
*/
public class SpigotMappedTeleport extends AbstractTeleport {
private static Set<Object> teleportFlags;

private static Constructor packetConstructor;
private static Constructor vec3D;

private static Method position;
private static Method sendMethod;

private static Field connectionField;
private static Field justTeleportedField;
private static Field teleportPosField;
private static Field lastPosXField;
private static Field lastPosYField;
private static Field lastPosZField;
private static Field teleportAwaitField;
private static Field AField;
private static Field eField;
private static Field yaw;
private static Field pitch;

private static @NotNull Class<?> getNmsClass(String name) throws ClassNotFoundException {
return Class.forName("net.minecraft.server." + TeleportUtils.getVersion() + "." + name);
}

private static void sendPacket(Object packet, Player p) {
try {
Object handle = TeleportUtils.getHandle(p);
Object pConnection = connectionField.get(handle);
sendMethod.invoke(pConnection, packet);
}
catch (Exception e) {
e.printStackTrace();
}
}

public static boolean initialize() {
boolean success = false;
try {
Class<?> packet = getNmsClass("Packet");
Class<?> entity = getNmsClass("Entity");
Class<?> entityPlayer = getNmsClass("EntityPlayer");
Class<?> connectionClass = getNmsClass("PlayerConnection");
Class<?> packetClass = getNmsClass("PacketPlayOutPosition");
Class<?> vecClass = getNmsClass("Vec3D");
sendMethod = connectionClass.getMethod("sendPacket", packet);

position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE);

yaw = TeleportUtils.getField(entity, "yaw");
pitch = TeleportUtils.getField(entity, "pitch");
connectionField = TeleportUtils.getField(entityPlayer, "playerConnection");

packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE);
vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE);

Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants();
teleportFlags = Set.of(enumObjects[4], enumObjects[3]);

justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported");
teleportPosField = TeleportUtils.getField(connectionClass, "teleportPos");
lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX");
lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY");
lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ");
teleportAwaitField = TeleportUtils.getField(connectionClass, "teleportAwait");
AField = TeleportUtils.getField(connectionClass, "A");
eField = TeleportUtils.getField(connectionClass, "e");
success = true;
}
catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return success;
}

public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) {
double x = location.getX();
double y = location.getY();
double z = location.getZ();
Object handle = TeleportUtils.getHandle(player);
try {
position.invoke(handle, x, y, z, yaw.get(handle), pitch.get(handle));
Object connection = connectionField.get(handle);
justTeleportedField.set(connection, true);
teleportPosField.set(connection, vec3D.newInstance(x, y, z));
lastPosXField.set(connection, x);
lastPosYField.set(connection, y);
lastPosZField.set(connection, z);
int teleportAwait = teleportAwaitField.getInt(connection) + 1;
if (teleportAwait == Integer.MAX_VALUE)
teleportAwait = 0;
teleportAwaitField.set(connection, teleportAwait);
AField.set(connection, eField.get(connection));

Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait);
sendPacket(packet, player);
}
catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Loading

0 comments on commit e4efe14

Please sign in to comment.