Skip to content

Commit

Permalink
Refactor PlayerAnimation to accept a collection of players rather tha…
Browse files Browse the repository at this point in the history
…n radius. Rework NPCLinkToPlayerEvent handling
  • Loading branch information
fullwall committed Oct 30, 2023
1 parent d17ca61 commit 401e34a
Show file tree
Hide file tree
Showing 44 changed files with 299 additions and 600 deletions.
19 changes: 9 additions & 10 deletions main/src/main/java/net/citizensnpcs/EventListen.java
Expand Up @@ -433,19 +433,18 @@ public void onNPCKnockback(NPCKnockbackEvent event) {
@EventHandler(ignoreCancelled = true)
public void onNPCLinkToPlayer(NPCLinkToPlayerEvent event) {
NPC npc = event.getNPC();
if (npc.isSpawned() && npc.getEntity().getType() == EntityType.PLAYER) {
onNPCPlayerLinkToPlayer(event);
}

ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
if (crt != null) {
HologramTrait ht = crt.getRedirectNPC().getTraitNullable(HologramTrait.class);
if (ht != null) {
ht.onHologramSeenByPlayer(npc, event.getPlayer());
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
() -> ht.onHologramSeenByPlayer(npc, event.getPlayer()));
}
}

/* TODO
if (npc.isSpawned() && npc.getEntity().getType() == EntityType.PLAYER) {
onNPCPlayerLinkToPlayer(event);
}
*/
}

private void onNPCPlayerLinkToPlayer(NPCLinkToPlayerEvent event) {
Expand All @@ -462,8 +461,8 @@ private void onNPCPlayerLinkToPlayer(NPCLinkToPlayerEvent event) {
boolean sendTabRemove = NMS.sendTabListAdd(event.getPlayer(), (Player) tracker);
if (!sendTabRemove || !Setting.DISABLE_TABLIST.asBoolean()) {
if (resetYaw) {
// Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
// () -> PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer()), 1);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
() -> PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer()));
}
return;
}
Expand All @@ -474,7 +473,7 @@ private void onNPCPlayerLinkToPlayer(NPCLinkToPlayerEvent event) {

NMS.sendTabListRemove(event.getPlayer(), (Player) tracker);
if (resetYaw) {
// PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer());
PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer());
}
}, Setting.TABLIST_REMOVE_PACKET_DELAY.asTicks());
}
Expand Down
Expand Up @@ -1136,7 +1136,8 @@ public void hitbox(CommandContext args, CommandSender sender, NPC npc, @Flag("sc
permission = "citizens.npc.hologram")
public void hologram(CommandContext args, CommandSender sender, NPC npc, @Arg(
value = 1,
completions = { "add", "set", "remove", "clear", "lineheight", "margintop", "marginbottom" }) String action)
completions = { "add", "set", "remove", "clear", "lineheight", "margintop", "marginbottom" }) String action,
@Arg(value = 2, completionsProvider = HologramTrait.TabCompletions.class) String secondCompletion)
throws CommandException {
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
if (args.argsLength() == 1) {
Expand Down
12 changes: 6 additions & 6 deletions main/src/main/java/net/citizensnpcs/npc/CitizensNPC.java
Expand Up @@ -207,8 +207,8 @@ public void load(final DataKey root) {

@Override
public boolean requiresNameHologram() {
return super.requiresNameHologram() || (getEntityType() != EntityType.ARMOR_STAND
&& !getEntityType().name().equals("TEXT_DISPLAY") && Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean());
return super.requiresNameHologram()
|| (Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean() && !data().has(NPC.Metadata.HOLOGRAM_FOR));
}

private void resetCachedCoord() {
Expand Down Expand Up @@ -646,11 +646,11 @@ private void updateUsingItemState(Player player) {

try {
if (useItem) {
NMS.playAnimation(PlayerAnimation.STOP_USE_ITEM, player, 64);
NMS.playAnimation(PlayerAnimation.START_USE_MAINHAND_ITEM, player, 64);
PlayerAnimation.STOP_USE_ITEM.play(player, 64);
PlayerAnimation.START_USE_MAINHAND_ITEM.play(player, 64);
} else if (offhand) {
NMS.playAnimation(PlayerAnimation.STOP_USE_ITEM, player, 64);
NMS.playAnimation(PlayerAnimation.START_USE_OFFHAND_ITEM, player, 64);
PlayerAnimation.STOP_USE_ITEM.play(player, 64);
PlayerAnimation.START_USE_OFFHAND_ITEM.play(player, 64);
}
} catch (UnsupportedOperationException ex) {
SUPPORT_USE_ITEM = false;
Expand Down
37 changes: 22 additions & 15 deletions main/src/main/java/net/citizensnpcs/trait/HologramTrait.java
@@ -1,34 +1,41 @@
package net.citizensnpcs.trait;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.command.Arg.CompletionsProvider;
import net.citizensnpcs.api.command.CommandContext;
import net.citizensnpcs.api.npc.MemoryNPCDataStore;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.api.util.SpigotUtil;
import net.citizensnpcs.util.NMS;
Expand Down Expand Up @@ -109,6 +116,7 @@ private NPC createHologram(String line, double heightOffset) {
hologramNPC.addTrait(PacketNPC.class);
}

hologramNPC.data().set(NPC.Metadata.HOLOGRAM_FOR, npc.getUniqueId().toString());
hologramNPC.spawn(currentLoc.clone().add(0, getEntityHeight() + heightOffset, 0));

Matcher itemMatcher = ITEM_MATCHER.matcher(line);
Expand Down Expand Up @@ -227,6 +235,7 @@ public void onHologramSeenByPlayer(NPC hologram, Player player) {
if (height == -1)
return;

Messaging.debug(npc, "hologram interaction ", hologram.getEntity(), "height offset set to", height);
NMS.linkTextInteraction(player, hologram.getEntity(), npc.getEntity(), height);
}
}
Expand Down Expand Up @@ -327,10 +336,6 @@ public void run() {
nameLine.hologram.teleport(npcLoc.clone().add(0, getEntityHeight(), 0), TeleportCause.PLUGIN);
}

if (useDisplayEntities && nameLine.hologram.getEntity().getVehicle() == null) {
npc.getEntity().addPassenger(nameLine.hologram.getEntity());
}

if (updateName) {
nameLine.setText(npc.getRawName());
}
Expand All @@ -354,10 +359,6 @@ public void run() {
hologramNPC.teleport(tp, TeleportCause.PLUGIN);
}

if (useDisplayEntities && hologramNPC.getEntity().getVehicle() == null) {
npc.getEntity().addPassenger(hologramNPC.getEntity());
}

String text = line.text;
if (ITEM_MATCHER.matcher(text).matches()) {
hologramNPC.data().set(NPC.Metadata.NAMEPLATE_VISIBLE, false);
Expand Down Expand Up @@ -511,13 +512,19 @@ public void spawnNPC(double height) {
}
}

private static final Pattern ITEM_MATCHER = Pattern.compile("<item:(.*?)([:].*?)?>");
private static boolean SUPPORTS_TEXT_DISPLAY = false;
static {
try {
EntityType.valueOf("TEXT_DISPLAY");
SUPPORTS_TEXT_DISPLAY = true;
} catch (IllegalArgumentException iae) {
public static class TabCompletions implements CompletionsProvider {
@Override
public Collection<String> getCompletions(CommandContext args, CommandSender sender, NPC npc) {
if (npc != null && LINE_ARGS.contains(args.getString(1).toLowerCase())) {
HologramTrait ht = npc.getOrAddTrait(HologramTrait.class);
return IntStream.range(0, ht.getLines().size()).mapToObj(Integer::toString)
.collect(Collectors.toList());
}
return Collections.emptyList();
}

private static final List<String> LINE_ARGS = ImmutableList.of("set", "remove", "margintop", "marginbottom");
}

private static final Pattern ITEM_MATCHER = Pattern.compile("<item:(.*?)([:].*?)?>");
}
4 changes: 2 additions & 2 deletions main/src/main/java/net/citizensnpcs/util/NMS.java
Expand Up @@ -683,8 +683,8 @@ public static void openHorseScreen(Tameable horse, Player equipper) {
BRIDGE.openHorseScreen(horse, equipper);
}

public static void playAnimation(PlayerAnimation animation, Player player, int radius) {
BRIDGE.playAnimation(animation, player, radius);
public static void playAnimation(PlayerAnimation animation, Player player, Iterable<Player> to) {
BRIDGE.playAnimation(animation, player, to);
}

public static Runnable playerTicker(Player entity) {
Expand Down
2 changes: 1 addition & 1 deletion main/src/main/java/net/citizensnpcs/util/NMSBridge.java
Expand Up @@ -146,7 +146,7 @@ public default void onPlayerInfoAdd(Player player, Object source, Function<UUID,

public void openHorseScreen(Tameable horse, Player equipper);

public void playAnimation(PlayerAnimation animation, Player player, int radius);
public void playAnimation(PlayerAnimation animation, Player player, Iterable<Player> to);

public Runnable playerTicker(Player entity);;

Expand Down
40 changes: 35 additions & 5 deletions main/src/main/java/net/citizensnpcs/util/PlayerAnimation.java
@@ -1,11 +1,17 @@
package net.citizensnpcs.util;

import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.scheduler.BukkitRunnable;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.MemoryNPCDataStore;
import net.citizensnpcs.api.npc.NPC;
Expand Down Expand Up @@ -39,17 +45,33 @@ public void play(Player player) {
play(player, 64);
}

public void play(Player player, int radius) {
public void play(Player from, int radius) {
Location loc = from.getLocation();
Location cloc = new Location(null, 0, 0, 0);
List<Player> to = Lists.newArrayList();
for (Player player : CitizensAPI.getLocationLookup().getNearbyPlayers(loc, radius)) {
if (loc.getWorld() != player.getWorld() || !player.canSee(from)
|| loc.distance(player.getLocation(cloc)) > radius) {
continue;
}
to.add(player);
}
play(from, to);
}

public void play(Player player, Iterable<Player> to) {
if (this == SIT) {
if (player instanceof NPCHolder) {
((NPCHolder) player).getNPC().getOrAddTrait(SitTrait.class).setSitting(player.getLocation());
return;
}

player.setMetadata("citizens.sitting", new FixedMetadataValue(CitizensAPI.getPlugin(), true));
NPCRegistry registry = CitizensAPI.getNamedNPCRegistry("PlayerAnimationImpl");
if (registry == null) {
registry = CitizensAPI.createNamedNPCRegistry("PlayerAnimationImpl", new MemoryNPCDataStore());
}

final NPC holder = registry.createNPC(EntityType.ARMOR_STAND, "");
holder.getOrAddTrait(ArmorStandTrait.class).setAsPointEntity();
holder.spawn(player.getLocation());
Expand Down Expand Up @@ -96,13 +118,15 @@ public void run() {
}
return;
} else if (this == STOP_USE_ITEM || this == START_USE_MAINHAND_ITEM || this == START_USE_OFFHAND_ITEM) {
NMS.playAnimation(this, player, radius);
NMS.playAnimation(this, player, to);
if (player.hasMetadata("citizens-using-item-id")) {
Bukkit.getScheduler().cancelTask(player.getMetadata("citizens-using-item-id").get(0).asInt());
player.removeMetadata("citizens-using-item-id", CitizensAPI.getPlugin());
}

if (this == STOP_USE_ITEM)
return;

if (player.hasMetadata("citizens-using-item-remaining-ticks")) {
int remainingTicks = player.getMetadata("citizens-using-item-remaining-ticks").get(0).asInt();
new BukkitRunnable() {
Expand All @@ -113,8 +137,8 @@ public void run() {
return;
}

NMS.playAnimation(PlayerAnimation.STOP_USE_ITEM, player, radius);
NMS.playAnimation(PlayerAnimation.this, player, radius);
NMS.playAnimation(PlayerAnimation.STOP_USE_ITEM, player, to);
NMS.playAnimation(PlayerAnimation.this, player, to);
if (!player.hasMetadata("citizens-using-item-id")) {
player.setMetadata("citizens-using-item-id",
new FixedMetadataValue(CitizensAPI.getPlugin(), getTaskId()));
Expand All @@ -123,8 +147,14 @@ public void run() {
}.runTaskTimer(CitizensAPI.getPlugin(), Math.max(0, remainingTicks + 1),
Math.max(1, remainingTicks + 1));
}

return;
}
NMS.playAnimation(this, player, radius);

NMS.playAnimation(this, player, to);
}

public void play(Player player, Player to) {
play(player, ImmutableList.of(to));
}
}
Expand Up @@ -961,8 +961,8 @@ public void openHorseScreen(Tameable horse, Player equipper) {
}

@Override
public void playAnimation(PlayerAnimation animation, Player player, int radius) {
PlayerAnimationImpl.play(animation, player, radius);
public void playAnimation(PlayerAnimation animation, Player player, Iterable<Player> to) {
PlayerAnimationImpl.play(animation, player, to);
}

@Override
Expand Down
Expand Up @@ -14,18 +14,17 @@
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityMetadata;

public class PlayerAnimationImpl {
public static void play(PlayerAnimation animation, Player bplayer, int radius) {
public static void play(PlayerAnimation animation, Player bplayer, Iterable<Player> to) {
// TODO: this is pretty gross
final EntityPlayer player = (EntityPlayer) NMSImpl.getHandle(bplayer);
if (DEFAULTS.containsKey(animation)) {
playDefaultAnimation(player, radius, DEFAULTS.get(animation));
playDefaultAnimation(player, to, DEFAULTS.get(animation));
return;
}
switch (animation) {
case SNEAK:
player.getBukkitEntity().setSneaking(true);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), player,
radius);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), to);
break;
case START_ELYTRA:
player.M();
Expand All @@ -35,36 +34,34 @@ public static void play(PlayerAnimation animation, Player bplayer, int radius) {
break;
case START_USE_MAINHAND_ITEM:
player.c(EnumHand.MAIN_HAND);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), player,
radius);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), to);
break;
case START_USE_OFFHAND_ITEM:
player.c(EnumHand.OFF_HAND);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), player,
radius);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), to);
break;
case STOP_SNEAKING:
player.getBukkitEntity().setSneaking(false);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), player,
radius);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), to);
break;
case STOP_USE_ITEM:
player.clearActiveItem();
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), player,
radius);
sendPacketNearby(new PacketPlayOutEntityMetadata(player.getId(), player.getDataWatcher(), true), to);
break;
default:
throw new UnsupportedOperationException();
}
}

protected static void playDefaultAnimation(EntityPlayer player, int radius, int code) {
protected static void playDefaultAnimation(EntityPlayer player, Iterable<Player> to, int code) {
PacketPlayOutAnimation packet = new PacketPlayOutAnimation(player, code);
sendPacketNearby(packet, player, radius);
sendPacketNearby(packet, to);
}

protected static void sendPacketNearby(Packet<?> packet, EntityPlayer player, int radius) {
NMSImpl.sendPacketNearby(player.getBukkitEntity(), player.getBukkitEntity().getLocation(), packet, radius);
protected static void sendPacketNearby(Packet<?> packet, Iterable<Player> to) {
for (Player player : to) {
NMSImpl.sendPacket(player, packet);
}
}

private static EnumMap<PlayerAnimation, Integer> DEFAULTS = Maps.newEnumMap(PlayerAnimation.class);
Expand Down

0 comments on commit 401e34a

Please sign in to comment.