feat: Implement forced nametag functionality for players

This commit is contained in:
AlexDev_ committed 2025-12-27 22:58:47 +01:00
1 parent 7fd168d6c2
commit 0006cf83a0
3 files changed
+128 -9

No files matched your search

+1 -1
View File
@@ -1 +1 @@
version = 1.6.10
version = 1.6.11
@@ -2,6 +2,7 @@ package org.alexdev.unlimitednametags.api;
import me.tofaa.entitylib.meta.display.AbstractDisplayMeta;
import net.kyori.adventure.text.Component;
import org.alexdev.unlimitednametags.UnlimitedNameTags;
import org.alexdev.unlimitednametags.config.Settings;
import org.alexdev.unlimitednametags.hook.hat.HatHook;
@@ -359,6 +360,60 @@ public class UNTAPI {
plugin.getNametagManager().setNametagOverride(player, modified);
}
/**
* Forces a specific component as the nametag for a player.
* This overrides any existing nametag configuration or overrides.
*
* @param player the player whose nametag should be forced
* @param component the component to display as the nametag
*/
public void setForcedNametag(@NotNull Player player, @NotNull Component component) {
plugin.getNametagManager().getPacketDisplayText(player).ifPresent(packetNameTag -> {
packetNameTag.setForcedNameTag(component);
packetNameTag.refresh();
});
}
/**
* Forces a specific component as the nametag for a player, visible only to a specific viewer.
* This overrides any existing nametag configuration or overrides for that specific viewer.
*
* @param player the player whose nametag should be forced
* @param viewer the player who will see the forced nametag
* @param component the component to display as the nametag
*/
public void setForcedNametag(@NotNull Player player, @NotNull Player viewer, @NotNull Component component) {
plugin.getNametagManager().getPacketDisplayText(player).ifPresent(packetNameTag -> {
packetNameTag.setForcedNameTag(viewer.getUniqueId(), component);
packetNameTag.refreshForPlayer(viewer);
});
}
/**
* Clears the forced nametag for a player.
*
* @param player the player whose forced nametag should be cleared
*/
public void clearForcedNametag(@NotNull Player player) {
plugin.getNametagManager().getPacketDisplayText(player).ifPresent(packetNameTag -> {
packetNameTag.clearForcedNameTag();
packetNameTag.refresh();
});
}
/**
* Clears the forced nametag for a player, for a specific viewer.
*
* @param player the player whose forced nametag should be cleared
* @param viewer the player who was seeing the forced nametag
*/
public void clearForcedNametag(@NotNull Player player, @NotNull Player viewer) {
plugin.getNametagManager().getPacketDisplayText(player).ifPresent(packetNameTag -> {
packetNameTag.clearForcedNameTag(viewer.getUniqueId());
packetNameTag.refreshForPlayer(viewer);
});
}
static final class NotRegisteredException extends IllegalStateException {
private static final String MESSAGE = """
@@ -27,6 +27,7 @@ import org.bukkit.Location;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Consumer;
@@ -43,6 +44,9 @@ public class PacketNameTag {
private final Set<UUID> blocked;
@NotNull
private final Map<UUID, Component> relationalCache;
private final Map<UUID, Component> calculatedTextCache = Maps.newConcurrentMap();
private final Map<UUID, Component> forcedRelationalText = Maps.newConcurrentMap();
private volatile Component forcedGlobalText = null;
private long lastUpdate;
@Setter
private boolean visible;
@@ -51,7 +55,7 @@ public class PacketNameTag {
private float scale;
private float offset;
private float increasedOffset;
private boolean removed;
private volatile boolean removed;
@Setter
private boolean sneaking;
@@ -84,6 +88,16 @@ public class PacketNameTag {
return false;
}
calculatedTextCache.put(player.getUniqueId(), text);
if (forcedRelationalText.containsKey(player.getUniqueId()) || forcedGlobalText != null) {
return false;
}
return applyText(player, text);
}
private boolean applyText(@NotNull Player player, @NotNull Component text) {
if (text.equals(relationalCache.get(player.getUniqueId()))) {
return false;
}
@@ -99,7 +113,7 @@ public class PacketNameTag {
return true;
}
public void modify(User user, Consumer<TextDisplayMeta> consumer) {
public void modify(@Nullable User user, @NotNull Consumer<TextDisplayMeta> consumer) {
if (removed) {
return;
}
@@ -114,7 +128,7 @@ public class PacketNameTag {
});
}
public void modifyOwner(Consumer<TextDisplayMeta> consumer) {
public void modifyOwner(@NotNull Consumer<TextDisplayMeta> consumer) {
if (removed) {
return;
}
@@ -127,7 +141,7 @@ public class PacketNameTag {
modify(owner, consumer);
}
public void modifyOwnerEntity(Consumer<WrapperEntity> consumer) {
public void modifyOwnerEntity(@NotNull Consumer<WrapperEntity> consumer) {
if (removed) {
return;
}
@@ -140,7 +154,7 @@ public class PacketNameTag {
modifyEntity(owner, consumer);
}
public void modify(Consumer<TextDisplayMeta> consumer) {
public void modify(@NotNull Consumer<TextDisplayMeta> consumer) {
if (removed) {
return;
}
@@ -151,7 +165,7 @@ public class PacketNameTag {
});
}
public void modifyEntity(User user, Consumer<WrapperEntity> consumer) {
public void modifyEntity(@Nullable User user, @NotNull Consumer<WrapperEntity> consumer) {
if (removed) {
return;
}
@@ -159,7 +173,7 @@ public class PacketNameTag {
perPlayerEntity.modify(user, consumer);
}
public void modifyEntity(Consumer<WrapperEntity> consumer) {
public void modifyEntity(@NotNull Consumer<WrapperEntity> consumer) {
if (removed) {
return;
}
@@ -354,7 +368,7 @@ public class PacketNameTag {
}
private boolean hasRequiredPermissions(@NotNull Player player) {
boolean isOwner = isOwner(player);
final boolean isOwner = isOwner(player);
if (!isOwner && !player.hasPermission("unt.shownametags")) {
return false;
}
@@ -439,6 +453,7 @@ public class PacketNameTag {
}
relationalCache.remove(player.getUniqueId());
calculatedTextCache.remove(player.getUniqueId());
plugin.getPacketManager().removePassenger(player, entityId);
}
@@ -463,6 +478,7 @@ public class PacketNameTag {
}
perPlayerEntity.getEntities().remove(player.getUniqueId());
relationalCache.remove(player.getUniqueId());
calculatedTextCache.remove(player.getUniqueId());
}
public boolean canPlayerSee(@NotNull Player player) {
@@ -520,6 +536,9 @@ public class PacketNameTag {
plugin.getPacketManager().removePassenger(entityId);
relationalCache.clear();
calculatedTextCache.clear();
forcedRelationalText.clear();
forcedGlobalText = null;
}
public void handleQuit(@NotNull Player player) {
@@ -571,6 +590,51 @@ public class PacketNameTag {
return properties;
}
public void setForcedNameTag(@NotNull Component component) {
this.forcedGlobalText = component;
updateAllViewers();
}
public void setForcedNameTag(@NotNull UUID viewer, @NotNull Component component) {
this.forcedRelationalText.put(viewer, component);
updateViewer(viewer);
}
public void clearForcedNameTag() {
this.forcedGlobalText = null;
updateAllViewers();
}
public void clearForcedNameTag(@NotNull UUID viewer) {
this.forcedRelationalText.remove(viewer);
updateViewer(viewer);
}
private void updateAllViewers() {
for (final UUID uuid : getViewers()) {
updateViewer(uuid);
}
}
private void updateViewer(@NotNull UUID uuid) {
final Player player = Bukkit.getPlayer(uuid);
if (player == null) return;
Component textToUse = calculatedTextCache.get(uuid);
if (forcedRelationalText.containsKey(uuid)) {
textToUse = forcedRelationalText.get(uuid);
} else if (forcedGlobalText != null) {
textToUse = forcedGlobalText;
}
if (textToUse != null) {
if (applyText(player, textToUse)) {
refreshForPlayer(player);
}
}
}
/**
* Returns an unmodifiable set containing the viewers of the nametag.
*