Compare commits

..

1 Commits

9 changed files with 116 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
# Project
projectVersion=1.0.0
projectVersion=1.0.4
projectGroup=com.nickcore
# Minecraft / Paper

View File

@@ -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() + ")");
}
}

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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);
});
});
}

View File

@@ -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);
});
}
}
}

View File

@@ -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 ────────────────────────────────────────────────
/**

View File

@@ -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

View File

@@ -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 =