feat: v1.0.4 - cross-server nick persistence, DB-backed rank changes, Velocity auto-sync, author BaileyCodes
This commit is contained in:
@@ -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() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,13 +172,12 @@ public final class NickCommand implements CommandExecutor, TabCompleter {
|
||||
sendMessage(player, "<red>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, "<green>Rank set to <white>" +
|
||||
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, "<green>Rank set to <white>" +
|
||||
rankService.getRank(rankId).map(r -> r.displayName()).orElse(rankId));
|
||||
applyDisplay(player);
|
||||
});
|
||||
}
|
||||
|
||||
private void handleSkin(Player player, String[] args) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Void> 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 ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user