Skip to content

Commit

Permalink
Add offthread_repeat arg to relative teleport command (#2533)
Browse files Browse the repository at this point in the history
* Add offthread_repeat arg to relative teleport command

* Add offthread_yaw/pitch to new teleport offthread_repeat options

* Meta fixes

* Send initial packet then do repeats instead of waiting first
  • Loading branch information
mergu committed Sep 10, 2023
1 parent 6ed5db9 commit 6013532
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 11 deletions.
@@ -1,6 +1,7 @@
package com.denizenscript.denizen.nms.interfaces;

import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand;
import com.denizenscript.denizen.utilities.maps.MapImage;
import com.denizenscript.denizencore.objects.core.ColorTag;
import org.bukkit.Bukkit;
Expand Down Expand Up @@ -151,6 +152,10 @@ default void sendCollectItemEntity(Player player, Entity taker, Entity item, int
throw new UnsupportedOperationException();
}

default void sendRelativePositionPacket(Player player, double x, double y, double z, float yaw, float pitch, List<TeleportCommand.Relative> relativeMovement) {
throw new UnsupportedOperationException();
}

default void sendRelativeLookPacket(Player player, float yaw, float pitch) {
throw new UnsupportedOperationException();
}
Expand Down
Expand Up @@ -7,16 +7,21 @@
import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizen.utilities.PaperAPITools;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper;
import com.denizenscript.denizencore.DenizenCore;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import com.denizenscript.denizencore.scripts.commands.generator.*;
import com.denizenscript.denizencore.utilities.Deprecations;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import net.citizensnpcs.trait.CurrentLocation;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector;

import java.util.Arrays;
import java.util.List;
Expand All @@ -25,17 +30,17 @@ public class TeleportCommand extends AbstractCommand {

public TeleportCommand() {
setName("teleport");
setSyntax("teleport (<entity>|...) [<location>] (cause:<cause>) (entity_options:<option>|...) (relative) (relative_axes:<axis>|...)");
setRequiredArguments(1, 6);
setSyntax("teleport (<entity>|...) [<location>] (cause:<cause>) (entity_options:<option>|...) (relative) (relative_axes:<axis>|...) (offthread_repeat:<#>) (offthread_yaw) (offthread_pitch)");
setRequiredArguments(1, 9);
isProcedural = false;
autoCompile();
}

// <--[command]
// @Name Teleport
// @Syntax teleport (<entity>|...) [<location>] (cause:<cause>) (entity_options:<option>|...) (relative) (relative_axes:<axis>|...)
// @Syntax teleport (<entity>|...) [<location>] (cause:<cause>) (entity_options:<option>|...) (relative) (relative_axes:<axis>|...) (offthread_repeat:<#>) (offthread_yaw) (offthread_pitch)
// @Required 1
// @Maximum 6
// @Maximum 9
// @Short Teleports the entity(s) to a new location.
// @Synonyms tp
// @Group entity
Expand All @@ -50,6 +55,8 @@ public TeleportCommand() {
// Optionally specify "relative" to use relative teleportation (Paper only). This is primarily useful only for players, but available for all entities.
// Relative teleports are smoother for the client when teleporting over short distances.
// Optionally, you may use "relative_axes:" to specify a set of axes to move relative on (and other axes will be treated as absolute), as any of "X", "Y", "Z", "YAW", "PITCH".
// Optionally, you may use "offthread_repeat:" with the relative arg to smooth out the teleport with a specified number of extra async packets sent within a single tick.
// Optionally, specify "offthread_yaw" or "offthread_pitch" while using offthread_repeat to smooth the player's yaw/pitch to the new location's yaw/pitch.
//
// Optionally, specify additional teleport options using the 'entity_options:' arguments (Paper only).
// This allows things like retaining an open inventory when teleporting - see the links below for more information.
Expand Down Expand Up @@ -104,7 +111,10 @@ public static void autoExecute(ScriptEntry scriptEntry,
@ArgPrefixed @ArgName("cause") @ArgDefaultText("plugin") PlayerTeleportEvent.TeleportCause cause,
@ArgName("entity_options") @ArgPrefixed @ArgDefaultNull @ArgSubType(EntityState.class) List<EntityState> entityOptions,
@ArgName("relative_axes") @ArgPrefixed @ArgDefaultNull @ArgSubType(Relative.class) List<Relative> relativeAxes,
@ArgName("relative") boolean relative) {
@ArgName("relative") boolean relative,
@ArgName("offthread_repeat") @ArgDefaultNull @ArgPrefixed ElementTag offthreadRepeats,
@ArgName("offthread_yaw") boolean offthreadYaw,
@ArgName("offthread_pitch") boolean offthreadPitch) {
if (locationRaw == null) { // Compensate for legacy "- teleport <loc>" default fill
locationRaw = entityList;
entityList = Utilities.entryDefaultEntity(scriptEntry, true);
Expand Down Expand Up @@ -148,6 +158,48 @@ else if (entityList.identify().startsWith("l@")) { // Compensate for legacy enti
NMSHandler.entityHelper.look(entity.getBukkitEntity(), location.getYaw(), location.getPitch());
return;
}
if (offthreadRepeats != null && relativeAxes != null && entity.isPlayer()) {
NetworkInterceptHelper.enable();
int times = offthreadRepeats.asInt() + 1;
int ms = 50 / times;
Player player = entity.getPlayer();
Vector increment = location.clone().subtract(player.getLocation()).toVector().multiply(1.0 / times);
double x = relativeAxes.contains(Relative.X) ? increment.getX() : location.getX();
double y = relativeAxes.contains(Relative.Y) ? increment.getY() : location.getY();
double z = relativeAxes.contains(Relative.Z) ? increment.getZ() : location.getZ();
float yaw;
if (relativeAxes.contains(Relative.YAW)) {
float relYaw = (location.getYaw() - player.getLocation().getYaw()) % 360;
if (relYaw > 180) {
relYaw -= 360;
}
yaw = offthreadYaw ? relYaw / times : 0;
}
else {
yaw = location.getYaw();
}
float pitch;
if (relativeAxes.contains(Relative.PITCH)) {
pitch = offthreadPitch ? (location.getPitch() - player.getLocation().getPitch()) / times : 0;
}
else {
pitch = location.getPitch();
}
List<Relative> finalRelativeAxes = relativeAxes;
NMSHandler.packetHelper.sendRelativePositionPacket(player, x, y, z, yaw, pitch, finalRelativeAxes);
DenizenCore.runAsync(() -> {
try {
for (int i = 0; i < times - 1; i++) {
Thread.sleep(ms);
NMSHandler.packetHelper.sendRelativePositionPacket(player, x, y, z, yaw, pitch, finalRelativeAxes);
}
}
catch (Throwable ex) {
Debug.echoError(ex);
}
});
continue;
}
if (entityOptions != null || relativeAxes != null) {
PaperAPITools.instance.teleport(entity.getBukkitEntity(), location, cause, entityOptions, relativeAxes);
continue;
Expand Down
Expand Up @@ -6,6 +6,7 @@
import com.denizenscript.denizen.nms.v1_20.ReflectionMappingsInfo;
import com.denizenscript.denizen.nms.v1_20.impl.SidebarImpl;
import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl;
import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand;
import com.denizenscript.denizen.utilities.FormattedTextHelper;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizen.utilities.maps.MapImage;
Expand Down Expand Up @@ -61,10 +62,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;

public class PacketHelperImpl implements PacketHelper {

Expand Down Expand Up @@ -376,12 +374,37 @@ public void sendCollectItemEntity(Player player, Entity taker, Entity item, int
send(player, new ClientboundTakeItemEntityPacket(item.getEntityId(), taker.getEntityId(), amount));
}

public RelativeMovement toNmsRelativeMovement(TeleportCommand.Relative relative) {
return switch (relative) {
case X -> RelativeMovement.X;
case Y -> RelativeMovement.Y;
case Z -> RelativeMovement.Z;
case YAW -> RelativeMovement.Y_ROT;
case PITCH -> RelativeMovement.X_ROT;
};
}

@Override
public void sendRelativeLookPacket(Player player, float yaw, float pitch) {
ClientboundPlayerPositionPacket packet = new ClientboundPlayerPositionPacket(0, 0, 0, yaw, pitch, RelativeMovement.ALL, 0);
public void sendRelativePositionPacket(Player player, double x, double y, double z, float yaw, float pitch, List<TeleportCommand.Relative> relativeAxis) {
Set<RelativeMovement> relativeMovements;
if (relativeAxis == null) {
relativeMovements = RelativeMovement.ALL;
}
else {
relativeMovements = EnumSet.noneOf(RelativeMovement.class);
for (TeleportCommand.Relative relative : relativeAxis) {
relativeMovements.add(toNmsRelativeMovement(relative));
}
}
ClientboundPlayerPositionPacket packet = new ClientboundPlayerPositionPacket(x, y, z, yaw, pitch, relativeMovements, 0);
DenizenNetworkManagerImpl.getNetworkManager(player).oldManager.channel.writeAndFlush(packet);
}

@Override
public void sendRelativeLookPacket(Player player, float yaw, float pitch) {
sendRelativePositionPacket(player, 0, 0, 0, yaw, pitch, null);
}

public static void send(Player player, Packet<?> packet) {
((CraftPlayer) player).getHandle().connection.send(packet);
}
Expand Down

0 comments on commit 6013532

Please sign in to comment.