feat: Custom guild chat format and NametagManager for above-head & tablist guild tags

This commit is contained in:
2026-08-20 21:28:45 +02:00
parent cbe9089699
commit 56231af30d
5 changed files with 255 additions and 1 deletions
+13
View File
@@ -33,6 +33,7 @@ public final class Main extends JavaPlugin {
private EconomyManager economyManager; private EconomyManager economyManager;
private fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager; private fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager;
private GuildManager guildManager; private GuildManager guildManager;
private fr.luc.gamingcore.manager.NametagManager nametagManager;
private BetterMcCommands betterMcCommands; private BetterMcCommands betterMcCommands;
/** /**
@@ -64,6 +65,8 @@ public final class Main extends JavaPlugin {
// 6. Initialiser le service métier GuildManager et charger les données // 6. Initialiser le service métier GuildManager et charger les données
this.guildManager = new GuildManager(this, guildRepository, economyManager, worldGuardManager); this.guildManager = new GuildManager(this, guildRepository, economyManager, worldGuardManager);
this.nametagManager = new fr.luc.gamingcore.manager.NametagManager(this, guildManager);
this.guildManager.setNametagManager(nametagManager);
loadConfigSettings(); loadConfigSettings();
this.guildManager.loadData(); this.guildManager.loadData();
@@ -75,6 +78,7 @@ public final class Main extends JavaPlugin {
PluginManager pm = getServer().getPluginManager(); PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new TerritoryProtectionListener(this), this); pm.registerEvents(new TerritoryProtectionListener(this), this);
pm.registerEvents(new fr.luc.gamingcore.listener.GuildChatListener(this), this); pm.registerEvents(new fr.luc.gamingcore.listener.GuildChatListener(this), this);
pm.registerEvents(new fr.luc.gamingcore.listener.NametagListener(this), this);
getLogger().info("GamingCore (Système de Guilde - Cœur Métier & Commandes) a ete active avec succes !"); getLogger().info("GamingCore (Système de Guilde - Cœur Métier & Commandes) a ete active avec succes !");
} }
@@ -265,4 +269,13 @@ public final class Main extends JavaPlugin {
public BetterMcCommands getBetterMcCommands() { public BetterMcCommands getBetterMcCommands() {
return betterMcCommands; return betterMcCommands;
} }
/**
* Obtient le gestionnaire de Nametags et TabList.
*
* @return L'instance NametagManager.
*/
public fr.luc.gamingcore.manager.NametagManager getNametagManager() {
return nametagManager;
}
} }
@@ -0,0 +1,55 @@
package fr.luc.gamingcore.listener;
import fr.luc.gamingcore.Main;
import fr.luc.gamingcore.manager.NametagManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
/**
* Écouteur gérant l'assignation automatique des Nametags et noms TabList à la connexion/déconnexion des joueurs.
*/
public class NametagListener implements Listener {
private final Main plugin;
private final NametagManager nametagManager;
/**
* Constructeur de l'écouteur de Nametags.
*
* @param plugin Instance principale du plugin.
*/
public NametagListener(Main plugin) {
this.plugin = plugin;
this.nametagManager = plugin.getNametagManager();
}
/**
* Met à jour le tag au-dessus de la tête et dans la TabList lors de la connexion.
*
* @param event L'événement PlayerJoinEvent.
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
// Léger délai d'un tick pour laisser le client charger le scoreboard
plugin.getServer().getScheduler().runTask(plugin, () -> {
if (player.isOnline()) {
nametagManager.updatePlayer(player);
}
});
}
/**
* Nettoie les entrées de scoreboard à la déconnexion.
*
* @param event L'événement PlayerQuitEvent.
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
nametagManager.removePlayer(event.getPlayer());
}
}
@@ -30,6 +30,7 @@ public class GuildManager {
private final ChunkPriceCalculator priceCalculator; private final ChunkPriceCalculator priceCalculator;
private final InviteManager inviteManager; private final InviteManager inviteManager;
private final MessageManager messageManager; private final MessageManager messageManager;
private NametagManager nametagManager;
// Indexations en mémoire pour des lookups O(1) // Indexations en mémoire pour des lookups O(1)
private final Map<UUID, Guild> guildsById = new ConcurrentHashMap<>(); private final Map<UUID, Guild> guildsById = new ConcurrentHashMap<>();
@@ -55,6 +56,10 @@ public class GuildManager {
this.messageManager = plugin.getMessageManager(); this.messageManager = plugin.getMessageManager();
} }
public void setNametagManager(NametagManager nametagManager) {
this.nametagManager = nametagManager;
}
/** /**
* Charge toutes les données depuis la base de données SQLite en mémoire. * Charge toutes les données depuis la base de données SQLite en mémoire.
*/ */
@@ -80,6 +85,10 @@ public class GuildManager {
if (worldGuardManager != null && worldGuardManager.isEnabled()) { if (worldGuardManager != null && worldGuardManager.isEnabled()) {
worldGuardManager.syncAllGuilds(new ArrayList<>(loadedGuilds)); worldGuardManager.syncAllGuilds(new ArrayList<>(loadedGuilds));
} }
if (nametagManager != null) {
nametagManager.updateAll();
}
} }
/** /**
@@ -214,6 +223,10 @@ public class GuildManager {
worldGuardManager.createOrUpdateRegion(guild, loc.getWorld(), chunkX, chunkZ); worldGuardManager.createOrUpdateRegion(guild, loc.getWorld(), chunkX, chunkZ);
} }
if (nametagManager != null) {
nametagManager.updatePlayer(founder);
}
logAction(guild, founder, "CREATION", "Création de la guilde avec le chunk initial (" + chunkX + ", " + chunkZ + ")"); logAction(guild, founder, "CREATION", "Création de la guilde avec le chunk initial (" + chunkX + ", " + chunkZ + ")");
return GuildResult.success("La guilde " + guild.getFormattedName() + " a été créée avec succès !"); return GuildResult.success("La guilde " + guild.getFormattedName() + " a été créée avec succès !");
@@ -244,6 +257,18 @@ public class GuildManager {
worldGuardManager.removeGuildRegions(guild); worldGuardManager.removeGuildRegions(guild);
} }
if (nametagManager != null) {
for (GuildMember m : guild.getMembers()) {
if (m.getOfflinePlayer() != null && m.getOfflinePlayer().isOnline()) {
Player p = m.getOfflinePlayer().getPlayer();
if (p != null) {
nametagManager.updatePlayer(p);
}
}
}
nametagManager.removeGuildTeam(guild.getId());
}
unindexGuild(guild); unindexGuild(guild);
repository.deleteGuildAsync(guild.getId()); repository.deleteGuildAsync(guild.getId());
@@ -280,6 +305,10 @@ public class GuildManager {
worldGuardManager.syncGuildMembers(guild); worldGuardManager.syncGuildMembers(guild);
} }
if (nametagManager != null) {
nametagManager.updatePlayer(player);
}
logAction(guild, player, "JOIN", player.getName() + " a rejoint la guilde (" + defaultRank.getName() + ")"); logAction(guild, player, "JOIN", player.getName() + " a rejoint la guilde (" + defaultRank.getName() + ")");
broadcastToGuild(guild, "guild.broadcast.member_joined", "{player}", player.getName()); broadcastToGuild(guild, "guild.broadcast.member_joined", "{player}", player.getName());
@@ -325,6 +354,13 @@ public class GuildManager {
worldGuardManager.syncGuildMembers(guild); worldGuardManager.syncGuildMembers(guild);
} }
if (nametagManager != null) {
Player targetPlayer = org.bukkit.Bukkit.getPlayer(targetUuid);
if (targetPlayer != null) {
nametagManager.updatePlayer(targetPlayer);
}
}
logAction(guild, actor, "KICK", targetName + " a été expulsé par " + actor.getName()); logAction(guild, actor, "KICK", targetName + " a été expulsé par " + actor.getName());
broadcastToGuild(guild, "guild.broadcast.member_kicked", "{player}", targetName, "{actor}", actor.getName()); broadcastToGuild(guild, "guild.broadcast.member_kicked", "{player}", targetName, "{actor}", actor.getName());
@@ -357,6 +393,10 @@ public class GuildManager {
worldGuardManager.syncGuildMembers(guild); worldGuardManager.syncGuildMembers(guild);
} }
if (nametagManager != null) {
nametagManager.updatePlayer(player);
}
logAction(guild, player, "LEAVE", player.getName() + " a quitté la guilde."); logAction(guild, player, "LEAVE", player.getName() + " a quitté la guilde.");
broadcastToGuild(guild, "guild.broadcast.member_left", "{player}", player.getName()); broadcastToGuild(guild, "guild.broadcast.member_left", "{player}", player.getName());
@@ -557,6 +597,10 @@ public class GuildManager {
repository.saveGuildAsync(guild); repository.saveGuildAsync(guild);
logAction(guild, actor, "COLOR", "Couleur modifiée vers " + hexColor); logAction(guild, actor, "COLOR", "Couleur modifiée vers " + hexColor);
if (nametagManager != null) {
nametagManager.updateGuild(guild);
}
return GuildResult.success("La couleur de la guilde a été changée pour <color:" + hexColor + ">" + hexColor + "</color> !"); return GuildResult.success("La couleur de la guilde a été changée pour <color:" + hexColor + ">" + hexColor + "</color> !");
} }
@@ -577,6 +621,10 @@ public class GuildManager {
repository.saveGuildAsync(guild); repository.saveGuildAsync(guild);
logAction(guild, actor, "TAG", "Tag modifié vers [" + newTag.toUpperCase() + "]"); logAction(guild, actor, "TAG", "Tag modifié vers [" + newTag.toUpperCase() + "]");
if (nametagManager != null) {
nametagManager.updateGuild(guild);
}
return GuildResult.success("Le tag de la guilde a été changé pour " + guild.getFormattedTag() + " !"); return GuildResult.success("Le tag de la guilde a été changé pour " + guild.getFormattedTag() + " !");
} }
@@ -0,0 +1,138 @@
package fr.luc.gamingcore.manager;
import fr.luc.gamingcore.Main;
import fr.luc.gamingcore.model.Guild;
import fr.luc.gamingcore.model.GuildMember;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import java.util.UUID;
/**
* Gestionnaire responsable de l'affichage des tags et couleurs de guilde
* au-dessus de la tête des joueurs (Nametag / Scoreboard Team) et dans la liste des joueurs (TabList).
*/
public class NametagManager {
private final Main plugin;
private final GuildManager guildManager;
private final Scoreboard scoreboard;
/**
* Constructeur du gestionnaire de Nametags.
*
* @param plugin Instance principale du plugin.
* @param guildManager Gestionnaire métier des guildes.
*/
public NametagManager(Main plugin, GuildManager guildManager) {
this.plugin = plugin;
this.guildManager = guildManager;
this.scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
}
/**
* Met à jour le nametag et le nom dans le TabList pour un joueur spécifique.
*
* @param player Le joueur à mettre à jour.
*/
public void updatePlayer(Player player) {
if (player == null || !player.isOnline()) return;
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild != null) {
String teamName = getTeamName(guild.getId());
Team team = scoreboard.getTeam(teamName);
if (team == null) {
team = scoreboard.registerNewTeam(teamName);
}
String tagText = "<color:" + guild.getColor() + ">[" + guild.getTag() + "] </color>";
Component prefixComponent = MiniMessage.miniMessage().deserialize(tagText);
team.prefix(prefixComponent);
if (!team.hasEntry(player.getName())) {
// Retirer d'une ancienne équipe de guilde si nécessaire
Team oldTeam = scoreboard.getEntryTeam(player.getName());
if (oldTeam != null && oldTeam.getName().startsWith("g_") && !oldTeam.getName().equals(teamName)) {
oldTeam.removeEntry(player.getName());
}
team.addEntry(player.getName());
}
// TabList Name
Component tabName = MiniMessage.miniMessage().deserialize(tagText + "<white>" + player.getName() + "</white>");
player.playerListName(tabName);
} else {
// Joueur sans guilde
Team currentTeam = scoreboard.getEntryTeam(player.getName());
if (currentTeam != null && currentTeam.getName().startsWith("g_")) {
currentTeam.removeEntry(player.getName());
}
player.playerListName(Component.text(player.getName()));
}
}
/**
* Met à jour l'affichage de tous les membres d'une guilde donnée.
*
* @param guild La guilde dont les membres doivent être actualisés.
*/
public void updateGuild(Guild guild) {
if (guild == null) return;
for (GuildMember member : guild.getMembers()) {
if (member.getOfflinePlayer() != null && member.getOfflinePlayer().isOnline()) {
Player p = member.getOfflinePlayer().getPlayer();
if (p != null) {
updatePlayer(p);
}
}
}
}
/**
* Supprime l'équipe Scoreboard associée à une guilde lors de sa dissolution.
*
* @param guildId L'UUID de la guilde dissoute.
*/
public void removeGuildTeam(UUID guildId) {
if (guildId == null) return;
String teamName = getTeamName(guildId);
Team team = scoreboard.getTeam(teamName);
if (team != null) {
team.unregister();
}
}
/**
* Met à jour tous les joueurs actuellement connectés sur le serveur.
*/
public void updateAll() {
for (Player online : Bukkit.getOnlinePlayers()) {
updatePlayer(online);
}
}
/**
* Nettoie les équipes lors de la déconnexion d'un joueur.
*
* @param player Le joueur déconnecté.
*/
public void removePlayer(Player player) {
if (player == null) return;
Team team = scoreboard.getEntryTeam(player.getName());
if (team != null && team.getName().startsWith("g_")) {
team.removeEntry(player.getName());
}
}
private String getTeamName(UUID guildId) {
// Le nom d'équipe est préfixé par "g_" suivi des 12 premiers caractères de l'UUID pour rester sous les 16 car.
String raw = guildId.toString().replace("-", "");
return "g_" + (raw.length() > 12 ? raw.substring(0, 12) : raw);
}
}
+1 -1
View File
@@ -93,7 +93,7 @@ guild:
pagination: "<click:run_command:'/guild list {prev_page}'><hover:show_text:'<yellow>Page précédente</yellow>'><aqua>[◀ Précédent]</aqua></hover></click> <dark_gray>---</dark_gray> <click:run_command:'/guild list {next_page}'><hover:show_text:'<yellow>Page suivante</yellow>'><aqua>[Suivant ▶]</aqua></hover></click>" pagination: "<click:run_command:'/guild list {prev_page}'><hover:show_text:'<yellow>Page précédente</yellow>'><aqua>[◀ Précédent]</aqua></hover></click> <dark_gray>---</dark_gray> <click:run_command:'/guild list {next_page}'><hover:show_text:'<yellow>Page suivante</yellow>'><aqua>[Suivant ▶]</aqua></hover></click>"
chat: chat:
format: "<color:{color}>[Chat Guilde] <gold>{rank}</gold> <white>{player}</white> <dark_gray>»</dark_gray> <white>{message}</white></color>" format: "<color:{color}>[Guild Chat]</color> {guild} <dark_gray>-</dark_gray> <gold>{rank}</gold> <dark_gray>-</dark_gray> <white>{player}</white> <dark_gray>=></dark_gray> <white>{message}</white>"
broadcast: broadcast:
member_joined: "<green><white>{player}</white> a rejoint la guilde !</green>" member_joined: "<green><white>{player}</white> a rejoint la guilde !</green>"