diff --git a/build.gradle.kts b/build.gradle.kts index 04f4b46..876a513 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -73,13 +73,9 @@ tasks { downloadPlugins { hangar("ViaVersion", "5.0.1") hangar("ViaBackwards", "5.0.1") - hangar("PlaceholderAPI", "2.11.6") // For testing groups in config.yml url("https://download.luckperms.net/1556/bukkit/loader/LuckPerms-Bukkit-5.4.141.jar") - - // For testing TAB hook - github("NEZNAMY", "TAB", "4.1.8", "TAB.v4.1.8.jar") } } } diff --git a/src/main/java/com/mattmx/nametags/EventsListener.java b/src/main/java/com/mattmx/nametags/EventsListener.java index 3fc25d7..0764262 100644 --- a/src/main/java/com/mattmx/nametags/EventsListener.java +++ b/src/main/java/com/mattmx/nametags/EventsListener.java @@ -1,11 +1,7 @@ package com.mattmx.nametags; -import com.mattmx.nametags.config.TextDisplayMetaConfiguration; import com.mattmx.nametags.entity.NameTagEntity; -import com.mattmx.nametags.entity.trait.RefreshTrait; import com.mattmx.nametags.entity.trait.SneakTrait; -import com.mattmx.nametags.event.NameTagEntityCreateEvent; -import org.bukkit.Color; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; @@ -18,11 +14,10 @@ public class EventsListener implements Listener { @EventHandler public void onPlayerJoin(@NotNull PlayerJoinEvent event) { - final NameTagEntity tag = NameTags.getInstance() + NameTags.getInstance() .getEntityManager() - .getOrCreateNameTagEntity(event.getPlayer()); - - tag.updateVisibility(); + .getOrCreateNameTagEntity(event.getPlayer()) + .updateVisibility(); } @EventHandler diff --git a/src/main/java/com/mattmx/nametags/NameTags.java b/src/main/java/com/mattmx/nametags/NameTags.java index 3dfaecd..badb7a5 100644 --- a/src/main/java/com/mattmx/nametags/NameTags.java +++ b/src/main/java/com/mattmx/nametags/NameTags.java @@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEventsAPI; import com.mattmx.nametags.config.ConfigDefaultsListener; import com.mattmx.nametags.entity.NameTagEntityManager; +import com.mattmx.nametags.hook.GlowingEffectHook; import com.mattmx.nametags.hook.NeznamyTABHook; import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.EntityLib; @@ -11,6 +12,7 @@ import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.HandlerList; import org.bukkit.permissions.Permission; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -50,6 +52,7 @@ public void onEnable() { final PacketEventsAPI packetEvents = PacketEvents.getAPI(); packetEvents.getEventManager().registerListener(packetListener); +// packetEvents.getEventManager().registerListener(new GlowingEffectHook()); NeznamyTABHook.inject(this); diff --git a/src/main/java/com/mattmx/nametags/NameTagsCommand.java b/src/main/java/com/mattmx/nametags/NameTagsCommand.java index e8b9f96..b303a38 100644 --- a/src/main/java/com/mattmx/nametags/NameTagsCommand.java +++ b/src/main/java/com/mattmx/nametags/NameTagsCommand.java @@ -1,11 +1,17 @@ package com.mattmx.nametags; +import com.mattmx.nametags.entity.NameTagEntity; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.util.UUID; + public class NameTagsCommand implements CommandExecutor { private final @NotNull NameTags plugin; @@ -16,7 +22,24 @@ public NameTagsCommand(@NotNull NameTags plugin) { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { this.plugin.reloadConfig(); - sender.sendMessage(Component.text("Reloaded!")); + + for (final Player player : Bukkit.getOnlinePlayers()) { + final NameTagEntity tag = plugin.getEntityManager().removeEntity(player); + + if (tag == null) continue; + + tag.destroy(); + + final NameTagEntity newTag = plugin.getEntityManager().getOrCreateNameTagEntity(player); + + for (final UUID viewer : tag.getPassenger().getViewers()) { + newTag.getPassenger().addViewer(viewer); + } + + newTag.updateVisibility(); + } + + sender.sendMessage(Component.text("Reloaded!").color(NamedTextColor.GREEN)); return false; } } diff --git a/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java b/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java index 92b8d8c..aa83d81 100644 --- a/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java +++ b/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java @@ -54,6 +54,7 @@ public void onPacketSend(@NotNull PacketSendEvent event) { } } case PacketType.Play.Server.ENTITY_EFFECT -> { + // TODO per-player impl final WrapperPlayServerEntityEffect packet = new WrapperPlayServerEntityEffect(event); if (packet.getPotionType() != PotionTypes.INVISIBILITY) return; @@ -65,6 +66,7 @@ public void onPacketSend(@NotNull PacketSendEvent event) { nameTagEntity.updateVisibility(true); } case PacketType.Play.Server.REMOVE_ENTITY_EFFECT -> { + // TODO per-player impl final WrapperPlayServerRemoveEntityEffect packet = new WrapperPlayServerRemoveEntityEffect(event); if (packet.getPotionType() != PotionTypes.INVISIBILITY) return; diff --git a/src/main/java/com/mattmx/nametags/config/ConfigDefaultsListener.java b/src/main/java/com/mattmx/nametags/config/ConfigDefaultsListener.java index 4154f5d..ff31072 100644 --- a/src/main/java/com/mattmx/nametags/config/ConfigDefaultsListener.java +++ b/src/main/java/com/mattmx/nametags/config/ConfigDefaultsListener.java @@ -32,12 +32,20 @@ private ConfigurationSection defaultSection() { public void onCreate(@NotNull NameTagEntityCreateEvent event) { if (!(event.getNameTag().getBukkitEntity() instanceof Player player)) return; + // By default, we shouldn't notify until we have finished processing. + event.getNameTag() + .getPassenger() + .getEntityMeta() + .setNotifyAboutChanges(false); + + long refreshMillis = plugin.getConfig().getLong("defaults.refresh-every", 50); + event.getNameTag() .getTraits() .getOrAddTrait(RefreshTrait.class, () -> - RefreshTrait.ofSeconds( - NameTags.getInstance(), - 1L, + RefreshTrait.ofMillis( + plugin, + refreshMillis, (entity) -> { TextDisplayMetaConfiguration.applyMeta(defaultSection(), entity.getMeta()); TextDisplayMetaConfiguration.applyTextMeta(defaultSection(), entity.getMeta(), player, player); @@ -52,13 +60,13 @@ public void onCreate(@NotNull NameTagEntityCreateEvent event) { TextDisplayMetaConfiguration.applyTextMeta(e.getValue(), entity.getMeta(), player, player); }); - entity.updateVisibility(); if (entity.getMeta().getBillboardConstraints() == AbstractDisplayMeta.BillboardConstraints.CENTER) { // Look passenger down to remove debug getting in the way entity.getPassenger().rotateHead(0f, 90f); } + entity.updateVisibility(); entity.getPassenger().refresh(); } ) diff --git a/src/main/java/com/mattmx/nametags/config/ConfigHelper.java b/src/main/java/com/mattmx/nametags/config/ConfigHelper.java index c5ed5b8..8f11cdd 100644 --- a/src/main/java/com/mattmx/nametags/config/ConfigHelper.java +++ b/src/main/java/com/mattmx/nametags/config/ConfigHelper.java @@ -18,6 +18,8 @@ public class ConfigHelper { @NotNull Function provider, @NotNull Consumer take ) { + if (section.get(key) == null) return null; + Optional optional = Optional.ofNullable(provider.apply(key)); optional.ifPresent(take); diff --git a/src/main/java/com/mattmx/nametags/config/TextDisplayMetaConfiguration.java b/src/main/java/com/mattmx/nametags/config/TextDisplayMetaConfiguration.java index 1f70f02..f4b6285 100644 --- a/src/main/java/com/mattmx/nametags/config/TextDisplayMetaConfiguration.java +++ b/src/main/java/com/mattmx/nametags/config/TextDisplayMetaConfiguration.java @@ -67,7 +67,6 @@ public static void applyMeta(@NotNull ConfigurationSection section, @NotNull Tex } }); - // TODO(matt): impl other features ConfigHelper.takeIfPresent(section, "see-through", section::getBoolean, (seeThrough) -> { if (to.isSeeThrough() != seeThrough) { to.setSeeThrough(seeThrough); diff --git a/src/main/java/com/mattmx/nametags/entity/trait/RefreshTrait.java b/src/main/java/com/mattmx/nametags/entity/trait/RefreshTrait.java index fb13a34..e5ee3db 100644 --- a/src/main/java/com/mattmx/nametags/entity/trait/RefreshTrait.java +++ b/src/main/java/com/mattmx/nametags/entity/trait/RefreshTrait.java @@ -46,8 +46,12 @@ public void onDestroy() { return new RefreshTrait(plugin, seconds, TimeUnit.SECONDS, update); } + public static @NotNull RefreshTrait ofMillis(@NotNull JavaPlugin plugin, long millis, Consumer update) { + return new RefreshTrait(plugin, millis, TimeUnit.MILLISECONDS, update); + } + public static @NotNull RefreshTrait ofTicks(@NotNull JavaPlugin plugin, long ticks, Consumer update) { - return new RefreshTrait(plugin, ticks * 50, TimeUnit.MILLISECONDS, update); + return ofMillis(plugin, ticks * 50, update); } } diff --git a/src/main/java/com/mattmx/nametags/hook/GlowingEffectHook.java b/src/main/java/com/mattmx/nametags/hook/GlowingEffectHook.java new file mode 100644 index 0000000..b9aefa5 --- /dev/null +++ b/src/main/java/com/mattmx/nametags/hook/GlowingEffectHook.java @@ -0,0 +1,38 @@ +package com.mattmx.nametags.hook; + +import com.github.retrooper.packetevents.event.PacketListenerAbstract; +import com.github.retrooper.packetevents.event.PacketSendEvent; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata; +import com.mattmx.nametags.NameTags; +import com.mattmx.nametags.entity.NameTagEntity; +import me.tofaa.entitylib.meta.EntityMeta; +import me.tofaa.entitylib.meta.Metadata; + +public class GlowingEffectHook extends PacketListenerAbstract { + + @Override + public void onPacketSend(PacketSendEvent event) { + if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) return; + final WrapperPlayServerEntityMetadata packet = new WrapperPlayServerEntityMetadata(event); + + final NameTagEntity entity = NameTags.getInstance() + .getEntityManager() + .getNameTagEntityById(packet.getEntityId()); + + if (entity == null) return; + + Metadata meta = new Metadata(packet.getEntityId()); + + packet.getEntityMetadata().forEach((entry) -> meta.setIndex((byte) entry.getIndex(), (EntityDataType) entry.getType(), entry.getValue())); + + EntityMeta wrapper = new EntityMeta(packet.getEntityId(), meta); + + if (wrapper.isGlowing()) { + entity.modify((tagMeta) -> { + tagMeta.setSeeThrough(true); + }); + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e8f675e..3719f0e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -9,6 +9,8 @@ sneak: defaults: # If not enabled then plugin simulates vanilla name tags enabled: true + # How often should we refresh tags (in milliseconds) + refresh-every: 50 text: - "%player_name%" - "%player_ping%ms"