diff --git a/gradle.properties b/gradle.properties index fc6fd90..dc136c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Project -projectVersion=1.0.0 +projectVersion=1.0.4 projectGroup=com.nickcore # Minecraft / Paper diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/NickCorePlugin.java b/nickcore-paper/src/main/java/com/nickcore/paper/NickCorePlugin.java index 4fa8f8f..a4307c3 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/NickCorePlugin.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/NickCorePlugin.java @@ -302,9 +302,11 @@ public final class NickCorePlugin extends JavaPlugin { private void registerVelocityMessaging(NickCoreConfig config) { if (config.velocity().enabled()) { velocityMessaging = new VelocityMessaging(this, profileCache, - placeholderService, nametagService, scheduler, - getLogger(), config.velocity().serverName()); + placeholderService, nametagService, nameOverrideService, + scheduler, getLogger(), config.velocity().serverName()); velocityMessaging.register(); + // Let NickService auto-sync changes to other servers + nickService.setVelocityMessaging(velocityMessaging); getLogger().info("Velocity messaging enabled (server: " + config.velocity().serverName() + ")"); } } diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/command/NickCommand.java b/nickcore-paper/src/main/java/com/nickcore/paper/command/NickCommand.java index 19acbf3..dc39c7d 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/command/NickCommand.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/command/NickCommand.java @@ -172,13 +172,12 @@ public final class NickCommand implements CommandExecutor, TabCompleter { sendMessage(player, "You don't have permission for that rank."); return; } - NickProfile profile = profileCache.get(player.getUniqueId()) - .orElse(NickProfile.empty(player.getUniqueId())); - NickProfile updated = profile.withRank(rankId); - profileCache.put(updated); - sendMessage(player, "Rank set to " + - rankService.getRank(rankId).map(r -> r.displayName()).orElse(rankId)); - applyDisplay(player); + // Save rank to DB and sync to Velocity + nickService.saveRankChange(player.getUniqueId(), rankId).thenRun(() -> { + sendMessage(player, "Rank set to " + + rankService.getRank(rankId).map(r -> r.displayName()).orElse(rankId)); + applyDisplay(player); + }); } private void handleSkin(Player player, String[] args) { diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/gui/GuiManager.java b/nickcore-paper/src/main/java/com/nickcore/paper/gui/GuiManager.java index 9bc64f1..1339025 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/gui/GuiManager.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/gui/GuiManager.java @@ -53,8 +53,8 @@ public final class GuiManager implements Listener { } public void openRankMenu(Player player) { - RankMenuGui gui = new RankMenuGui(player, this, rankService, profileCache, - placeholderService, nametagService); + RankMenuGui gui = new RankMenuGui(player, this, nickService, rankService, + profileCache, placeholderService, nametagService); openGuis.put(player.getUniqueId(), gui); gui.open(); } diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/gui/RankMenuGui.java b/nickcore-paper/src/main/java/com/nickcore/paper/gui/RankMenuGui.java index b727f6e..b80d359 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/gui/RankMenuGui.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/gui/RankMenuGui.java @@ -3,6 +3,7 @@ package com.nickcore.paper.gui; import com.nickcore.common.model.NickProfile; import com.nickcore.common.model.RankDefinition; import com.nickcore.paper.cache.ProfileCache; +import com.nickcore.paper.service.NickService; import com.nickcore.paper.service.NametagService; import com.nickcore.paper.service.PlaceholderService; import com.nickcore.paper.service.RankService; @@ -21,6 +22,7 @@ import java.util.List; public final class RankMenuGui extends AbstractGui { private final GuiManager guiManager; + private final NickService nickService; private final RankService rankService; private final ProfileCache profileCache; private final PlaceholderService placeholderService; @@ -28,11 +30,12 @@ public final class RankMenuGui extends AbstractGui { private final MiniMessage mm = MiniMessage.miniMessage(); private int page = 0; - public RankMenuGui(Player viewer, GuiManager guiManager, RankService rankService, - ProfileCache profileCache, PlaceholderService placeholderService, - NametagService nametagService) { + public RankMenuGui(Player viewer, GuiManager guiManager, NickService nickService, + RankService rankService, ProfileCache profileCache, + PlaceholderService placeholderService, NametagService nametagService) { super(viewer, 54, Component.text("Select Rank", NamedTextColor.GOLD, TextDecoration.BOLD)); this.guiManager = guiManager; + this.nickService = nickService; this.rankService = rankService; this.profileCache = profileCache; this.placeholderService = placeholderService; @@ -57,14 +60,14 @@ public final class RankMenuGui extends AbstractGui { Component.text("Click to select", NamedTextColor.YELLOW) )), e -> { - NickProfile profile = profileCache.get(viewer.getUniqueId()) - .orElse(NickProfile.empty(viewer.getUniqueId())); - profileCache.put(profile.withRank(rank.id())); - viewer.closeInventory(); - viewer.sendMessage(Component.text("Rank set to ", NamedTextColor.GREEN) - .append(mm.deserialize(rank.displayName()))); - placeholderService.invalidate(viewer.getUniqueId(), viewer.getName()); - nametagService.updateNametag(viewer); + // Save to DB and sync via Velocity + nickService.saveRankChange(viewer.getUniqueId(), rank.id()).thenRun(() -> { + viewer.closeInventory(); + viewer.sendMessage(Component.text("Rank set to ", NamedTextColor.GREEN) + .append(mm.deserialize(rank.displayName()))); + placeholderService.invalidate(viewer.getUniqueId(), viewer.getName()); + nametagService.updateNametag(viewer); + }); }); } diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/integration/VelocityMessaging.java b/nickcore-paper/src/main/java/com/nickcore/paper/integration/VelocityMessaging.java index 194c83b..bc4fc7d 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/integration/VelocityMessaging.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/integration/VelocityMessaging.java @@ -3,6 +3,7 @@ package com.nickcore.paper.integration; import com.nickcore.common.dto.NickSyncMessage; import com.nickcore.common.model.NickProfile; import com.nickcore.paper.cache.ProfileCache; +import com.nickcore.paper.service.NameOverrideService; import com.nickcore.paper.service.PlaceholderService; import com.nickcore.paper.service.NametagService; import com.nickcore.paper.scheduler.SchedulerAdapter; @@ -19,6 +20,10 @@ import java.util.logging.Logger; /** * Velocity plugin messaging integration. * Sends/receives NickSyncMessages for cross-server nick synchronization. + * + *

When a player switches servers (hub → survival), the Velocity proxy forwards + * their profile to the new server. This handler receives that sync and applies + * the full name override so the nick persists across servers.

*/ public final class VelocityMessaging implements PluginMessageListener { @@ -26,17 +31,20 @@ public final class VelocityMessaging implements PluginMessageListener { private final ProfileCache profileCache; private final PlaceholderService placeholderService; private final NametagService nametagService; + private final NameOverrideService nameOverrideService; private final SchedulerAdapter scheduler; private final Logger logger; private final String serverName; public VelocityMessaging(Plugin plugin, ProfileCache profileCache, PlaceholderService placeholderService, NametagService nametagService, - SchedulerAdapter scheduler, Logger logger, String serverName) { + NameOverrideService nameOverrideService, SchedulerAdapter scheduler, + Logger logger, String serverName) { this.plugin = plugin; this.profileCache = profileCache; this.placeholderService = placeholderService; this.nametagService = nametagService; + this.nameOverrideService = nameOverrideService; this.scheduler = scheduler; this.logger = logger; this.serverName = serverName; @@ -71,12 +79,34 @@ public final class VelocityMessaging implements PluginMessageListener { } /** - * Sends a full profile sync for a player. + * Sends a full profile sync to Velocity for cross-server propagation. + * Called every time a nick/rank/skin changes on this server. */ public void syncProfile(NickProfile profile) { sendSync(NickSyncMessage.fullSync(profile, serverName)); } + /** + * Sends a nick update to Velocity. + */ + public void syncNickUpdate(java.util.UUID uuid, String nickname) { + sendSync(NickSyncMessage.nickUpdate(uuid, nickname, serverName)); + } + + /** + * Sends a rank update to Velocity. + */ + public void syncRankUpdate(java.util.UUID uuid, String rankId) { + sendSync(NickSyncMessage.rankUpdate(uuid, rankId, serverName)); + } + + /** + * Sends a reset to Velocity. + */ + public void syncReset(java.util.UUID uuid) { + sendSync(NickSyncMessage.reset(uuid, serverName)); + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] data) { if (!NickSyncMessage.CHANNEL.equals(channel)) return; @@ -109,7 +139,11 @@ public final class VelocityMessaging implements PluginMessageListener { Player player = Bukkit.getPlayer(msg.playerUuid()); if (player != null) { placeholderService.invalidate(msg.playerUuid(), player.getName()); - scheduler.runAtEntity(plugin, player, () -> nametagService.updateNametag(player)); + scheduler.runAtEntity(plugin, player, () -> { + // Apply full name override so the nick appears everywhere on this server + nameOverrideService.applyFullOverride(player); + nametagService.updateNametag(player); + }); } } @@ -137,13 +171,24 @@ public final class VelocityMessaging implements PluginMessageListener { private void handleCacheInvalidate(NickSyncMessage msg) { profileCache.remove(msg.playerUuid()); placeholderService.remove(msg.playerUuid()); + Player player = Bukkit.getPlayer(msg.playerUuid()); + if (player != null) { + scheduler.runAtEntity(plugin, player, () -> { + nameOverrideService.clearMapping(player); + nameOverrideService.applyFullOverride(player); + nametagService.updateNametag(player); + }); + } } private void refreshPlayer(java.util.UUID uuid) { Player player = Bukkit.getPlayer(uuid); if (player != null) { placeholderService.invalidate(uuid, player.getName()); - scheduler.runAtEntity(plugin, player, () -> nametagService.updateNametag(player)); + scheduler.runAtEntity(plugin, player, () -> { + nameOverrideService.applyFullOverride(player); + nametagService.updateNametag(player); + }); } } } diff --git a/nickcore-paper/src/main/java/com/nickcore/paper/service/NickService.java b/nickcore-paper/src/main/java/com/nickcore/paper/service/NickService.java index 206d200..ef3eba3 100644 --- a/nickcore-paper/src/main/java/com/nickcore/paper/service/NickService.java +++ b/nickcore-paper/src/main/java/com/nickcore/paper/service/NickService.java @@ -5,6 +5,7 @@ import com.nickcore.common.model.NickProfile; import com.nickcore.common.validation.InputSanitizer; import com.nickcore.common.validation.NicknameValidator; import com.nickcore.paper.cache.ProfileCache; +import com.nickcore.paper.integration.VelocityMessaging; import com.nickcore.paper.repository.NickRepository; import net.kyori.adventure.text.Component; @@ -45,6 +46,9 @@ public final class NickService { private volatile boolean allowDuplicateNicks = false; private volatile boolean allowCustomNames = false; + // Optional: set when Velocity is enabled for cross-server sync + private volatile VelocityMessaging velocityMessaging; + public NickService(NickRepository repository, ProfileCache cache, NicknameValidator validator, Logger logger) { this.repository = Objects.requireNonNull(repository); @@ -138,6 +142,11 @@ public final class NickService { return repository.save(newProfile).thenCompose(v -> { cache.put(newProfile); + // Sync to other servers via Velocity + if (velocityMessaging != null) { + velocityMessaging.syncProfile(newProfile); + } + // Record history NickHistory history = NickHistory.nickChange( uuid, oldProfile.nickname(), sanitized, @@ -189,6 +198,11 @@ public final class NickService { return repository.save(resetProfile).thenCompose(v -> { cache.put(resetProfile); + // Sync reset to other servers + if (velocityMessaging != null) { + velocityMessaging.syncReset(uuid); + } + NickHistory history = NickHistory.reset( uuid, oldProfile.nickname(), oldProfile.rankId(), changedBy ); @@ -239,6 +253,28 @@ public final class NickService { return allowCustomNames; } + /** + * Sets the VelocityMessaging instance for cross-server sync. + */ + public void setVelocityMessaging(VelocityMessaging velocityMessaging) { + this.velocityMessaging = velocityMessaging; + } + + /** + * Saves a rank change to the database and syncs to Velocity. + */ + public CompletableFuture saveRankChange(java.util.UUID uuid, String rankId) { + NickProfile profile = cache.get(uuid).orElse(NickProfile.empty(uuid)); + NickProfile updated = profile.withRank(rankId); + cache.put(updated); + + if (velocityMessaging != null) { + velocityMessaging.syncRankUpdate(uuid, rankId); + } + + return repository.save(updated); + } + // ── Result Container ──────────────────────────────────────────────── /** diff --git a/nickcore-paper/src/main/resources/plugin.yml b/nickcore-paper/src/main/resources/plugin.yml index 15a59ef..6eab475 100644 --- a/nickcore-paper/src/main/resources/plugin.yml +++ b/nickcore-paper/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ name: NickCore -version: '1.0.0' +version: '1.0.4' main: com.nickcore.paper.NickCorePlugin api-version: '1.21' description: Enterprise Minecraft Nickname Plugin -author: NickCore Team +author: BaileyCodes website: https://nickcore.com folia-supported: true diff --git a/nickcore-velocity/src/main/java/com/nickcore/velocity/NickCoreVelocity.java b/nickcore-velocity/src/main/java/com/nickcore/velocity/NickCoreVelocity.java index 081d0f3..0339ce1 100644 --- a/nickcore-velocity/src/main/java/com/nickcore/velocity/NickCoreVelocity.java +++ b/nickcore-velocity/src/main/java/com/nickcore/velocity/NickCoreVelocity.java @@ -27,8 +27,8 @@ import java.util.concurrent.ConcurrentHashMap; * NickCore Velocity proxy plugin. * Maintains a cross-server nick profile cache and routes sync messages. */ -@Plugin(id = "nickcore", name = "NickCore", version = "1.0.0", - authors = {"NickCore Team"}, description = "Enterprise nickname system - Velocity module") +@Plugin(id = "nickcore", name = "NickCore", version = "1.0.4", + authors = {"BaileyCodes"}, description = "Enterprise nickname system - Velocity module") public final class NickCoreVelocity { private static final MinecraftChannelIdentifier CHANNEL =