Skip to content

Commit

Permalink
modernize look command and add offthread_repeat
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed Jan 1, 2023
1 parent 74f52a4 commit 383274b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 71 deletions.
Expand Up @@ -141,4 +141,8 @@ default void sendBrand(Player player, String brand) {
default void sendCollectItemEntity(Player player, Entity taker, Entity item, int amount) {
throw new UnsupportedOperationException();
}

default void sendRelativeLookPacket(Player player, float yaw, float pitch) {
throw new UnsupportedOperationException();
}
}
Expand Up @@ -6,6 +6,7 @@
import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.scripts.commands.generator.*;
import com.denizenscript.denizencore.utilities.Deprecations;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
Expand Down Expand Up @@ -82,6 +83,7 @@ public static void autoExecute(ScriptEntry scriptEntry,
ObjectTag swapEntities = entitiesObj;
entitiesObj = amountObj;
if (swapEntities != null && swapEntities.asElement().isDouble()) {
Deprecations.outOfOrderArgs.warn(scriptEntry);
amountObj = swapEntities;
}
else {
Expand Down
Expand Up @@ -2,20 +2,26 @@

import com.denizenscript.denizen.Denizen;
import com.denizenscript.denizen.utilities.PaperAPITools;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper;
import com.denizenscript.denizencore.DenizenCore;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull;
import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear;
import com.denizenscript.denizencore.scripts.commands.generator.ArgName;
import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed;
import com.denizenscript.denizencore.utilities.Deprecations;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException;
import com.denizenscript.denizencore.objects.Argument;
import com.denizenscript.denizencore.objects.core.DurationTag;
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.utilities.debugging.Debug;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;

Expand All @@ -27,16 +33,18 @@ public class LookCommand extends AbstractCommand {

public LookCommand() {
setName("look");
setSyntax("look (<entity>|...) [<location>/cancel/yaw:<yaw> pitch:<pitch>] (duration:<duration>)");
setRequiredArguments(1, 4);
setSyntax("look (<entity>|...) [<location>/cancel/yaw:<yaw> pitch:<pitch>] (duration:<duration>) (offthread_repeat:<#>)");
setRequiredArguments(1, 5);
isProcedural = false;
addRemappedPrefixes("duration", "d");
autoCompile();
}

// <--[command]
// @Name Look
// @Syntax look (<entity>|...) [<location>/cancel/yaw:<yaw> pitch:<pitch>] (duration:<duration>)
// @Syntax look (<entity>|...) [<location>/cancel/yaw:<yaw> pitch:<pitch>] (duration:<duration>) (offthread_repeat:<#>)
// @Required 1
// @Maximum 4
// @Maximum 5
// @Short Causes the NPC or other entity to look at a target location.
// @Synonyms Turn,Face
// @Group entity
Expand All @@ -51,6 +59,9 @@ public LookCommand() {
// If a duration is set, the entity cannot look away from the location until the duration has expired.
// Use the cancel argument to end the duration earlier.
//
// Optionally, you can use the "offthread_repeat:" option alongside "yaw:" and "pitch:"
// to cause a player's rotation to be smoothed out with a specified number of extra async rotation packets within a single tick.
//
// @Tags
// <LocationTag.yaw>
// <LocationTag.pitch>
Expand All @@ -64,70 +75,25 @@ public LookCommand() {
// - look <player> <npc.location> duration:10s
// -->

@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (Argument arg : scriptEntry) {
if (!scriptEntry.hasObject("location")
&& !scriptEntry.hasObject("cancel")
&& arg.limitToOnlyPrefix("location")
&& arg.matchesArgumentType(LocationTag.class)) {
scriptEntry.addObject("location", arg.asType(LocationTag.class));
}
else if (!scriptEntry.hasObject("cancel")
&& !scriptEntry.hasObject("location")
&& arg.matches("cancel")) {
scriptEntry.addObject("cancel", new ElementTag("true"));
}
else if (!scriptEntry.hasObject("yaw")
&& arg.matchesPrefix("yaw")
&& arg.matchesFloat()) {
scriptEntry.addObject("yaw", arg.asElement());
}
else if (!scriptEntry.hasObject("pitch")
&& arg.matchesPrefix("pitch")
&& arg.matchesFloat()) {
scriptEntry.addObject("pitch", arg.asElement());
}
else if (!scriptEntry.hasObject("duration")
&& arg.matchesArgumentType(DurationTag.class)
&& arg.matchesPrefix("duration", "d")) {
scriptEntry.addObject("duration", arg.asType(DurationTag.class));
}
else if (!scriptEntry.hasObject("entities")
&& arg.matchesArgumentList(EntityTag.class)) {
scriptEntry.addObject("entities", arg.asType(ListTag.class).filter(EntityTag.class, scriptEntry));
}
else {
arg.reportUnhandled();
}
}
if (!scriptEntry.hasObject("entities")) {
scriptEntry.defaultObject("entities", Utilities.entryDefaultEntityList(scriptEntry, false));
}
if (!scriptEntry.hasObject("location") && !scriptEntry.hasObject("cancel") && !scriptEntry.hasObject("yaw")) {
throw new InvalidArgumentsException("Must specify a location, a yaw and pitch, or 'cancel'!");
}
if (!scriptEntry.hasObject("entities")) {
throw new InvalidArgumentsException("Must specify an entity!");
}
}

public static HashMap<UUID, BukkitTask> lookTasks = new HashMap<>();

@Override
public void execute(ScriptEntry scriptEntry) {
final LocationTag loc = scriptEntry.getObjectTag("location");
List<EntityTag> entities = (List<EntityTag>) scriptEntry.getObject("entities");
if (entities == null) {
throw new InvalidArgumentsRuntimeException("Missing entity target input");
}
final DurationTag duration = scriptEntry.getObjectTag("duration");
ElementTag yaw = scriptEntry.getElement("yaw");
ElementTag pitch = scriptEntry.getElement("pitch");
ElementTag cancel = scriptEntry.getElement("cancel");
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), cancel, loc, duration, yaw, pitch, db("entities", entities));
public static void autoExecute(ScriptEntry scriptEntry,
@ArgName("entities") @ArgDefaultNull @ArgLinear ObjectTag entitiesObj,
@ArgName("location") @ArgDefaultNull @ArgLinear ObjectTag locationObj,
@ArgName("duration") @ArgDefaultNull @ArgPrefixed DurationTag duration,
@ArgName("yaw") @ArgDefaultNull @ArgPrefixed ElementTag yaw,
@ArgName("pitch") @ArgDefaultNull @ArgPrefixed ElementTag pitch,
@ArgName("offthread_repeat") @ArgDefaultNull @ArgPrefixed ElementTag offthreadRepeats) {
if (!(entitiesObj instanceof ListTag)) {
String entStr = entitiesObj.asElement().asLowerString();
if (entStr.equals("cancel") || entStr.startsWith("l@")) {
Deprecations.outOfOrderArgs.warn(scriptEntry);
ObjectTag swap = entitiesObj;
entitiesObj = locationObj;
locationObj = swap;
}
}
List<EntityTag> entities = entitiesObj.asType(ListTag.class, scriptEntry.context).filter(EntityTag.class, scriptEntry);
for (EntityTag entity : entities) {
if (entity.isSpawned()) {
BukkitTask task = lookTasks.remove(entity.getUUID());
Expand All @@ -136,9 +102,13 @@ public void execute(ScriptEntry scriptEntry) {
}
}
}
if (cancel != null && cancel.asBoolean()) {
if (locationObj != null && !(locationObj instanceof LocationTag) && locationObj.asElement().asLowerString().equals("cancel")) {
return;
}
LocationTag loc = locationObj == null ? null : locationObj.asType(LocationTag.class, scriptEntry.context);
if (loc == null && yaw == null && pitch == null) {
throw new InvalidArgumentsRuntimeException("Missing or invalid Location input!");
}
final float yawRaw = yaw == null ? 0 : yaw.asFloat();
final float pitchRaw = pitch == null ? 0 : pitch.asFloat();
for (EntityTag entity : entities) {
Expand All @@ -149,9 +119,28 @@ public void execute(ScriptEntry scriptEntry) {
else {
if (entity.isPlayer()) {
Location playerTeleDest = entity.getLocation().clone();
float relYaw = yawRaw - playerTeleDest.getYaw();
float relPitch = pitchRaw - playerTeleDest.getPitch();
playerTeleDest.setYaw(yawRaw);
playerTeleDest.setPitch(pitchRaw);
PaperAPITools.instance.teleportPlayerRelative(entity.getPlayer(), playerTeleDest);
Player player = entity.getPlayer();
PaperAPITools.instance.teleportPlayerRelative(player, playerTeleDest);
if (offthreadRepeats != null) {
NetworkInterceptHelper.enable();
int times = offthreadRepeats.asInt();
int ms = 50 / (times + 1);
DenizenCore.runAsync(() -> {
try {
for (int i = 0; i < times; i++) {
Thread.sleep(ms);
NMSHandler.packetHelper.sendRelativeLookPacket(player, relYaw, relPitch);
}
}
catch (Throwable ex) {
Debug.echoError(ex);
}
});
}
}
else {
NMSHandler.entityHelper.rotate(entity.getBukkitEntity(), yawRaw, pitchRaw);
Expand Down
Expand Up @@ -440,6 +440,12 @@ public void sendCollectItemEntity(Player player, Entity taker, Entity item, int
send(player, packet);
}

@Override
public void sendRelativeLookPacket(Player player, float yaw, float pitch) {
ClientboundPlayerPositionPacket packet = new ClientboundPlayerPositionPacket(0, 0, 0, yaw, pitch, ClientboundPlayerPositionPacket.RelativeArgument.ALL, 0, false);
((DenizenNetworkManagerImpl) ((CraftPlayer) player).getHandle().connection.connection).oldManager.channel.writeAndFlush(packet);
}

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

0 comments on commit 383274b

Please sign in to comment.